/** * *************************************************************************** * Copyright (c) 2010 Qcadoo Limited * Project: Qcadoo Framework * Version: 1.4 * * This file is part of Qcadoo. * * Qcadoo is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation; either version 3 of the License, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *************************************************************************** */ package com.qcadoo.view.internal.components.lookup; import java.util.LinkedList; import java.util.List; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.springframework.util.StringUtils; import com.qcadoo.model.api.Entity; import com.qcadoo.model.api.FieldDefinition; import com.qcadoo.model.api.expression.ExpressionUtils; import com.qcadoo.model.api.search.SearchCriteriaBuilder; import com.qcadoo.model.api.search.SearchOrders; import com.qcadoo.model.api.search.SearchRestrictions; import com.qcadoo.model.api.search.SearchRestrictions.SearchMatchMode; import com.qcadoo.model.api.search.SearchResult; import com.qcadoo.model.api.types.BelongsToType; import com.qcadoo.view.api.components.LookupComponent; import com.qcadoo.view.api.components.lookup.FilterValueHolder; import com.qcadoo.view.internal.CriteriaModifier; import com.qcadoo.view.internal.FilterValueHolderImpl; import com.qcadoo.view.internal.components.FieldComponentState; public final class LookupComponentState extends FieldComponentState implements LookupComponent { public static final String JSON_REQUIRED = "required"; public static final String JSON_OLD_SELECTED_ENTITY_ID = "oldValue"; public static final String JSON_TEXT = "selectedEntityValue"; public static final String JSON_CODE = "selectedEntityCode"; public static final String JSON_ACTIVE = "selectedEntityActive"; public static final String JSON_CURRENT_CODE = "currentCode"; public static final String JSON_CLEAR_CURRENT_CODE = "clearCurrentCodeCode"; public static final String JSON_BELONGS_TO_ENTITY_ID = "contextEntityId"; public static final String JSON_AUTOCOMPLETE_MATCHES = "autocompleteMatches"; public static final String JSON_AUTOCOMPLETE_CODE = "autocompleteCode"; public static final String JSON_AUTOCOMPLETE_ENTITIES_NUMBER = "autocompleteEntitiesNumber"; public static final String JSON_CRITERIA_MODIFIER_PARAMETER = "criteriaModifierParameter"; private static final String CRITERIA_MODIFIER_NOT_PRESENT = "There is no critieria modifier. Filter value is not present."; private final LookupEventPerformer eventPerformer = new LookupEventPerformer(); private final FieldDefinition belongsToFieldDefinition; private Long belongsToEntityId; private Long oldSelectedEntityId; private String currentCode; private boolean clearCurrentCodeCode = false; private boolean selectedEntityActive = true; private boolean onlyActive = false; private String selectedEntityCode; private String selectedEntityValue; private final String fieldCode; private final String expression; private String autocompleteCode; private List<Entity> autocompleteMatches; private int autocompleteEntitiesNumber; private final CriteriaModifier criteriaModifier; private final FilterValueHolder criteriaModifierParameter; public LookupComponentState(final FieldDefinition scopeField, final String fieldCode, final String expression, final LookupComponentPattern pattern) { super(pattern); this.belongsToFieldDefinition = scopeField; this.fieldCode = fieldCode; this.expression = expression; this.criteriaModifier = pattern.getCriteriaModifier(); this.criteriaModifierParameter = this.criteriaModifier != null ? new FilterValueHolderImpl() : null; this.onlyActive = pattern.isOnlyActive(); registerEvent("initialize", eventPerformer, "initialize"); registerEvent("autompleteSearch", eventPerformer, "autompleteSearch"); registerEvent("onSelectedEntityChange", eventPerformer, "onSelectedEntityChange"); } @Override protected void initializeContent(final JSONObject json) throws JSONException { super.initializeContent(json); if (json.has(JSON_TEXT) && !json.isNull(JSON_TEXT)) { selectedEntityValue = json.getString(JSON_TEXT); } if (json.has(JSON_CODE) && !json.isNull(JSON_CODE)) { selectedEntityCode = json.getString(JSON_CODE); } if (json.has(JSON_BELONGS_TO_ENTITY_ID) && !json.isNull(JSON_BELONGS_TO_ENTITY_ID)) { belongsToEntityId = json.getLong(JSON_BELONGS_TO_ENTITY_ID); } if (json.has(JSON_OLD_SELECTED_ENTITY_ID) && !json.isNull(JSON_OLD_SELECTED_ENTITY_ID)) { oldSelectedEntityId = json.getLong(JSON_OLD_SELECTED_ENTITY_ID); } if (json.has(JSON_CURRENT_CODE) && !json.isNull(JSON_CURRENT_CODE)) { currentCode = json.getString(JSON_CURRENT_CODE); } if (json.has(JSON_AUTOCOMPLETE_CODE) && !json.isNull(JSON_AUTOCOMPLETE_CODE)) { autocompleteCode = json.getString(JSON_AUTOCOMPLETE_CODE); } if (json.has(JSON_CRITERIA_MODIFIER_PARAMETER) && !json.isNull(JSON_CRITERIA_MODIFIER_PARAMETER)) { criteriaModifierParameter.initialize(json.getJSONObject(JSON_CRITERIA_MODIFIER_PARAMETER)); } if (belongsToFieldDefinition != null && belongsToEntityId == null) { setEnabled(false); } } @Override protected JSONObject renderContent() throws JSONException { JSONObject json = super.renderContent(); json.put(JSON_TEXT, selectedEntityValue); json.put(JSON_CODE, selectedEntityCode); json.put(JSON_ACTIVE, selectedEntityActive); json.put(JSON_BELONGS_TO_ENTITY_ID, belongsToEntityId); if (clearCurrentCodeCode) { json.put(JSON_CLEAR_CURRENT_CODE, clearCurrentCodeCode); } if (autocompleteMatches != null) { JSONArray matches = new JSONArray(); for (Entity entity : autocompleteMatches) { JSONObject matchEntity = new JSONObject(); matchEntity.put("id", entity.getId()); matchEntity.put("value", ExpressionUtils.getValue(entity, expression, getLocale())); matchEntity.put("code", String.valueOf(entity.getField(fieldCode))); matchEntity.put("active", entity.isActive()); matches.put(matchEntity); } json.put(JSON_AUTOCOMPLETE_MATCHES, matches); json.put(JSON_AUTOCOMPLETE_CODE, autocompleteCode); json.put(JSON_AUTOCOMPLETE_ENTITIES_NUMBER, autocompleteEntitiesNumber); } if (criteriaModifierParameter != null && !criteriaModifierParameter.isEmpty()) { json.put(JSON_CRITERIA_MODIFIER_PARAMETER, criteriaModifierParameter.toJSON()); } return json; } @Override public Long getFieldValue() { return getFieldValueWithoutSearching(); } @Override public boolean isEmpty() { return org.apache.commons.lang3.StringUtils.isEmpty(autocompleteCode) && !hasSelectedEntity(); } private boolean hasSelectedEntity() { return getFieldValue() != null; } public Long getFieldValueWithoutSearching() { return convertToLong(super.getFieldValue()); } @Override public void setFieldValue(final Object value) { setFieldValueWithoutRefreshing(convertToLong(value)); if (!this.isHasError()) { clearCurrentCodeCode = true; } eventPerformer.refresh(); } private void setFieldValueWithoutRefreshing(final Long value) { super.setFieldValue(value); notifyEntityIdChangeListeners(convertToLong(value)); } private Long convertToLong(final Object value) { if (value == null) { return null; } else if (value instanceof Long) { return (Long) value; } else if (StringUtils.hasText(value.toString()) && !"null".equals(value.toString())) { return Long.parseLong(value.toString()); } else { return null; } } @Override public void onScopeEntityIdChange(final Long scopeEntityId) { if (belongsToFieldDefinition == null) { throw new IllegalStateException("Lookup doesn't have scopeField, it cannot set scopeEntityId"); } belongsToEntityId = scopeEntityId; setEnabled(scopeEntityId != null); requestRender(); } @Override public Entity getEntity() { Long entityId = getFieldValueWithoutSearching(); if (entityId == null) { return null; } return getDataDefinition().get(entityId); } protected class LookupEventPerformer { public void initialize(final String[] args) { refresh(); requestRender(); } public void autompleteSearch(final String[] args) { if ((belongsToFieldDefinition == null || belongsToEntityId != null)) { SearchCriteriaBuilder searchCriteriaBuilder = getDataDefinition().find(); if(StringUtils.hasText(currentCode)){ searchCriteriaBuilder.add(SearchRestrictions.ilike(fieldCode, currentCode, SearchMatchMode.ANYWHERE)); } if (belongsToFieldDefinition != null && belongsToEntityId != null && belongsToFieldDefinition.getType() instanceof BelongsToType) { BelongsToType type = (BelongsToType) belongsToFieldDefinition.getType(); searchCriteriaBuilder.add(SearchRestrictions.belongsTo(belongsToFieldDefinition.getName(), type .getDataDefinition().get(belongsToEntityId))); } if (getDataDefinition().isActivable() && onlyActive) { if (oldSelectedEntityId == null) { searchCriteriaBuilder.add(SearchRestrictions.eq("active", true)); } else { searchCriteriaBuilder.add(SearchRestrictions.or(SearchRestrictions.eq("active", true), SearchRestrictions.idEq(oldSelectedEntityId))); } } searchCriteriaBuilder.addOrder(SearchOrders.asc(fieldCode)); if (criteriaModifier != null) { criteriaModifier.modifyCriteria(searchCriteriaBuilder, criteriaModifierParameter); } searchCriteriaBuilder.setMaxResults(25); SearchResult results = searchCriteriaBuilder.list(); autocompleteEntitiesNumber = results.getTotalNumberOfEntities(); if (results.getTotalNumberOfEntities() > 25) { autocompleteMatches = new LinkedList<>(); } else { autocompleteMatches = results.getEntities(); } } else { autocompleteMatches = new LinkedList<>(); } if(!StringUtils.hasText(currentCode)){ setFieldValue(""); } autocompleteCode = currentCode; requestRender(); } public void onSelectedEntityChange(final String[] args) { notifyEntityIdChangeListeners(getFieldValue()); } private void refresh() { Long entityId = getFieldValueWithoutSearching(); if (entityId == null) { selectedEntityCode = ""; selectedEntityValue = ""; selectedEntityActive = true; return; } Entity entity = getDataDefinition().get(entityId); if (entity == null) { setFieldValueWithoutRefreshing(null); selectedEntityCode = ""; selectedEntityValue = ""; selectedEntityActive = true; } else { selectedEntityCode = String.valueOf(entity.getField(fieldCode)); selectedEntityValue = ExpressionUtils.getValue(entity, expression, getLocale()); selectedEntityActive = entity.isActive(); } } } @Override public FilterValueHolder getFilterValue() { if (criteriaModifier == null) { throw new IllegalStateException(CRITERIA_MODIFIER_NOT_PRESENT); } FilterValueHolder holder = new FilterValueHolderImpl(criteriaModifierParameter); return holder; } @Override public void setFilterValue(FilterValueHolder value) { if (criteriaModifier == null) { throw new IllegalStateException(CRITERIA_MODIFIER_NOT_PRESENT); } criteriaModifierParameter.initialize(value.toJSON()); requestRender(); } }