package org.tessell.model.properties;
import static java.lang.Boolean.TRUE;
import java.util.ArrayList;
import java.util.List;
import org.tessell.model.values.DerivedValue;
import org.tessell.model.values.LambdaValue;
import org.tessell.model.values.SetValue;
import org.tessell.model.values.Value;
import com.google.gwt.event.dom.client.HasAllDragAndDropHandlers;
/** Lots of helper methods to constructor {@link Property}s out of bindings/{@link DerivedValue}s/etc. */
public class NewProperty {
public static <P> BasicProperty<P> property(String name, P value) {
return new BasicProperty<P>(new SetValue<P>(name, value));
}
public static <P> BasicProperty<P> derivedProperty(final LambdaValue<P> value) {
return new BasicProperty<P>(value);
}
public static <P> BasicProperty<P> derivedProperty(final DerivedValue<P> value) {
return new BasicProperty<P>(value);
}
public static <P> BasicProperty<P> basicProperty(final Value<P> value) {
return new BasicProperty<P>(value);
}
public static <P> BasicProperty<P> basicProperty(final LambdaValue<P> value) {
return new BasicProperty<P>(value);
}
public static <P> BasicProperty<P> basicProperty(final String name) {
return new BasicProperty<P>(new SetValue<P>(name));
}
public static <P> BasicProperty<P> basicProperty(final String name, P initialValue) {
return new BasicProperty<P>(new SetValue<P>(name, initialValue));
}
public static <T> BasicProperty<T> basicProperty(final String name, final Getter<T> getter, Setter<T> setter) {
return new BasicProperty<T>(new GetSetValue<T>(name, getter, setter));
}
public static BooleanProperty booleanProperty(final String name) {
return new BooleanProperty(new SetValue<Boolean>(name));
}
public static BooleanProperty booleanProperty(final String name, final boolean initialValue) {
return new BooleanProperty(new SetValue<Boolean>(name, initialValue));
}
public static BooleanProperty booleanProperty(final Value<Boolean> value) {
return new BooleanProperty(value);
}
public static BooleanProperty booleanProperty(final LambdaValue<Boolean> value) {
return new BooleanProperty(value);
}
public static BooleanProperty booleanProperty(final String name, final Getter<Boolean> getter, Setter<Boolean> setter) {
return new BooleanProperty(new GetSetValue<Boolean>(name, getter, setter));
}
public static Property<Boolean> not(final Property<Boolean> property) {
return property.formatted(new PropertyFormatter<Boolean, Boolean>() {
public Boolean format(Boolean a) {
return !property.get();
}
public Boolean parse(Boolean b) throws Exception {
return !b;
}
});
}
@SafeVarargs
public static BooleanProperty or(final Property<Boolean>... properties) {
return booleanProperty(new DerivedValue<Boolean>() {
public Boolean get() {
for (Property<Boolean> property : properties) {
if (TRUE.equals(property.get())) {
return true;
}
}
return false;
}
});
}
@SafeVarargs
public static <E> ListProperty<E> union(final ListProperty<E>... properties) {
return listProperty(new DerivedValue<List<E>>("union") {
public List<E> get() {
List<E> copy = new ArrayList<E>();
for (ListProperty<E> property : properties) {
copy.addAll(property.get());
}
return copy;
}
});
}
@SafeVarargs
public static BooleanProperty and(final Property<Boolean>... properties) {
return booleanProperty(new DerivedValue<Boolean>() {
public Boolean get() {
for (Property<Boolean> property : properties) {
if (!TRUE.equals(property.get())) {
return false;
}
}
return true;
}
});
}
// We cannot always rely on dragend events to manage "is current" within draggingOver
// itself. If we use this static state instead, the next draggable getting a dragstart
// event effectively resets "is current" to false for the previous dragstart target.
private static HasAllDragAndDropHandlers currentDraggable;
/** @return a {@link BooleanProperty} of whether {@code draggable} is current being dragged over. */
public static BooleanProperty draggingOver(HasAllDragAndDropHandlers draggable) {
BooleanProperty over = booleanProperty("over");
// for ignoring drag enters when we're selected
draggable.addDragStartHandler(e -> currentDraggable = draggable);
// Technically if the draggable element is removed from the DOM (say because the
// current drag's drop logic moves it somewhere else), we will not get the dragend
// event. So we can set it null here, but we rely on the static currentDraggable
// being reset by the next dragstart to handle the "removed from DOM" case.
draggable.addDragEndHandler(e -> currentDraggable = null);
// our children will bubble up dragEnters/dragLeaves as well, so keep track
// of the "last" drag enter, which will be ours, and ignore them until then
int[] count = { 0 };
draggable.addDragEnterHandler(e -> {
if (currentDraggable != draggable && ++count[0] == 1) {
over.set(true);
}
});
draggable.addDragLeaveHandler(e -> {
if (over.isTrue() && --count[0] == 0) {
over.set(false);
}
});
draggable.addDropHandler(e -> {
over.set(false);
count[0] = 0;
});
return over;
}
public static BooleanProperty dragging(HasAllDragAndDropHandlers draggable) {
BooleanProperty dragging = booleanProperty("dragging");
draggable.addDragStartHandler(e -> dragging.set(true));
draggable.addDragEndHandler(e -> dragging.set(false));
return dragging;
}
public static IntegerProperty integerProperty(final String name) {
return new IntegerProperty(new SetValue<Integer>(name));
}
public static IntegerProperty integerProperty(final String name, Integer i) {
return new IntegerProperty(new SetValue<Integer>(name, i));
}
public static IntegerProperty integerProperty(final Value<Integer> derived) {
return new IntegerProperty(derived);
}
public static IntegerProperty integerProperty(final LambdaValue<Integer> derived) {
return new IntegerProperty(derived);
}
public static IntegerProperty integerProperty(final String name, final Getter<Integer> getter, Setter<Integer> setter) {
return new IntegerProperty(new GetSetValue<Integer>(name, getter, setter));
}
public static LongProperty longProperty(final String name) {
return new LongProperty(new SetValue<Long>(name));
}
public static LongProperty longProperty(final String name, Long i) {
return new LongProperty(new SetValue<Long>(name, i));
}
public static LongProperty longProperty(final Value<Long> derived) {
return new LongProperty(derived);
}
public static LongProperty longProperty(final LambdaValue<Long> derived) {
return new LongProperty(derived);
}
public static LongProperty longProperty(final String name, final Getter<Long> getter, Setter<Long> setter) {
return new LongProperty(new GetSetValue<Long>(name, getter, setter));
}
public static StringProperty stringProperty(final String name) {
return new StringProperty(new SetValue<String>(name));
}
public static StringProperty stringProperty(final String name, final String initialValue) {
return new StringProperty(new SetValue<String>(name, initialValue));
}
public static StringProperty stringProperty(final Value<String> value) {
return new StringProperty(value);
}
public static StringProperty stringProperty(final LambdaValue<String> value) {
return new StringProperty(value);
}
public static StringProperty stringProperty(final String name, final Getter<String> getter, Setter<String> setter) {
return new StringProperty(new GetSetValue<String>(name, getter, setter));
}
public static <E> ListProperty<E> listProperty(final Value<List<E>> value) {
return new ListProperty<E>(value);
}
public static <E> ListProperty<E> listProperty(final LambdaValue<List<E>> value) {
return new ListProperty<E>(value);
}
public static <E> ListProperty<E> listProperty(final String name, final List<E> list) {
return new ListProperty<E>(new SetValue<List<E>>(name, list));
}
public static <E> ListProperty<E> listProperty(final String name) {
return new ListProperty<E>(new SetValue<List<E>>(name, new ArrayList<E>()));
}
public static <E> ListProperty<E> listProperty(final String name, final Getter<List<E>> getter, Setter<List<E>> setter) {
return new ListProperty<E>(new GetSetValue<List<E>>(name, getter, setter));
}
public static <P> SetValue<P> setValue(String name) {
return new SetValue<P>(name);
}
public static <P> SetValue<P> setValue(String name, P initialValue) {
return new SetValue<P>(name, initialValue);
}
public static <E extends Enum<E>> EnumProperty<E> enumProperty(final Value<E> value) {
return new EnumProperty<E>(value);
}
public static <E extends Enum<E>> EnumProperty<E> enumProperty(final LambdaValue<E> value) {
return new EnumProperty<E>(value);
}
public static <E extends Enum<E>> EnumProperty<E> enumProperty(final String name) {
return new EnumProperty<E>(new SetValue<E>(name));
}
public static <E extends Enum<E>> EnumProperty<E> enumProperty(final String name, E initialValue) {
return new EnumProperty<E>(new SetValue<E>(name, initialValue));
}
/** Takes {@link Getter} and {@link Setter}, ideally provided as lambdas, and adapts them to a {@link Value}. */
public static class GetSetValue<T> implements Value<T> {
private final String name;
private final Getter<T> getter;
private final Setter<T> setter;
GetSetValue(String name, Getter<T> getter, Setter<T> setter) {
this.name = name;
this.getter = getter;
this.setter = setter;
}
@Override
public T get() {
return getter.get();
}
@Override
public void set(T value) {
setter.set(value);
}
@Override
public String getName() {
return name;
}
@Override
public boolean isReadOnly() {
return setter != null;
}
@Override
public String toString() {
return name + " " + getter.get();
}
}
}