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.
io.github.mmm.ui.api.binding.data.UiDataBinding Maven / Gradle / Ivy
/* Copyright (c) The m-m-m Team, Licensed under the Apache License, Version 2.0
* http://www.apache.org/licenses/LICENSE-2.0 */
package io.github.mmm.ui.api.binding.data;
import java.util.Collection;
import io.github.mmm.bean.BeanFactory;
import io.github.mmm.bean.ReadableBean;
import io.github.mmm.bean.WritableBean;
import io.github.mmm.bean.property.ReadableBeanProperty;
import io.github.mmm.entity.id.Id;
import io.github.mmm.entity.link.Link;
import io.github.mmm.property.ReadableProperty;
import io.github.mmm.property.WritableProperty;
import io.github.mmm.property.container.ReadableContainerProperty;
import io.github.mmm.ui.api.UiLocalizer;
import io.github.mmm.ui.api.event.UiValueChangeEvent;
import io.github.mmm.ui.api.factory.UiWidgetFactoryProperty;
import io.github.mmm.ui.api.widget.form.UiFormGroup;
import io.github.mmm.ui.api.widget.form.UiFormPanel;
import io.github.mmm.ui.api.widget.input.UiAbstractInput;
import io.github.mmm.ui.api.widget.input.UiInput;
import io.github.mmm.ui.api.widget.value.UiValidatableWidget;
import io.github.mmm.validation.Validator;
/**
* Binding that allows to bind a {@link ReadableProperty property} or an entire {@link ReadableBean bean} to the UI. It
* can create entire dialogs forms for beans dynamically.
*/
public class UiDataBinding {
private final PropertyProvider defaultPropertyFilter;
/**
* The constructor.
*/
public UiDataBinding() {
this(null);
}
/**
* The constructor.
*
* @param defaultPropertyFilter the {@link PropertyProvider} to use as default.
*/
public UiDataBinding(PropertyProvider defaultPropertyFilter) {
super();
if (defaultPropertyFilter == null) {
this.defaultPropertyFilter = PropertyProviderDefault.INSTANCE;
} else {
this.defaultPropertyFilter = defaultPropertyFilter;
}
}
public UiValidatableWidget createEditor(B bean) {
return createEditor(bean, 2);
}
public UiValidatableWidget createEditor(B bean, int columns) {
// UiResponsiveColumnPanel panel = context.create(UiResponsiveColumnPanel.class);
// bindBean(bean, panel, columns);
// return new UiCustomForm<>(this.context, getValue, setValue);
return null;
}
/**
* @param bean the {@link ReadableBean} to bind.
* @param receiver the {@link UiBindingReceiver}.
* @param createGroup - {@code true} to create {@link UiFormGroup}s for nested beans, {@code false} otherwise.
*/
public void bindBean(ReadableBean bean, UiBindingReceiver receiver, boolean createGroup) {
bindBean(bean, receiver, createGroup, this.defaultPropertyFilter);
}
/**
* @param bean the {@link ReadableBean} to bind.
* @param receiver the {@link UiBindingReceiver}.
* @param createGroup - {@code true} to create {@link UiFormGroup}s for nested beans, {@code false} otherwise.
* @param propertyProvider the {@link PropertyProvider}.
*/
public void bindBean(ReadableBean bean, UiBindingReceiver receiver, boolean createGroup,
PropertyProvider propertyProvider) {
if (bean == null) {
return;
}
propertyProvider.get(bean).forEach(p -> {
bindProperty(p, bean, receiver, propertyProvider, createGroup);
});
}
private void bindProperty(ReadableProperty property, ReadableBean bean, UiBindingReceiver receiver,
PropertyProvider propertyProvider, boolean createGroup) {
if (property instanceof ReadableBeanProperty) {
bindBean((ReadableBeanProperty>) property, bean, receiver, propertyProvider, createGroup);
} else {
createInput(property, bean, receiver, false);
}
}
private void bindBean(ReadableBeanProperty beanProperty, ReadableBean parentBean,
UiBindingReceiver receiver, PropertyProvider propertyFilter, boolean createGroup) {
B childBean = beanProperty.get();
if (childBean == null) {
childBean = BeanFactory.get().create(beanProperty.getValueClass());
}
if (createGroup) {
UiFormGroup formGroup = createFormGroup(childBean, beanProperty, parentBean, propertyFilter);
receiver.add(beanProperty, formGroup);
} else {
bindBean(childBean, receiver, false, propertyFilter);
}
}
/**
* @param type of {@link WritableBean}.
* @param bean the {@link WritableBean}.
* @return the {@link UiFormGroup}.
*/
public UiFormPanel createFormPanel(B bean) {
return createFormPanel(bean, this.defaultPropertyFilter);
}
/**
* @param type of {@link WritableBean}.
* @param bean the {@link WritableBean}.
* @param propertyFilter the {@link PropertyProvider}.
* @return the {@link UiFormGroup}.
*/
public UiFormPanel createFormPanel(B bean, PropertyProvider propertyFilter) {
UiBindingReceiverImpl binding = new UiBindingReceiverImpl<>(bean);
bindBean(bean, binding, true, propertyFilter);
Collection> inputs = binding.getInputs();
if (inputs.isEmpty()) {
return null;
}
UiFormPanel formPanel = UiFormPanel.of(binding);
for (UiAbstractInput> input : inputs) {
formPanel.addChild(input);
}
return formPanel;
}
/**
* @param type of {@link WritableBean}.
* @param bean the {@link WritableBean}.
* @param beanProperty the {@link ReadableBeanProperty}.
* @param parentBean the parent {@link ReadableBean bean}.
* @param propertyFilter the {@link PropertyProvider}.
* @return the {@link UiFormGroup}.
*/
public UiFormGroup createFormGroup(B bean, ReadableBeanProperty beanProperty,
ReadableBean parentBean, PropertyProvider propertyFilter) {
String groupName = localizeLabel(beanProperty, parentBean);
UiBindingReceiverImpl binding = new UiBindingReceiverImpl<>(bean);
bindBean(bean, binding, false, propertyFilter);
Collection> inputs = binding.getInputs();
if (inputs.isEmpty()) {
return null;
}
UiFormGroup formGroup = UiFormGroup.of(binding, groupName);
for (UiAbstractInput> input : inputs) {
formGroup.addChild((UiInput>) input);
}
return formGroup;
}
/**
* @param property the {@link ReadableProperty} to test.
* @return {@code true} if the given {@code property} should be bound to the UI, {@code false} otherwise.
*/
protected boolean isBindableProperty(ReadableProperty> property) {
if (property instanceof ReadableContainerProperty) {
return isBindableProperty(((ReadableContainerProperty, ?>) property).getValueProperty());
}
Class> valueClass = property.getValueClass();
if (Id.class.isAssignableFrom(valueClass)) {
return false;
} else if (Link.class.isAssignableFrom(valueClass)) {
return false;
}
return true;
}
/**
* @param type of the {@link ReadableProperty#get() property value}.
* @param property the {@link ReadableProperty}.
* @param source the optional {@link Object} (e.g. {@code Bean}) owning the property. May be {@code null} but is
* required for advanced localization (if you want more specific labels in case the
* {@link WritableProperty#getName() property name} is not specific enough).
* @param receiver the {@link UiBindingReceiver}. May be {@code null}.
* @param bindValue {@code true} to bind the value of the {@link ReadableProperty} bidirectional with the
* {@link UiInput}.
* @return the {@link UiInput} widget for the given {@link ReadableProperty property}.
*/
public UiInput createInput(ReadableProperty property, Object source, UiBindingReceiver receiver,
boolean bindValue) {
UiInput input = UiWidgetFactoryProperty.get().create(property);
input.setId(createId(property, source));
bindProperty(property, input, source, bindValue);
if (receiver != null) {
receiver.add(property, input);
}
return input;
}
/**
* @param property the {@link ReadableProperty} to bind.
* @param input the {@link UiInput} to bind.
* @param source the optional {@link Object} (e.g. {@code Bean}) owning the property. May be {@code null} but is
* required for advanced localization (if you want more specific labels in case the
* {@link WritableProperty#getName() property name} is not specific enough).
* @param bindValue {@code true} to bind the value of the {@link ReadableProperty} bidirectional with the
* {@link UiInput}.
* @param type of the value.
*/
public void bindProperty(ReadableProperty property, UiInput input, Object source, boolean bindValue) {
Validator super V> validator = property.getMetadata().getValidator();
input.setValidator(validator);
String label = localizeLabel(property, source);
input.setName(label);
boolean readOnly = property.isReadOnly();
if (readOnly) {
input.setReadOnlyFixed(Boolean.TRUE);
} else {
if (bindValue) {
final WritableProperty writableProperty = (WritableProperty) property;
input.addListener((e) -> {
if (e.getType() == UiValueChangeEvent.TYPE) {
V value = input.getValue();
writableProperty.set(value);
}
});
}
}
if (bindValue) {
property.addWeakListener((e) -> {
if (!e.isChange()) {
V value = property.get();
input.setValue(value);
}
});
}
}
/**
* @param property the {@link ReadableProperty}.
* @param source the optional {@link Object} (e.g. {@code Bean}) owning the property. May be {@code null}.
* @return the widget ID.
*/
protected String createId(ReadableProperty> property, Object source) {
String propertyName = property.getName();
if (source == null) {
return propertyName;
}
return source.getClass().getSimpleName() + "_" + propertyName;
}
/**
* @param property the {@link ReadableProperty}.
* @param source the optional {@link Object} (e.g. {@code Bean}) owning the property. May be {@code null}.
* @return the localized label {@link String}.
*/
protected String localizeLabel(ReadableProperty> property, Object source) {
String name = property.getName();
String result = UiLocalizer.get().localizeOrNull(name, source);
if (result == null) {
result = name;
}
return result;
}
}