< prev index next > modules/javafx.base/src/main/java/com/sun/javafx/binding/ExpressionHelper.java
Print this page
* questions.
*/
package com.sun.javafx.binding;
import javafx.beans.InvalidationListener;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
- import java.util.Arrays;
-
/**
* A convenience class for creating implementations of {@link javafx.beans.value.ObservableValue}.
* It contains all of the infrastructure support for value invalidation- and
* change event notification.
*
* questions.
*/
package com.sun.javafx.binding;
+ import java.util.LinkedHashMap;
+ import java.util.Map;
+ import java.util.Map.Entry;
+
import javafx.beans.InvalidationListener;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
/**
* A convenience class for creating implementations of {@link javafx.beans.value.ObservableValue}.
* It contains all of the infrastructure support for value invalidation- and
* change event notification.
*
}
}
private static class Generic<T> extends ExpressionHelper<T> {
! private InvalidationListener[] invalidationListeners;
! private ChangeListener<? super T>[] changeListeners;
- private int invalidationSize;
- private int changeSize;
- private boolean locked;
private T currentValue;
private Generic(ObservableValue<T> observable, InvalidationListener listener0, InvalidationListener listener1) {
super(observable);
! this.invalidationListeners = new InvalidationListener[] {listener0, listener1};
! this.invalidationSize = 2;
}
private Generic(ObservableValue<T> observable, ChangeListener<? super T> listener0, ChangeListener<? super T> listener1) {
super(observable);
! this.changeListeners = new ChangeListener[] {listener0, listener1};
! this.changeSize = 2;
this.currentValue = observable.getValue();
}
private Generic(ObservableValue<T> observable, InvalidationListener invalidationListener, ChangeListener<? super T> changeListener) {
super(observable);
! this.invalidationListeners = new InvalidationListener[] {invalidationListener};
! this.invalidationSize = 1;
- this.changeListeners = new ChangeListener[] {changeListener};
- this.changeSize = 1;
this.currentValue = observable.getValue();
}
@Override
protected Generic<T> addListener(InvalidationListener listener) {
! if (invalidationListeners == null) {
! invalidationListeners = new InvalidationListener[] {listener};
! invalidationSize = 1;
! } else {
- final int oldCapacity = invalidationListeners.length;
- if (locked) {
- final int newCapacity = (invalidationSize < oldCapacity)? oldCapacity : (oldCapacity * 3)/2 + 1;
- invalidationListeners = Arrays.copyOf(invalidationListeners, newCapacity);
- } else if (invalidationSize == oldCapacity) {
- invalidationSize = trim(invalidationSize, invalidationListeners);
- if (invalidationSize == oldCapacity) {
- final int newCapacity = (oldCapacity * 3)/2 + 1;
- invalidationListeners = Arrays.copyOf(invalidationListeners, newCapacity);
- }
}
- invalidationListeners[invalidationSize++] = listener;
}
return this;
}
@Override
protected ExpressionHelper<T> removeListener(InvalidationListener listener) {
! if (invalidationListeners != null) {
! for (int index = 0; index < invalidationSize; index++) {
! if (listener.equals(invalidationListeners[index])) {
! if (invalidationSize == 1) {
! if (changeSize == 1) {
! return new SingleChange<T>(observable, changeListeners[0]);
! }
- invalidationListeners = null;
- invalidationSize = 0;
- } else if ((invalidationSize == 2) && (changeSize == 0)) {
- return new SingleInvalidation<T>(observable, invalidationListeners[1-index]);
- } else {
- final int numMoved = invalidationSize - index - 1;
- final InvalidationListener[] oldListeners = invalidationListeners;
- if (locked) {
- invalidationListeners = new InvalidationListener[invalidationListeners.length];
- System.arraycopy(oldListeners, 0, invalidationListeners, 0, index);
- }
- if (numMoved > 0) {
- System.arraycopy(oldListeners, index+1, invalidationListeners, index, numMoved);
- }
- invalidationSize--;
- if (!locked) {
- invalidationListeners[invalidationSize] = null; // Let gc do its work
- }
- }
- break;
}
}
}
return this;
}
@Override
protected ExpressionHelper<T> addListener(ChangeListener<? super T> listener) {
! if (changeListeners == null) {
! changeListeners = new ChangeListener[] {listener};
! changeSize = 1;
! } else {
- final int oldCapacity = changeListeners.length;
- if (locked) {
- final int newCapacity = (changeSize < oldCapacity)? oldCapacity : (oldCapacity * 3)/2 + 1;
- changeListeners = Arrays.copyOf(changeListeners, newCapacity);
- } else if (changeSize == oldCapacity) {
- changeSize = trim(changeSize, changeListeners);
- if (changeSize == oldCapacity) {
- final int newCapacity = (oldCapacity * 3)/2 + 1;
- changeListeners = Arrays.copyOf(changeListeners, newCapacity);
- }
}
- changeListeners[changeSize++] = listener;
}
! if (changeSize == 1) {
currentValue = observable.getValue();
}
return this;
}
@Override
protected ExpressionHelper<T> removeListener(ChangeListener<? super T> listener) {
! if (changeListeners != null) {
! for (int index = 0; index < changeSize; index++) {
! if (listener.equals(changeListeners[index])) {
! if (changeSize == 1) {
! if (invalidationSize == 1) {
! return new SingleInvalidation<T>(observable, invalidationListeners[0]);
! }
- changeListeners = null;
- changeSize = 0;
- } else if ((changeSize == 2) && (invalidationSize == 0)) {
- return new SingleChange<T>(observable, changeListeners[1-index]);
- } else {
- final int numMoved = changeSize - index - 1;
- final ChangeListener<? super T>[] oldListeners = changeListeners;
- if (locked) {
- changeListeners = new ChangeListener[changeListeners.length];
- System.arraycopy(oldListeners, 0, changeListeners, 0, index);
- }
- if (numMoved > 0) {
- System.arraycopy(oldListeners, index+1, changeListeners, index, numMoved);
- }
- changeSize--;
- if (!locked) {
- changeListeners[changeSize] = null; // Let gc do its work
- }
- }
- break;
}
}
}
return this;
}
@Override
protected void fireValueChangedEvent() {
! final InvalidationListener[] curInvalidationList = invalidationListeners;
! final int curInvalidationSize = invalidationSize;
! final ChangeListener<? super T>[] curChangeList = changeListeners;
! final int curChangeSize = changeSize;
try {
! locked = true;
! for (int i = 0; i < curInvalidationSize; i++) {
- try {
- curInvalidationList[i].invalidated(observable);
- } catch (Exception e) {
- Thread.currentThread().getUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), e);
- }
}
! if (curChangeSize > 0) {
! final T oldValue = currentValue;
! currentValue = observable.getValue();
! final boolean changed = (currentValue == null)? (oldValue != null) : !currentValue.equals(oldValue);
! if (changed) {
! for (int i = 0; i < curChangeSize; i++) {
! try {
! curChangeList[i].changed(observable, oldValue, currentValue);
! } catch (Exception e) {
! Thread.currentThread().getUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), e);
! }
! }
- }
}
! } finally {
! locked = false;
}
}
}
-
}
}
}
private static class Generic<T> extends ExpressionHelper<T> {
! private Map<InvalidationListener, Integer> invalidationListeners = new LinkedHashMap<>();
! private Map<ChangeListener<? super T>, Integer> changeListeners = new LinkedHashMap<>();
private T currentValue;
+ private int weakChangeListenerGcCount = 2;
+ private int weakInvalidationListenerGcCount = 2;
private Generic(ObservableValue<T> observable, InvalidationListener listener0, InvalidationListener listener1) {
super(observable);
! this.invalidationListeners.put(listener0, 1);
! // use merge here in case listener1 == listener0
+ this.invalidationListeners.merge(listener1, 1, Integer::sum);
}
private Generic(ObservableValue<T> observable, ChangeListener<? super T> listener0, ChangeListener<? super T> listener1) {
super(observable);
! this.changeListeners.put(listener0, 1);
! // use merge here in case listener1 == listener0
+ this.changeListeners.merge(listener1, 1, Integer::sum);
this.currentValue = observable.getValue();
}
private Generic(ObservableValue<T> observable, InvalidationListener invalidationListener, ChangeListener<? super T> changeListener) {
super(observable);
! this.invalidationListeners.put(invalidationListener, 1);
! this.changeListeners.put(changeListener, 1);
this.currentValue = observable.getValue();
}
@Override
protected Generic<T> addListener(InvalidationListener listener) {
! if (invalidationListeners.size() == weakInvalidationListenerGcCount) {
! removeWeakListeners(invalidationListeners);
! if (invalidationListeners.size() == weakInvalidationListenerGcCount) {
! weakInvalidationListenerGcCount = (weakInvalidationListenerGcCount * 3)/2 + 1;
}
}
+ invalidationListeners.merge(listener, 1, Integer::sum);
return this;
}
@Override
protected ExpressionHelper<T> removeListener(InvalidationListener listener) {
! if (invalidationListeners.containsKey(listener)) {
! if (invalidationListeners.merge(listener, -1, Integer::sum) == 0) {
! invalidationListeners.remove(listener);
! if (invalidationListeners.isEmpty() && changeListeners.size() == 1) {
! return new SingleChange<T>(observable, changeListeners.keySet().iterator().next());
! } else if ((invalidationListeners.size() == 1) && changeListeners.isEmpty()) {
! return new SingleInvalidation<T>(observable, invalidationListeners.keySet().iterator().next());
}
}
}
return this;
}
@Override
protected ExpressionHelper<T> addListener(ChangeListener<? super T> listener) {
! if (changeListeners.size() == weakChangeListenerGcCount) {
! removeWeakListeners(changeListeners);
! if (changeListeners.size() == weakChangeListenerGcCount) {
! weakChangeListenerGcCount = (weakChangeListenerGcCount * 3)/2 + 1;
}
}
! changeListeners.merge(listener, 1, Integer::sum);
+ if (changeListeners.size() == 1) {
currentValue = observable.getValue();
}
return this;
}
@Override
protected ExpressionHelper<T> removeListener(ChangeListener<? super T> listener) {
! if (changeListeners.containsKey(listener)) {
! if (changeListeners.merge(listener, -1, Integer::sum) == 0) {
! changeListeners.remove(listener);
! if (changeListeners.isEmpty() && invalidationListeners.size() == 1) {
! return new SingleInvalidation<T>(observable, invalidationListeners.keySet().iterator().next());
! } else if ((changeListeners.size() == 1) && invalidationListeners.isEmpty()) {
! return new SingleChange<T>(observable, changeListeners.keySet().iterator().next());
}
}
}
return this;
}
@Override
protected void fireValueChangedEvent() {
! // Take a copy of listeners to ensure adding and removing listeners
! // while the observers are being notified is safe
! final Map<InvalidationListener, Integer> curInvalidationList = new LinkedHashMap<>(invalidationListeners);
! final Map<ChangeListener<? super T>, Integer> curChangeList = new LinkedHashMap<>(changeListeners);
+
+ curInvalidationList.entrySet().forEach(entry -> fireInvalidationListeners(entry));
+
+ if (!curChangeList.isEmpty()) {
+ final T oldValue = currentValue;
+ currentValue = observable.getValue();
+ final boolean changed = (currentValue == null)? (oldValue != null) : !currentValue.equals(oldValue);
+ if (changed) {
+ curChangeList.entrySet().forEach(entry -> fireChangeListeners(oldValue, entry));
+ }
+ }
+ }
+ private void fireInvalidationListeners(Entry<InvalidationListener, Integer> entry) {
+ final InvalidationListener listener = entry.getKey();
+ final int registrationCount = entry.getValue();
try {
! for (int i = 0; i < registrationCount; i++) {
! listener.invalidated(observable);
}
! } catch (Exception e) {
! Thread.currentThread().getUncaughtExceptionHandler().uncaughtException(
! Thread.currentThread(), e);
! }
! }
!
! private void fireChangeListeners(final T oldValue, Entry<ChangeListener<? super T>, Integer> entry) {
! final ChangeListener<? super T> listener = entry.getKey();
! final int registrationCount = entry.getValue();
! try {
! for (int i = 0; i < registrationCount; i++) {
! listener.changed(observable, oldValue, currentValue);
}
! } catch (Exception e) {
! Thread.currentThread().getUncaughtExceptionHandler().uncaughtException(
+ Thread.currentThread(), e);
}
}
}
}
< prev index next >