/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.kie.workbench.common.forms.processing.engine.handling.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.inject.Inject;
import com.google.gwt.user.client.ui.IsWidget;
import org.jboss.errai.common.client.api.Assert;
import org.jboss.errai.databinding.client.PropertyChangeUnsubscribeHandle;
import org.jboss.errai.databinding.client.api.Converter;
import org.jboss.errai.databinding.client.api.DataBinder;
import org.jboss.errai.databinding.client.api.handler.property.PropertyChangeHandler;
import org.kie.workbench.common.forms.processing.engine.handling.FieldChangeHandler;
import org.kie.workbench.common.forms.processing.engine.handling.FieldChangeHandlerManager;
import org.kie.workbench.common.forms.processing.engine.handling.FormField;
import org.kie.workbench.common.forms.processing.engine.handling.FormFieldProvider;
import org.kie.workbench.common.forms.processing.engine.handling.FormHandler;
import org.kie.workbench.common.forms.processing.engine.handling.FormValidator;
import org.kie.workbench.common.forms.processing.engine.handling.IsNestedModel;
public class FormHandlerImpl<T> implements FormHandler<T>,
FormFieldProvider {
protected FormValidator validator;
protected FieldChangeHandlerManager fieldChangeManager;
protected FormHandlerHelper<T> handlerHelper;
protected DataBinder<T> binder;
protected List<FormField> formFields = new ArrayList<>();
protected List<PropertyChangeUnsubscribeHandle> unsubscribeHandlers = new ArrayList<>();
@Inject
public FormHandlerImpl(FormValidator validator,
FieldChangeHandlerManager fieldChangeManager) {
this.validator = validator;
this.fieldChangeManager = fieldChangeManager;
this.validator.setFormFieldProvider(this);
fieldChangeManager.setValidator(validator);
}
@Override
public void setUp(DataBinder<T> binder) {
setUp(binder,
false);
}
@Override
public void setUp(DataBinder<T> binder,
boolean bindInputs) {
Assert.notNull("DataBinder cannot be null",
binder);
clear();
this.binder = binder;
this.handlerHelper = new BoundBinderHelper<>(binder,
bindInputs);
}
@Override
public void setUp(T model) {
Assert.notNull("Model cannot be null",
model);
clear();
this.binder = getBinderForModel(model);
this.handlerHelper = new NewBinderHelper<>(model);
}
protected DataBinder<T> getBinderForModel(T model) {
return DataBinder.forModel(model);
}
@Override
public void registerInput(FormField formField) {
registerInput(formField,
null);
}
@Override
public void registerInput(FormField formField,
Converter valueConverter) {
Assert.notNull("FormHandler isn't correctly initialized, please run any of the setUp methods before use",
binder);
Assert.notNull("FormField cannot be null!",
formField);
String fieldName = formField.getFieldName();
IsWidget widget = formField.getWidget();
formFields.add(formField);
if (handlerHelper.supportsInputBinding() && formField.isBindable()) {
if (valueConverter == null) {
binder.bind(widget,
formField.getFieldBinding());
} else {
binder.bind(widget,
formField.getFieldBinding(),
valueConverter);
}
}
fieldChangeManager.registerField(formField.getFieldName(),
formField.isValidateOnChange());
/**
* if field isn't bindable we cannot listen to field value changes.
*/
if (!formField.isBindable()) {
return;
}
if (widget instanceof IsNestedModel) {
IsNestedModel nestedModelWidget = (IsNestedModel) widget;
nestedModelWidget.addFieldChangeHandler((childFieldName, newValue) -> fieldChangeManager.processFieldChange(
fieldName + "." + childFieldName,
newValue,
getModel()));
} else {
PropertyChangeUnsubscribeHandle unsubscribeHandle = binder.addPropertyChangeHandler(
formField.getFieldBinding(),
(PropertyChangeHandler) event -> fieldChangeManager.processFieldChange(fieldName,
event.getNewValue(),
binder.getModel()));
unsubscribeHandlers.add(unsubscribeHandle);
}
}
public void addFieldChangeHandler(FieldChangeHandler handler) {
addFieldChangeHandler(null,
handler);
}
public void addFieldChangeHandler(String fieldName,
FieldChangeHandler handler) {
Assert.notNull("FieldChangeHandler cannot be null",
handler);
if (fieldName != null) {
fieldChangeManager.addFieldChangeHandler(fieldName,
handler);
} else {
fieldChangeManager.addFieldChangeHandler(handler);
}
}
@Override
public boolean validate() {
return validator.validate(getModel());
}
@Override
public boolean validate(String propertyName) {
return validator.validate(propertyName,
getModel());
}
@Override
public void setReadOnly(boolean readOnly) {
formFields.forEach(field -> field.setReadOnly(readOnly));
}
@Override
public void clear() {
// Check if it's initialized before clear.
if (handlerHelper == null || binder == null) {
return;
}
for (PropertyChangeUnsubscribeHandle handle : unsubscribeHandlers) {
handle.unsubscribe();
}
unsubscribeHandlers.clear();
formFields.clear();
fieldChangeManager.clear();
if (handlerHelper.supportsInputBinding()) {
binder.unbind();
}
}
public T getModel() {
return handlerHelper.getModel();
}
@Override
public FormField findFormField(String fieldName) {
for (FormField field : formFields) {
if (field.getFieldName().equals(fieldName) || fieldName.equals(field.getFieldBinding())) {
return field;
}
}
return null;
}
@Override
public Collection<FormField> getAll() {
return formFields;
}
private interface FormHandlerHelper<T> {
boolean supportsInputBinding();
T getModel();
}
protected class BoundBinderHelper<T> implements FormHandlerHelper {
private boolean bindInputs;
private DataBinder<T> dataBinder;
public BoundBinderHelper(DataBinder<T> dataBinder,
boolean bindInputs) {
this.dataBinder = dataBinder;
this.bindInputs = bindInputs;
}
@Override
public boolean supportsInputBinding() {
return bindInputs;
}
@Override
public T getModel() {
return dataBinder.getModel();
}
}
protected class NewBinderHelper<T> implements FormHandlerHelper {
private T model;
public NewBinderHelper(T model) {
this.model = model;
}
@Override
public boolean supportsInputBinding() {
return true;
}
@Override
public T getModel() {
return model;
}
}
}