org.pushingpixels.trident.TimelinePropertyBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of radiance-trident Show documentation
Show all versions of radiance-trident Show documentation
Building modern, elegant and fast Swing applications
/*
* Copyright (c) 2005-2018 Trident Kirill Grouchnikov. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* o Neither the name of Trident Kirill Grouchnikov nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.pushingpixels.trident;
import org.pushingpixels.trident.interpolator.KeyFrames;
import org.pushingpixels.trident.interpolator.PropertyInterpolator;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class TimelinePropertyBuilder {
/**
* Defines how to set a property.
*/
public static interface PropertySetter {
public void set(Object obj, String fieldName, T value);
}
/**
* Defines how to get a property.
*/
public static interface PropertyGetter {
public T get(Object obj, String fieldName);
}
/**
* Defines how to access a property.
*/
public static interface PropertyAccessor extends PropertyGetter, PropertySetter {
}
/**
* Default property setter.
*/
public static class DefaultPropertySetter implements PropertySetter {
private Method setterMethod;
public DefaultPropertySetter(Object obj, String fieldName) {
setterMethod = getSetter(obj, fieldName);
}
public void set(Object obj, String fieldName, T value) {
try {
setterMethod.invoke(obj, value);
} catch (Throwable t) {
throw new RuntimeException(
"Unable to set the value of the field '" + fieldName + "'", t);
}
}
}
/**
* Default property getter.
*/
public static class DefaultPropertyGetter implements PropertyGetter {
private Method getterMethod;
public DefaultPropertyGetter(Object obj, String fieldName) {
getterMethod = getGetter(obj, fieldName);
}
public T get(Object obj, String fieldName) {
try {
return (T) getterMethod.invoke(obj);
} catch (Throwable t) {
throw new RuntimeException(
"Unable to get the value of the field '" + fieldName + "'", t);
}
}
}
private Object target; // may be null
private final String propertyName; // required
private T from; // optional
private boolean isFromCurrent;
private T to; // must be optional because of KeyFrames
private PropertyInterpolator interpolator; // optional
private PropertyGetter getter; // optional
private PropertySetter setter; // optional
private KeyFrames keyFrames; // optional
TimelinePropertyBuilder(String propertyName) {
this.propertyName = propertyName;
this.isFromCurrent = false;
}
public TimelinePropertyBuilder from(T startValue) {
if (this.from != null) {
throw new IllegalArgumentException("from() can only be called once");
}
if (this.isFromCurrent) {
throw new IllegalArgumentException("from() cannot be called after fromCurrent()");
}
if (this.keyFrames != null) {
throw new IllegalArgumentException("from() cannot be called after goingThrough()");
}
this.from = startValue;
return this;
}
public TimelinePropertyBuilder fromCurrent() {
if (this.isFromCurrent) {
throw new IllegalArgumentException("fromCurrent() can only be called once");
}
if (this.from != null) {
throw new IllegalArgumentException("fromCurrent() cannot be called after from()");
}
if (this.keyFrames != null) {
throw new IllegalArgumentException(
"fromCurrent() cannot be called after goingThrough()");
}
this.isFromCurrent = true;
return this;
}
public TimelinePropertyBuilder to(T endValue) {
if (this.to != null) {
throw new IllegalArgumentException("to() can only be called once");
}
if (this.keyFrames != null) {
throw new IllegalArgumentException("to() cannot be called after goingThrough()");
}
this.to = endValue;
return this;
}
public TimelinePropertyBuilder on(Object object) {
this.target = object;
return this;
}
public TimelinePropertyBuilder interpolatedWith(PropertyInterpolator pInterpolator) {
if (this.interpolator != null) {
throw new IllegalArgumentException("interpolatedWith() can only be called once");
}
this.interpolator = pInterpolator;
return this;
}
public TimelinePropertyBuilder setWith(PropertySetter pSetter) {
if (this.setter != null) {
throw new IllegalArgumentException("setWith() can only be called once");
}
this.setter = pSetter;
return this;
}
public TimelinePropertyBuilder getWith(PropertyGetter pGetter) {
if (this.getter != null) {
throw new IllegalArgumentException("getWith() can only be called once");
}
this.getter = pGetter;
return this;
}
public TimelinePropertyBuilder accessWith(PropertyAccessor pAccessor) {
if (this.setter != null || this.getter != null) {
throw new IllegalArgumentException("accessWith() can only be called once");
}
this.setter = pAccessor;
this.getter = pAccessor;
return this;
}
public TimelinePropertyBuilder goingThrough(KeyFrames keyFrames) {
if (this.keyFrames != null) {
throw new IllegalArgumentException("goingThrough() can only be called once");
}
if (this.isFromCurrent) {
throw new IllegalArgumentException(
"goingThrough() cannot be called after fromCurrent()");
}
if (this.from != null) {
throw new IllegalArgumentException("goingThrough() cannot be called after from()");
}
if (this.to != null) {
throw new IllegalArgumentException("goingThrough() cannot be called after to()");
}
this.keyFrames = keyFrames;
return this;
}
AbstractFieldInfo getFieldInfo(Timeline timeline) {
if (this.target == null) {
this.target = timeline.mainObject;
}
if (this.keyFrames != null) {
return new KeyFramesFieldInfo(this.target, this.propertyName, this.keyFrames,
this.setter);
}
if (this.isFromCurrent) {
if (this.interpolator == null) {
this.interpolator = TridentConfig.getInstance().getPropertyInterpolator(this.to);
if (this.interpolator == null) {
throw new IllegalArgumentException(
"No interpolator found for " + this.to.getClass().getName());
}
}
return new GenericFieldInfoTo(this.target, this.propertyName, this.to,
this.interpolator, this.getter, this.setter);
}
if (this.interpolator == null) {
this.interpolator = TridentConfig.getInstance().getPropertyInterpolator(this.from,
this.to);
if (this.interpolator == null) {
throw new IllegalArgumentException("No interpolator found for "
+ this.from.getClass().getName() + ":" + this.to.getClass().getName());
}
}
return new GenericFieldInfo(this.target, this.propertyName, this.from, this.to,
this.interpolator, this.setter);
}
abstract class AbstractFieldInfo {
protected Object object;
protected String fieldName;
protected PropertyGetter getter;
protected PropertySetter setter;
protected F from;
protected F to;
AbstractFieldInfo(Object obj, String fieldName, PropertyGetter pGetter,
PropertySetter pSetter) {
this.object = obj;
this.fieldName = fieldName;
this.getter = pGetter;
this.setter = pSetter;
}
void setValues(F from, F to) {
this.from = from;
this.to = to;
}
abstract void onStart();
abstract void updateFieldValue(float timelinePosition);
}
private static PropertyGetter getPropertyGetter(Object obj, String fieldName,
PropertyGetter pGetter) {
if (pGetter != null)
return pGetter;
return new DefaultPropertyGetter(obj, fieldName);
}
private static PropertySetter getPropertySetter(Object obj, String fieldName,
PropertySetter pSetter) {
if (pSetter != null)
return pSetter;
return new DefaultPropertySetter(obj, fieldName);
}
private class GenericFieldInfoTo extends AbstractFieldInfo