📄 binding.java
字号:
/**
* Unsets the value of the {@code sourceUnreadableValue} property by clearing
* the value and setting the value of the {@code sourceUnreadableValueSet}
* property to {@code false}.
* <p>
* If the property was previously set, fires a property change notification
* with property name {@code "sourceUnreadableValueSet"}, and a property
* change notification with property name {@code "sourceUnreadableValue"}.
* The event for the latter notification will have a new value of {@code null}.
* <p>
* See the documentation for {@link #setSourceUnreadableValue} for more
* information on the {@code sourceUnreadableValue} property.
* <p>
* This method may not be called on a bound binding.
*
* @throws IllegalStateException if the {@code Binding} is bound
* @see #isSourceUnreadableValueSet
* @see #getSourceUnreadableValue
*/
public final void unsetSourceUnreadableValue() {
throwIfBound();
if (isSourceUnreadableValueSet()) {
TV old = this.sourceUnreadableValue;
this.sourceUnreadableValue = null;
this.sourceUnreadableValueSet = false;
firePropertyChange("sourceUnreadableValueSet", true, false);
firePropertyChange("sourceUnreadableValue", old, null);
}
}
/**
* Returns the value of the {@code sourceUnreadableValueSet} property,
* which indicates whether or not the {@code sourceUnreadableValue} property
* is set on the {@code Binding}.
* <p>
* See the documentation for {@link #setSourceUnreadableValue} for more
* information on the {@code sourceUnreadableValue} property.
*
* @return whether or not the {@code sourceUnreadableValue} property
* is set on the {@code Binding}
* @see #unsetSourceUnreadableValue
* @see #getSourceUnreadableValue
*/
public final boolean isSourceUnreadableValueSet() {
return sourceUnreadableValueSet;
}
/**
* If set, returns the value to be returned by {@link #getSourceValueForTarget}
* when the source property is unreadable for the source object. Throws
* {@code UnsupportedOperationException} if the property is not set,
* as indicated by {@link #isSourceUnreadableValueSet}.
* <p>
* See the documentation for {@link #setSourceUnreadableValue} for more
* information on this property.
*
* @return the value that replaces an unreadable source value, which may
* be {@code null}
* @see #unsetSourceUnreadableValue
* @throws UnsupportedOperationException if the property is not set,
* as indicated by {@code isSourceUnreadableValueSet}
*/
public final TV getSourceUnreadableValue() {
if (!isSourceUnreadableValueSet()) {
throw new UnsupportedOperationException("not set");
}
return sourceUnreadableValue;
}
/**
* Adds a {@code BindingListener} to be notified of changes to this {@code Binding}.
* Does nothing if the listener is {@code null}. If a listener is added more than once,
* notifications are sent to that listener once for every time that it has
* been added. The ordering of listener notification is unspecified.
*
* @param listener the listener to add
*/
public final void addBindingListener(BindingListener listener) {
if (listener == null) {
return;
}
if (listeners == null) {
listeners = new ArrayList<BindingListener>();
}
listeners.add(listener);
}
/**
* Removes a {@code BindingListener} from the {@code Binding}. Does
* nothing if the listener is {@code null} or is not one of those registered.
* If the listener being removed was registered more than once, only one
* occurrence of the listener is removed from the list of listeners.
* The ordering of listener notification is unspecified.
*
* @param listener the listener to remove
* @see #addBindingListener
*/
public final void removeBindingListener(BindingListener listener) {
if (listener == null) {
return;
}
if (listeners != null) {
listeners.remove(listener);
}
}
/**
* Returns the list of {@code BindingListeners} registered on this
* {@code Binding}. Order is undefined. Returns an empty array if there are
* no listeners.
*
* @return the list of {@code BindingListeners} registered on this {@code Binding}
* @see #addBindingListener
*/
public final BindingListener[] getBindingListeners() {
if (listeners == null) {
return new BindingListener[0];
}
BindingListener[] ret = new BindingListener[listeners.size()];
ret = listeners.toArray(ret);
return ret;
}
/**
* Fetches the value of the source property for the source object and
* returns a {@code ValueResult} representing that value in terms that
* can be set on the target property for the target object.
* <p>
* First, if the target property is not writeable for the target object,
* a {@code ValueResult} is returned representing a failure
* with failure type {@code SyncFailureType.TARGET_UNWRITEABLE}.
* Then, if the source property is unreadable for the source object,
* the value of {@link #isSourceUnreadableValueSet} is checked. If {@code true}
* then a {@code ValueResult} is returned containing the value of the
* {@code Binding's} {@link #getSourceUnreadableValue}. Otherwise a
* {@code ValueResult} is returned representing a failure with failure
* type {@code SyncFailureType.SOURCE_UNREADABLE}.
* <p>
* Next, the value of the source property is fetched for the source
* object. If the value is {@code null}, a {@code ValueResult} is
* returned containing the value of the {@code Binding's}
* {@link #getSourceNullValue}. If the value is {@code non-null},
* the {@code Binding's Converter}, if any, is run to convert
* the value from source type to the target property's
* {@code getWriteType}, by calling its {@code convertForward}
* method with the value. If no {@code Converter} is registered,
* a set of default converters is checked to see if one of them
* can convert the value to the target type. Finally, the value
* (converted or not) is cast to the target write type.
* <p>
* This final value is returned in a {@code ValueResult}.
* <p>
* Any {@code RuntimeException} or {@code ClassCastException} thrown by a
* converter or the final cast is propogated up to the caller of this method.
*
* @return a {@code ValueResult} as described above
* @throws RuntimeException if thrown by any of the converters
* @throws ClassCastException if thrown by a converter or the final cast
*/
public final ValueResult<TV> getSourceValueForTarget() {
if (!targetProperty.isWriteable(targetObject)) {
return new ValueResult<TV>(SyncFailure.TARGET_UNWRITEABLE);
}
if (!sourceProperty.isReadable(sourceObject)) {
if (sourceUnreadableValueSet) {
return new ValueResult<TV>(sourceUnreadableValue);
} else {
return new ValueResult<TV>(SyncFailure.SOURCE_UNREADABLE);
}
}
TV value;
SV rawValue = sourceProperty.getValue(sourceObject);
if (rawValue == null) {
value = sourceNullValue;
} else {
// may throw ClassCastException or other RuntimeException here;
// allow it to be propogated back to the user of Binding
value = convertForward(rawValue);
}
return new ValueResult<TV>(value);
}
/**
* Fetches the value of the target property for the target object and
* returns a {@code ValueResult} representing that value in terms that
* can be set on the source property for the source object.
* <p>
* First, if the source property is not writeable for the source object,
* a {@code ValueResult} is returned representing a failure
* with failure type {@code SyncFailureType.SOURCE_UNWRITEABLE}.
* Then, if the target property is not readable for the target object,
* a {@code ValueResult} is returned representing a failure
* with failure type {@code SyncFailureType.TARGET_UNREADABLE}.
* <p>
* Next, the value of the target property is fetched for the target
* object. If the value is {@code null}, a {@code ValueResult} is
* returned containing the value of the {@code Binding's}
* {@link #getTargetNullValue}. If the value is {@code non-null},
* the {@code Binding's Converter}, if any, is run to convert
* the value from target type to the source property's
* {@code getWriteType}, by calling its {@code convertReverse}
* method with the value. If no {@code Converter} is registered,
* a set of default converters is checked to see if one of them
* can convert the value to the source type. Finally, the value
* (converted or not) is cast to the source write type.
* <p>
* If a converter throws a {@code RuntimeException} other than
* {@code ClassCastException}, this method returns a
* {@code ValueResult} containing the failure, with failure type
* {@code SyncFailureType.CONVERSION_FAILURE}.
* <p>
* As the last step, the {@code Binding's Validator}, if any, is called
* upon to validate the final value. If the {@code Validator}
* returns {@code non-null} from its {@code validate} method,
* a {@code ValueResult} is returned containing the validation
* result, with failure type {@code SyncFailureType.VALIDATION_FAILURE}.
* Otherwise a {@code ValueResult} is returned containing the
* final validated value.
* <p>
* Any {@code ClassCastException} thrown by a converter or the final
* cast is propogated up to the caller of this method.
*
* @return a {@code ValueResult} as described above
* @throws ClassCastException if thrown by a converter or the final cast
*/
public final ValueResult<SV> getTargetValueForSource() {
if (!sourceProperty.isWriteable(sourceObject)) {
return new ValueResult<SV>(SyncFailure.SOURCE_UNWRITEABLE);
}
if (!targetProperty.isReadable(targetObject)) {
return new ValueResult<SV>(SyncFailure.TARGET_UNREADABLE);
}
SV value = null;
TV rawValue = targetProperty.getValue(targetObject);
if (rawValue == null) {
value = targetNullValue;
} else {
try {
value = convertReverse(rawValue);
} catch (ClassCastException cce) {
throw cce;
} catch (RuntimeException rte) {
return new ValueResult<SV>(SyncFailure.conversionFailure(rte));
}
if (validator != null) {
Validator.Result vr = validator.validate(value);
if (vr != null) {
return new ValueResult<SV>(SyncFailure.validationFailure(vr));
}
}
}
return new ValueResult<SV>((SV)value);
}
/**
* Binds this binding. Calls {@link #bindImpl} to allow subclasses
* to initiate binding, adds a {@code PropertyStateListener} to the source
* property for the source object and the target property for the target
* object to start tracking changes, notifies all registered
* {@code BindingListeners} that the binding has become bound, and
* fires a property change notification to indicate a change to the
* {@code "bound"} property.
*
* @throws UnsupportedOperationException if the {@code Binding} is managed
* @throws IllegalStateException if the {@code Binding} is already bound
* @see #isBound()
* @see #isManaged()
* @see #unbind
*/
public final void bind() {
throwIfManaged();
bindUnmanaged();
}
/**
* A protected version of {@link #bind} that allows managed
* subclasses to bind without throwing an exception
* for being managed.
*
* @throws IllegalStateException if the {@code Binding} is bound
* @see #isManaged()
* @see #isBound()
*/
protected final void bindUnmanaged() {
throwIfBound();
bindImpl();
psl = new PSL();
sourceProperty.addPropertyStateListener(sourceObject, psl);
targetProperty.addPropertyStateListener(targetObject, psl);
isBound = true;
if (listeners != null) {
for (BindingListener listener : listeners) {
listener.bindingBecameBound(this);
}
}
firePropertyChange("bound", false, true);
}
/**
* Called by {@link #bind} to allow subclasses to initiate binding.
* Subclasses typically need not install {@code PropertyStateListeners}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -