com.sun.javafx.binding.BidirectionalContentBinding Maven / Gradle / Ivy
/*
* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.javafx.binding;
import javafx.beans.WeakListener;
import javafx.collections.*;
import java.lang.ref.WeakReference;
import java.util.Map;
import java.util.Set;
/**
*/
public class BidirectionalContentBinding {
private static void checkParameters(Object property1, Object property2) {
if ((property1 == null) || (property2 == null)) {
throw new NullPointerException("Both parameters must be specified.");
}
if (property1 == property2) {
throw new IllegalArgumentException("Cannot bind object to itself");
}
}
public static Object bind(ObservableList list1, ObservableList list2) {
checkParameters(list1, list2);
final ListContentBinding binding = new ListContentBinding(list1, list2);
list1.setAll(list2);
list1.addListener(binding);
list2.addListener(binding);
return binding;
}
public static Object bind(ObservableSet set1, ObservableSet set2) {
checkParameters(set1, set2);
final SetContentBinding binding = new SetContentBinding(set1, set2);
set1.clear();
set1.addAll(set2);
set1.addListener(binding);
set2.addListener(binding);
return binding;
}
public static Object bind(ObservableMap map1, ObservableMap map2) {
checkParameters(map1, map2);
final MapContentBinding binding = new MapContentBinding(map1, map2);
map1.clear();
map1.putAll(map2);
map1.addListener(binding);
map2.addListener(binding);
return binding;
}
public static void unbind(Object obj1, Object obj2) {
checkParameters(obj1, obj2);
if ((obj1 instanceof ObservableList) && (obj2 instanceof ObservableList)) {
final ObservableList list1 = (ObservableList)obj1;
final ObservableList list2 = (ObservableList)obj2;
final ListContentBinding binding = new ListContentBinding(list1, list2);
list1.removeListener(binding);
list2.removeListener(binding);
} else if ((obj1 instanceof ObservableSet) && (obj2 instanceof ObservableSet)) {
final ObservableSet set1 = (ObservableSet)obj1;
final ObservableSet set2 = (ObservableSet)obj2;
final SetContentBinding binding = new SetContentBinding(set1, set2);
set1.removeListener(binding);
set2.removeListener(binding);
} else if ((obj1 instanceof ObservableMap) && (obj2 instanceof ObservableMap)) {
final ObservableMap map1 = (ObservableMap)obj1;
final ObservableMap map2 = (ObservableMap)obj2;
final MapContentBinding binding = new MapContentBinding(map1, map2);
map1.removeListener(binding);
map2.removeListener(binding);
}
}
private static class ListContentBinding implements ListChangeListener, WeakListener {
private final WeakReference> propertyRef1;
private final WeakReference> propertyRef2;
private boolean updating = false;
public ListContentBinding(ObservableList list1, ObservableList list2) {
propertyRef1 = new WeakReference>(list1);
propertyRef2 = new WeakReference>(list2);
}
@Override
public void onChanged(Change extends E> change) {
if (!updating) {
final ObservableList list1 = propertyRef1.get();
final ObservableList list2 = propertyRef2.get();
if ((list1 == null) || (list2 == null)) {
if (list1 != null) {
list1.removeListener(this);
}
if (list2 != null) {
list2.removeListener(this);
}
} else {
try {
updating = true;
final ObservableList dest = (list1 == change.getList())? list2 : list1;
while (change.next()) {
if (change.wasPermutated()) {
dest.remove(change.getFrom(), change.getTo());
dest.addAll(change.getFrom(), change.getList().subList(change.getFrom(), change.getTo()));
} else {
if (change.wasRemoved()) {
dest.remove(change.getFrom(), change.getFrom() + change.getRemovedSize());
}
if (change.wasAdded()) {
dest.addAll(change.getFrom(), change.getAddedSubList());
}
}
}
} finally {
updating = false;
}
}
}
}
@Override
public boolean wasGarbageCollected() {
return (propertyRef1.get() == null) || (propertyRef2.get() == null);
}
@Override
public int hashCode() {
final ObservableList list1 = propertyRef1.get();
final ObservableList list2 = propertyRef2.get();
final int hc1 = (list1 == null)? 0 : list1.hashCode();
final int hc2 = (list2 == null)? 0 : list2.hashCode();
return hc1 * hc2;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
final Object propertyA1 = propertyRef1.get();
final Object propertyA2 = propertyRef2.get();
if ((propertyA1 == null) || (propertyA2 == null)) {
return false;
}
if (obj instanceof ListContentBinding) {
final ListContentBinding otherBinding = (ListContentBinding) obj;
final Object propertyB1 = otherBinding.propertyRef1.get();
final Object propertyB2 = otherBinding.propertyRef2.get();
if ((propertyB1 == null) || (propertyB2 == null)) {
return false;
}
if ((propertyA1 == propertyB1) && (propertyA2 == propertyB2)) {
return true;
}
if ((propertyA1 == propertyB2) && (propertyA2 == propertyB1)) {
return true;
}
}
return false;
}
}
private static class SetContentBinding implements SetChangeListener, WeakListener {
private final WeakReference> propertyRef1;
private final WeakReference> propertyRef2;
private boolean updating = false;
public SetContentBinding(ObservableSet list1, ObservableSet list2) {
propertyRef1 = new WeakReference>(list1);
propertyRef2 = new WeakReference>(list2);
}
@Override
public void onChanged(Change extends E> change) {
if (!updating) {
final ObservableSet set1 = propertyRef1.get();
final ObservableSet set2 = propertyRef2.get();
if ((set1 == null) || (set2 == null)) {
if (set1 != null) {
set1.removeListener(this);
}
if (set2 != null) {
set2.removeListener(this);
}
} else {
try {
updating = true;
final Set dest = (set1 == change.getSet())? set2 : set1;
if (change.wasRemoved()) {
dest.remove(change.getElementRemoved());
} else {
dest.add(change.getElementAdded());
}
} finally {
updating = false;
}
}
}
}
@Override
public boolean wasGarbageCollected() {
return (propertyRef1.get() == null) || (propertyRef2.get() == null);
}
@Override
public int hashCode() {
final ObservableSet set1 = propertyRef1.get();
final ObservableSet set2 = propertyRef2.get();
final int hc1 = (set1 == null)? 0 : set1.hashCode();
final int hc2 = (set2 == null)? 0 : set2.hashCode();
return hc1 * hc2;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
final Object propertyA1 = propertyRef1.get();
final Object propertyA2 = propertyRef2.get();
if ((propertyA1 == null) || (propertyA2 == null)) {
return false;
}
if (obj instanceof SetContentBinding) {
final SetContentBinding otherBinding = (SetContentBinding) obj;
final Object propertyB1 = otherBinding.propertyRef1.get();
final Object propertyB2 = otherBinding.propertyRef2.get();
if ((propertyB1 == null) || (propertyB2 == null)) {
return false;
}
if ((propertyA1 == propertyB1) && (propertyA2 == propertyB2)) {
return true;
}
if ((propertyA1 == propertyB2) && (propertyA2 == propertyB1)) {
return true;
}
}
return false;
}
}
private static class MapContentBinding implements MapChangeListener, WeakListener {
private final WeakReference> propertyRef1;
private final WeakReference> propertyRef2;
private boolean updating = false;
public MapContentBinding(ObservableMap list1, ObservableMap list2) {
propertyRef1 = new WeakReference>(list1);
propertyRef2 = new WeakReference>(list2);
}
@Override
public void onChanged(Change extends K, ? extends V> change) {
if (!updating) {
final ObservableMap map1 = propertyRef1.get();
final ObservableMap map2 = propertyRef2.get();
if ((map1 == null) || (map2 == null)) {
if (map1 != null) {
map1.removeListener(this);
}
if (map2 != null) {
map2.removeListener(this);
}
} else {
try {
updating = true;
final Map dest = (map1 == change.getMap())? map2 : map1;
if (change.wasRemoved()) {
dest.remove(change.getKey());
}
if (change.wasAdded()) {
dest.put(change.getKey(), change.getValueAdded());
}
} finally {
updating = false;
}
}
}
}
@Override
public boolean wasGarbageCollected() {
return (propertyRef1.get() == null) || (propertyRef2.get() == null);
}
@Override
public int hashCode() {
final ObservableMap map1 = propertyRef1.get();
final ObservableMap map2 = propertyRef2.get();
final int hc1 = (map1 == null)? 0 : map1.hashCode();
final int hc2 = (map2 == null)? 0 : map2.hashCode();
return hc1 * hc2;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
final Object propertyA1 = propertyRef1.get();
final Object propertyA2 = propertyRef2.get();
if ((propertyA1 == null) || (propertyA2 == null)) {
return false;
}
if (obj instanceof MapContentBinding) {
final MapContentBinding otherBinding = (MapContentBinding) obj;
final Object propertyB1 = otherBinding.propertyRef1.get();
final Object propertyB2 = otherBinding.propertyRef2.get();
if ((propertyB1 == null) || (propertyB2 == null)) {
return false;
}
if ((propertyA1 == propertyB1) && (propertyA2 == propertyB2)) {
return true;
}
if ((propertyA1 == propertyB2) && (propertyA2 == propertyB1)) {
return true;
}
}
return false;
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy