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.
pl.fhframework.model.forms.DictionaryCombo Maven / Gradle / Ivy
package pl.fhframework.model.forms;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import lombok.Setter;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import pl.fhframework.BindingResult;
import pl.fhframework.ReflectionUtils;
import pl.fhframework.annotations.CompilationTraversable;
import pl.fhframework.annotations.Control;
import pl.fhframework.annotations.DocumentedComponent;
import pl.fhframework.annotations.XMLProperty;
import pl.fhframework.binding.ActionBinding;
import pl.fhframework.core.FhCL;
import pl.fhframework.core.FhException;
import pl.fhframework.core.logging.FhLogger;
import pl.fhframework.model.dto.ElementChanges;
import pl.fhframework.model.dto.InMessageEventData;
import pl.fhframework.model.forms.provider.IComboDataProvider;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
@DocumentedComponent(documentationExample = true, value = "Enables users to quickly find and select from a pre-populated list of values as they type, leveraging searching and filtering.",
icon = "fa fa-outdent")
@Control(parents = {PanelGroup.class, Group.class, Column.class, Tab.class, Row.class, Form.class, Repeater.class}, invalidParents = {Table.class}, canBeDesigned = false)
public class DictionaryCombo extends Combo implements IGroupingComponent {
@Getter
@Setter
@XMLProperty
private String provider;
@JsonIgnore
private IComboDataProvider dataProvider;
@JsonIgnore
private List subcomponents = new LinkedList<>();
@JsonIgnore
private ComponentStateSaver componentStateSaver = new ComponentStateSaver();
@JsonIgnore
@Getter
private boolean processComponentChange = true;
@JsonIgnore
@Getter
@Setter
@CompilationTraversable
private List nonVisualSubcomponents = new ArrayList<>();
protected boolean multiselect = false;
@JsonIgnore
private Method getValues;
@JsonIgnore
private Method getValue;
@JsonIgnore
private List getValuesParamsList = new LinkedList<>();
@JsonIgnore
private List getValueParamsList = new LinkedList<>();
private boolean initializing = false;
private boolean filterEnabled = false;
public DictionaryCombo(Form form) {
super(form);
}
@Override
public void init() {
super.init();
try {
this.resolveDataProvider();
this.resolveMethods();
this.resolveParameters();
this.initializing = true;
} catch (Exception ex) {
FhLogger.warn("DictionaryCombo: Provider not found.", ex);
}
}
@JsonIgnore
public List getParameters() {
return subcomponents;
}
private void resolveDataProvider() throws ClassNotFoundException {
if (this.provider != null) {
Class extends IComboDataProvider> providerClass = (Class extends IComboDataProvider>) FhCL.classLoader.loadClass(String.format(this.provider));
this.dataProvider = pl.fhframework.helper.AutowireHelper.getBean(providerClass);
}
}
@Override
protected boolean processValuesBinding() {
return true;
}
protected boolean processValuesExternal(String text) {
List allParamsList = new LinkedList<>();
allParamsList.add(text);
allParamsList.addAll(this.getValuesFromDictionaryComboParameters(this.getValuesParamsList));
List values = (List) ReflectionUtils.run(this.getValues, this.dataProvider, allParamsList.toArray());
if (values != null) {
List collection = (List) values;
if (!CollectionUtils.isEmpty(collection)) {
this.modelType = collection.stream().findFirst().get().getClass();
}
this.values.put("", new LinkedList<>(collection));
return true;
}
return false;
}
protected void processFiltering(String text) {
if(!initializing && this.filterEnabled) {
filteredObjectValues.clear();
processValuesExternal(text);
Map> filtered = values.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, p -> p.getValue().stream().collect(Collectors.toList())));
filteredObjectValues.putAll(filtered);
filterInvoked = true;
}
}
private void resolveMethods() {
if (provider != null) {
this.getValues = ReflectionUtils.findMatchingPublicMethod(this.dataProvider.getClass(), "getValues").get();
List paramsList = new LinkedList<>();
Integer paramsCount = this.getValues.getParameterCount();
for (int idx = 0; idx < paramsCount; idx++) {
Optional p = ReflectionUtils.getMethodParamAnnotation(this.getValues, idx, pl.fhframework.core.uc.Parameter.class);
if (p.isPresent()) {
String paramName = p.get().name();
Optional optionalDictComboParam = subcomponents.stream().filter(e -> Objects.equals(e.getName(), paramName)).findFirst();
if (optionalDictComboParam.isPresent()) {
DictionaryComboParameter dictComboParam = optionalDictComboParam.get();
this.getValuesParamsList.add(dictComboParam);
} else {
throw new FhException("No attribute for " + DictionaryComboParameter.class.getSimpleName() + " : " + paramName);
}
}
}
this.getValue = ReflectionUtils.findMatchingPublicMethod(this.dataProvider.getClass(), "getValue").get();
Integer paramsCount2 = this.getValue.getParameterCount();
for (int idx = 0; idx < paramsCount2; idx++) {
Optional p = ReflectionUtils.getMethodParamAnnotation(this.getValue, idx, pl.fhframework.core.uc.Parameter.class);
if (p.isPresent()) {
String paramName = p.get().name();
Optional optionalDictComboParam = subcomponents.stream().filter(e -> Objects.equals(e.getName(), paramName)).findFirst();
if (optionalDictComboParam.isPresent()) {
DictionaryComboParameter dictComboParam = optionalDictComboParam.get();
this.getValueParamsList.add(dictComboParam);
BindingResult br = dictComboParam.getModelBinding().getBindingResult();
} else {
throw new FhException("No attribute for " + DictionaryComboParameter.class.getSimpleName() + " : " + paramName);
}
}
}
}
}
private void resolveParameters() {
if( this.getValuesParamsList.size() > 0){
this.getValuesParamsList.forEach(dictionaryComboParameter -> {
dictionaryComboParameter.resolveValue();
});
}
}
/**
* Function for geting actual values from DictionaryComboParameter based on its model bindings.
*
* @param dcp
* @return List
*/
List getValuesFromDictionaryComboParameters(List dcp) {
List l = new LinkedList<>();
dcp.forEach(dictionaryComboParameter -> {
BindingResult br = dictionaryComboParameter.getModelBinding().getBindingResult();
if (br != null) {
l.add(br.getValue());
} else {
throw new FhException("No attribute for " + DictionaryComboParameter.class.getSimpleName() + " : " + dictionaryComboParameter.getName());
}
});
return l;
}
/**
* Adds component to the container.
*/
@Override
public void addSubcomponent(DictionaryComboParameter component) {
subcomponents.add(component);
}
@Override
public void removeSubcomponent(DictionaryComboParameter removedFormElement) {
subcomponents.remove(removedFormElement);
}
@Override
public List getSubcomponents() {
return subcomponents;
}
protected String objectToString(Object s) {
if (s == null) return "";
if (s.getClass().equals(String.class)) {
return (String) s;
} else {
return this.dataProvider.getDisplayValue(s);
}
}
protected void changeSelectedItemBinding() {
if (getModelBinding() != null) {
if (selectedItem == null) {
getModelBinding().setValue(selectedItem);
} else {
getModelBinding().setValue(this.dataProvider.getCode(selectedItem));
}
}
}
protected MultiValueMap collectValues(MultiValueMap valuesToConvert) {
MultiValueMap filteredConvertedValues = new LinkedMultiValueMap<>();
AtomicReference idx = new AtomicReference<>(0L);
valuesToConvert.forEach((key, values) -> values.forEach(value -> {
ComboItemDTO item;
item = new ComboItemDTO(this.dataProvider.getCode(value), idx.get(), false, this.dataProvider.getDisplayValue(value));
idx.getAndSet(idx.get() + 1);
filteredConvertedValues.add(key, item);
}));
return filteredConvertedValues;
}
@Override
protected boolean processValueBinding(ElementChanges elementChanges) {
if (getModelBinding() != null) {
BindingResult selectedBindingResult = getModelBinding().getBindingResult();
if (selectedBindingResult != null) {
Object value = selectedBindingResult.getValue();
if (!this.dataProvider.areObjectsEquals(value, (selectedItem != null ? this.dataProvider.getCode(selectedItem) : null))) {
List allParamsList = new LinkedList<>();
allParamsList.add(value);
allParamsList.addAll(this.getValuesFromDictionaryComboParameters(this.getValueParamsList));
this.selectedItem = (Object) ReflectionUtils.run(this.getValue, this.dataProvider, allParamsList.toArray());
this.rawValue = toRawValue(this.selectedItem);
elementChanges.addChange(RAW_VALUE_ATTR, this.rawValue);
this.filterText = rawValue != null ? rawValue : "";
updateFilterTextBinding();
return true;
}
}
}
return false;
}
public ElementChanges comboParameterModelRefreash() {
final ElementChanges elementChanges = super.updateView();
this.processFiltering("");
this.processFilterBinding(elementChanges, true);
this.refreshView();
return elementChanges;
}
@Override
public ElementChanges updateView() {
final ElementChanges elementChanges = super.updateView();
boolean selectedBindingChanged = elementChanges.getChangedAttributes().containsKey(RAW_VALUE_ATTR);
if (freeTypingBinding != null) {
freeTyping = freeTypingBinding.resolveValueAndAddChanges(this, elementChanges, freeTyping, FREE_TYPING);
}
if (emptyValueBinding != null) {
emptyValue = emptyValueBinding.resolveValueAndAddChanges(this, elementChanges, emptyValue, EMPTY_VALUE_ATTR);
}
if (this.cleared) {
this.filterText = "";
updateFilterTextBinding();
processFiltering(this.filterText);
}
processFilterTextBinding(elementChanges);
setFilterFunction();
refreshAvailability(elementChanges);
boolean valuesChanged = (this.multiselect && languageChanged) || processValuesBinding();
if (selectedBindingChanged || valuesChanged ) {
processFiltering(this.filterText);
}
processFilterBinding(elementChanges, valuesChanged);
processLabelBinding(elementChanges);
processCursorBinding(this, elementChanges);
this.prepareComponentAfterValidation(elementChanges);
if (elementChanges.containsAnyChanges()) {
refreshView();
}
this.cleared = false;
this.languageChanged = false;
this.initializing = false;
this.filterEnabled = false;
return elementChanges;
}
@Override
public Optional getEventHandler(InMessageEventData eventData) {
//Only this component events allow to fire filtering.
this.filterEnabled = true;
return super.getEventHandler(eventData);
}
}