/******************************************************************************
* 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.property;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.gef.common.beans.binding.BindingUtils;
import org.eclipse.gef.common.beans.binding.SetMultimapExpression;
import org.eclipse.gef.common.collections.ObservableSetMultimap;
import com.google.common.collect.SetMultimap;
import javafx.beans.property.Property;
import javafx.beans.property.ReadOnlyListProperty;
import javafx.beans.property.ReadOnlyMapProperty;
import javafx.beans.property.ReadOnlyProperty;
import javafx.beans.property.ReadOnlySetProperty;
/**
* Abstract base class defining contract for a read-only {@link Property}
* wrapping an {@link ObservableSetMultimap}.
* <p>
* This class provides identical functionality for {@link SetMultimap} as
* {@link ReadOnlyMapProperty} for {@link Map}, {@link ReadOnlySetProperty} for
* {@link Set}, or {@link ReadOnlyListProperty} for {@link List}.
*
* @param <K>
* The key type of the wrapped {@link ObservableSetMultimap}.
* @param <V>
* The value type of the wrapped {@link ObservableSetMultimap}.
*
* @author anyssen
*/
public abstract class ReadOnlySetMultimapProperty<K, V>
extends SetMultimapExpression<K, V>
implements ReadOnlyProperty<ObservableSetMultimap<K, V>> {
/**
* Appends a representation of this {@link SetMultimapProperty}'s value to
* the given {@link StringBuilder}. Gets called from {@link #toString()} to
* allow subclasses to provide a changed value representation.
*
* @param result
* A {@link StringBuilder} to append the value representation to.
*/
protected void appendValueToString(final StringBuilder result) {
result.append("value: " + get());
}
/**
* Creates a unidirectional content binding between the
* {@link ObservableSetMultimap}, that is wrapped in this
* {@link ReadOnlySetMultimapProperty}, and the given
* {@link ObservableSetMultimap}.
* <p>
* A content binding ensures that the content of the wrapped
* {@link ObservableSetMultimap} is the same as that of the other
* {@link ObservableSetMultimap}. If the content of the other
* {@link ObservableSetMultimap} changes, the wrapped
* {@link ObservableSetMultimap} will be updated automatically.
*
* @param target
* The {@link ObservableSetMultimap} this property should be
* unidirectionally bound to.
*/
public void bindContent(ObservableSetMultimap<K, V> target) {
BindingUtils.bindContent(this, target);
}
/**
* Creates a bidirectional content binding of the
* {@link ObservableSetMultimap}, that is wrapped in this
* {@link ReadOnlySetMultimapProperty}, and the given
* {@link ObservableSetMultimap} .
* <p>
* A bidirectional content binding ensures that the content of the two
* {@link ObservableSetMultimap ObservableSetMultimaps} are the same. If the
* content of one of the {@link ObservableSetMultimap
* ObservableSetMultimaps} changes, the other one will be updated
* automatically.
*
* @param other
* The {@link ObservableSetMultimap} this property should be
* bidirectionally bound to.
*/
public void bindContentBidirectional(ObservableSetMultimap<K, V> other) {
BindingUtils.bindContentBidirectional(this, other);
}
@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}
if (other == null || !(other instanceof SetMultimap)) {
return false;
}
if (get() == null) {
return false;
}
return get().equals(other);
}
@Override
public int hashCode() {
// XXX: As we rely on equality to remove a binding again, we have to
// ensure the hash code is the same for a pair of given properties.
// We fall back to the very easiest case here (and use a constant).
return 0;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder(
getClass().getSimpleName() + " [");
final Object bean = getBean();
if (bean != null) {
sb.append("bean: " + bean + ", ");
}
final String name = getName();
if ((name != null) && !name.equals("")) {
sb.append("name: " + name + ", ");
}
appendValueToString(sb);
sb.append("]");
return sb.toString();
}
/**
* Deletes a content binding between the {@link ObservableSetMultimap}, that
* is wrapped in this {@link ReadOnlySetMultimapProperty}, and another
* {@link Object}.
*
* @param target
* The {@link Object} to which the binding should be removed.
*/
@SuppressWarnings("unchecked")
public void unbindContent(Object target) {
try {
BindingUtils.unbindContent(this,
(ObservableSetMultimap<? extends K, ? extends V>) target);
} catch (ClassCastException e) {
// do nothing if types don't match
}
}
/**
* Deletes a bidirectional content binding between the
* {@link ObservableSetMultimap}, that is wrapped in this
* {@link ReadOnlySetMultimapProperty}, and another {@link Object}.
*
* @param other
* The {@link Object} to which the bidirectional binding should
* be removed.
*/
@SuppressWarnings("unchecked")
public void unbindContentBidirectional(Object other) {
try {
BindingUtils.unbindContentBidirectional(this,
(ObservableSetMultimap<K, V>) other);
} catch (ClassCastException e) {
// do nothing if types don't match
}
}
}