/* * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * * * * * * * * * * * * * * * * * * * * */ package com.sun.javafx.binding; import javafx.beans.WeakListener; import javafx.collections.*; import java.lang.ref.WeakReference; import java.util.List; import java.util.Map; import java.util.Set; /** */ public class ContentBinding { 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(List list1, ObservableList list2) { checkParameters(list1, list2); final ListContentBinding contentBinding = new ListContentBinding(list1); if (list1 instanceof ObservableList) { ((ObservableList) list1).setAll(list2); } else { list1.clear(); list1.addAll(list2); } list2.removeListener(contentBinding); list2.addListener(contentBinding); return contentBinding; } public static Object bind(Set set1, ObservableSet set2) { checkParameters(set1, set2); final SetContentBinding contentBinding = new SetContentBinding(set1); set1.clear(); set1.addAll(set2); set2.removeListener(contentBinding); set2.addListener(contentBinding); return contentBinding; } public static Object bind(Map map1, ObservableMap map2) { checkParameters(map1, map2); final MapContentBinding contentBinding = new MapContentBinding(map1); map1.clear(); map1.putAll(map2); map2.removeListener(contentBinding); map2.addListener(contentBinding); return contentBinding; } public static void unbind(Object obj1, Object obj2) { checkParameters(obj1, obj2); if ((obj1 instanceof List) && (obj2 instanceof ObservableList)) { ((ObservableList)obj2).removeListener(new ListContentBinding((List)obj1)); } else if ((obj1 instanceof Set) && (obj2 instanceof ObservableSet)) { ((ObservableSet)obj2).removeListener(new SetContentBinding((Set)obj1)); } else if ((obj1 instanceof Map) && (obj2 instanceof ObservableMap)) { ((ObservableMap)obj2).removeListener(new MapContentBinding((Map)obj1)); } } private static class ListContentBinding implements ListChangeListener, WeakListener { private final WeakReference> listRef; public ListContentBinding(List list) { this.listRef = new WeakReference>(list); } @Override public void onChanged(Change change) { final List list = listRef.get(); if (list == null) { change.getList().removeListener(this); } else { while (change.next()) { if (change.wasPermutated()) { list.subList(change.getFrom(), change.getTo()).clear(); list.addAll(change.getFrom(), change.getList().subList(change.getFrom(), change.getTo())); } else { if (change.wasRemoved()) { list.subList(change.getFrom(), change.getFrom() + change.getRemovedSize()).clear(); } if (change.wasAdded()) { list.addAll(change.getFrom(), change.getAddedSubList()); } } } } } @Override public boolean wasGarbageCollected() { return listRef.get() == null; } @Override public int hashCode() { final List list = listRef.get(); return (list == null)? 0 : list.hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } final List list1 = listRef.get(); if (list1 == null) { return false; } if (obj instanceof ListContentBinding) { final ListContentBinding other = (ListContentBinding) obj; final List list2 = other.listRef.get(); return list1 == list2; } return false; } } private static class SetContentBinding implements SetChangeListener, WeakListener { private final WeakReference> setRef; public SetContentBinding(Set set) { this.setRef = new WeakReference>(set); } @Override public void onChanged(Change change) { final Set set = setRef.get(); if (set == null) { change.getSet().removeListener(this); } else { if (change.wasRemoved()) { set.remove(change.getElementRemoved()); } else { set.add(change.getElementAdded()); } } } @Override public boolean wasGarbageCollected() { return setRef.get() == null; } @Override public int hashCode() { final Set set = setRef.get(); return (set == null)? 0 : set.hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } final Set set1 = setRef.get(); if (set1 == null) { return false; } if (obj instanceof SetContentBinding) { final SetContentBinding other = (SetContentBinding) obj; final Set set2 = other.setRef.get(); return set1 == set2; } return false; } } private static class MapContentBinding implements MapChangeListener, WeakListener { private final WeakReference> mapRef; public MapContentBinding(Map map) { this.mapRef = new WeakReference>(map); } @Override public void onChanged(Change change) { final Map map = mapRef.get(); if (map == null) { change.getMap().removeListener(this); } else { if (change.wasRemoved()) { map.remove(change.getKey()); } else { map.put(change.getKey(), change.getValueAdded()); } } } @Override public boolean wasGarbageCollected() { return mapRef.get() == null; } @Override public int hashCode() { final Map map = mapRef.get(); return (map == null)? 0 : map.hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } final Map map1 = mapRef.get(); if (map1 == null) { return false; } if (obj instanceof MapContentBinding) { final MapContentBinding other = (MapContentBinding) obj; final Map map2 = other.mapRef.get(); return map1 == map2; } return false; } } }