All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.cedarsoft.commons.javafx.BindingsHelper Maven / Gradle / Ivy
package com.cedarsoft.commons.javafx;
import java.text.NumberFormat;
import java.text.ParseException;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javafx.beans.InvalidationListener;
import javafx.beans.binding.Binding;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.LongBinding;
import javafx.beans.binding.StringBinding;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.Property;
import javafx.beans.property.ReadOnlyIntegerProperty;
import javafx.beans.property.ReadOnlyProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableBooleanValue;
import javafx.beans.value.ObservableValue;
import javafx.beans.value.WritableDoubleValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.css.PseudoClass;
import javafx.scene.Node;
import javafx.scene.control.ComboBox;
public class BindingsHelper {
private BindingsHelper() {
}
/**
* Binds a combo box
*/
@Nonnull
public static > ComboBox bindEnumCombo(@Nonnull ObjectProperty property, @Nonnull Class type) {
return bindEnumCombo(new ComboBox<>(), property, type);
}
@Nonnull
public static > ComboBox bindEnumComboSpecificEnums(@Nonnull ObjectProperty property, @Nonnull Class type, @Nonnull T[] enumConstants) {
return bindEnumComboSpecificEnums(new ComboBox<>(), property, type, enumConstants);
}
@Nonnull
public static > ComboBox bindEnumCombo(@Nonnull ComboBox combo, @Nonnull ObjectProperty property, @Nonnull Class type) {
return bindEnumComboSpecificEnums(combo, property, type, type.getEnumConstants());
}
@Nonnull
public static > ComboBox bindEnumComboSpecificEnums(@Nonnull ComboBox combo, @Nonnull ObjectProperty property, @Nonnull Class type, @Nonnull T[] enumConstants) {
combo.itemsProperty().set(FXCollections.observableArrayList(enumConstants));
combo.valueProperty().bindBidirectional(property);
combo.setButtonCell(new EnumListCell<>());
combo.setCellFactory(param -> new EnumListCell<>());
return combo;
}
@Nonnull
public static StringBinding toBinding(@Nonnull StringProperty stringProperty) {
return Bindings.createStringBinding(stringProperty::get, stringProperty);
}
public static > ComboBox bindEnumCombo(@Nonnull ComboBox combo, @Nonnull ObjectProperty property, @Nonnull ObservableList items) {
combo.itemsProperty().set(items);
combo.valueProperty().bindBidirectional(property);
return combo;
}
/**
* Sets the pseudo class when the given property is true
*/
public static void bindPseudoClass(@Nonnull Node node, @Nonnull PseudoClass pseudoClass, @Nonnull ObservableBooleanValue pseudoClassActive) {
//set initially
node.pseudoClassStateChanged(pseudoClass, pseudoClassActive.get());
//Update the pseudo class whenever the property changes
pseudoClassActive.addListener((observable, oldValue, newValue) -> node.pseudoClassStateChanged(pseudoClass, newValue));
}
@Nonnull
public static StringBinding asFormattedHex(@Nonnull ReadOnlyProperty longProperty) {
return Bindings.createStringBinding(() -> {
long longValue = longProperty.getValue().longValue();
if (longValue == 0) {
return "";
}
return toHex(longValue);
}, longProperty);
}
/**
* Converts to upper case hex with prefix "0x"
*/
@Nonnull
public static String toHex(long longValue) {
return "0x" + Long.toHexString(longValue).toUpperCase();
}
/**
* Wraps a string binding and ensures that no empty string is returned
*/
@Nonnull
public static Binding avoidEmptyString(@Nonnull Binding binding, @Nonnull String emptyStringReplacement) {
return new Binding() {
@Override
public String getValue() {
String value = binding.getValue();
if (value == null || value.trim().isEmpty()) {
return emptyStringReplacement;
}
return value;
}
@Override
public boolean isValid() {
return binding.isValid();
}
@Override
public void invalidate() {
binding.invalidate();
}
@Override
public ObservableList> getDependencies() {
return binding.getDependencies();
}
@Override
public void dispose() {
binding.dispose();
}
@Override
public void addListener(ChangeListener super String> listener) {
binding.addListener(listener);
}
@Override
public void removeListener(ChangeListener super String> listener) {
binding.removeListener(listener);
}
@Override
public void addListener(InvalidationListener listener) {
binding.addListener(listener);
}
@Override
public void removeListener(InvalidationListener listener) {
binding.removeListener(listener);
}
};
}
@Nonnull
public static StringBinding bindFormattedNumber(@Nonnull ObservableValue property, @Nonnull NumberFormat numberFormat) {
return Bindings.createStringBinding(() -> numberFormat.format(property.getValue()), property);
}
/**
* Creates a listener that ensures a given property always is within the given min and max value (both inclusive)
*/
@Nonnull
public static ChangeListener createBoundsChecker(double minValue, double maxValue) {
return (observable, oldValue, newValue) -> {
if (newValue.doubleValue() < minValue) {
((WritableDoubleValue) observable).set(minValue);
}
if (newValue.doubleValue() > maxValue) {
((WritableDoubleValue) observable).set(maxValue);
}
};
}
/**
* Can be used to bind a double property to a string property
*/
@Nonnull
public static Property double2stringBiDirectional(@Nonnull DoubleProperty doubleProperty) {
SimpleStringProperty stringProperty = new SimpleStringProperty();
stringProperty.addListener((observable, oldValue, newValue) -> {
try {
double doubleValue = string2double(newValue);
doubleProperty.setValue(doubleValue);
} catch (ParseException e) {
//Enforce the old values if can not be parsed
stringProperty.setValue(oldValue);
}
});
doubleProperty.addListener(new ChangeListener() {
@Override
public void changed(ObservableValue extends Number> observable, Number oldValue, Number newValue) {
try {
double oldValueFromString = string2double(stringProperty.get());
if (oldValueFromString == newValue.doubleValue()) {
return;
}
} catch (ParseException ignore) {
}
stringProperty.setValue(NumberFormat.getInstance().format(newValue.doubleValue()));
}
});
return stringProperty;
}
/**
* Converts a string to double. Handles null values and empty strings
*/
private static double string2double(@Nullable String newValue) throws ParseException {
if (newValue == null || newValue.isEmpty()) {
return 0.0;
}
return NumberFormat.getInstance().parse(newValue.trim()).doubleValue();
}
/**
* creates a LongBinding from three Integer properties.
* @param intProperty0
* @param intProperty1
* @param intProperty2
*/
public static LongBinding createLongBinding(@Nonnull ReadOnlyIntegerProperty intProperty0,
@Nonnull ReadOnlyIntegerProperty intProperty1,
@Nonnull ReadOnlyIntegerProperty intProperty2) {
return Bindings.createLongBinding(() -> {
Integer byte0 = intProperty0.getValue() & 0xffffff;
Integer byte1 = intProperty1.getValue() & 0xffff;
Integer byte2 = intProperty2.getValue() & 0xff;
return (long) (byte2 + byte1 * 256 + byte0 * 256 * 256);
}, intProperty0, intProperty1, intProperty2);
}
/**
* Binds two method calls to a boolean property.
* The method corresponding to the current state is called once initially
*/
public static void bindMethodsToBoolean(@Nonnull ObservableValue property, @Nonnull Runnable onTrue, @Nonnull Runnable onFalse) {
property.addListener((observable, oldValue, newValue) -> {
if (newValue) {
onTrue.run();
}
else {
onFalse.run();
}
});
//Initial
if (property.getValue()) {
onTrue.run();
}
else {
onFalse.run();
}
}
}