/*
* This is part of Geomajas, a GIS framework, http://www.geomajas.org/.
*
* Copyright 2008-2015 Geosparc nv, http://www.geosparc.com/, Belgium.
*
* The program is available in open source according to the GNU Affero
* General Public License. All contributions in this program are covered
* by the Geomajas Contributors License Agreement. For full licensing
* details, see LICENSE.txt in the project root.
*/
package org.geomajas.widget.searchandfilter.client.widget.attributesearch;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.fields.BlurbItem;
import com.smartgwt.client.widgets.form.fields.CanvasItem;
import com.smartgwt.client.widgets.form.fields.FormItem;
import com.smartgwt.client.widgets.form.fields.SelectItem;
import com.smartgwt.client.widgets.form.fields.events.ChangedEvent;
import com.smartgwt.client.widgets.form.fields.events.ChangedHandler;
import org.geomajas.configuration.AbstractAttributeInfo;
import org.geomajas.configuration.AbstractReadOnlyAttributeInfo;
import org.geomajas.gwt.client.i18n.I18nProvider;
import org.geomajas.gwt.client.map.layer.VectorLayer;
import org.geomajas.gwt.client.widget.attribute.AttributeFormFieldRegistry;
import org.geomajas.widget.searchandfilter.client.util.AttributeCriterionUtil;
import org.geomajas.widget.searchandfilter.search.dto.AttributeCriterion;
/**
* Adjusted from see {@link AttributeCriterionPane} to work with AttributeCriterion.
*
* @author Pieter De Graef
* @author Kristof Heirwegh
*/
public class AttributeCriterionPane extends Canvas {
private static final String CQL_WILDCARD = "*";
private static final String CQL_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZZZ";
private static final String ID_SUFFIX = ".@id";
private SelectItem attributeSelect;
private SelectItem operatorSelect;
private AttributeFormItem valueItem;
private VectorLayer layer;
private AbstractReadOnlyAttributeInfo selectedAttribute;
// -------------------------------------------------------------------------
// Constructors:
// -------------------------------------------------------------------------
/**
* Create a search criterion pane, for the given vector layer. The layer is required, as it's list of attribute
* definitions are a vital part of the search criteria.
*
* @param layer layer to create criterion for
*/
public AttributeCriterionPane(VectorLayer layer) {
super();
this.layer = layer;
buildUI();
}
// -------------------------------------------------------------------------
// Public methods:
// -------------------------------------------------------------------------
/**
* Validate the value that the user filled in. If it is not valid, don't ask for the SearchCriterion.
*
* @return true when user entered invalid value
*/
public boolean hasErrors() {
return valueItem.getForm().hasErrors();
}
public void setSearchCriterion(AttributeCriterion ac) {
if (ac != null) {
attributeSelect.setValue(getAttributeByName(ac.getAttributeName()).getLabel());
attributeChanged();
operatorSelect.setValue(AttributeCriterionUtil.getLabelFromOperatorCode(ac.getOperator()));
valueItem.setValue(trimLikeValue(ac.getValue(), ac.getOperator()));
}
}
private String trimLikeValue(String value, String operator) {
if ("like".equalsIgnoreCase(operator) && value != null) {
String tmp = value;
if (tmp.startsWith(CQL_WILDCARD)) {
tmp = tmp.substring(1, tmp.length());
}
if (tmp.endsWith(CQL_WILDCARD)) {
tmp = tmp.substring(0, tmp.length() - 1);
}
return tmp;
} else {
return value;
}
}
/**
* Return the actual search criterion object, or null if not all fields have been properly filled.
*
* @return search criterion
*/
public AttributeCriterion getSearchCriterion() {
Object operator = operatorSelect.getValue();
if (operator != null) {
return AttributeCriterionUtil.getSearchCriterion(layer.getServerLayerId(), selectedAttribute, valueItem,
org.geomajas.gwt.client.widget.attribute.AttributeCriterionPane.
getOperatorCodeFromLabel(operator.toString()));
}
return null;
}
// -------------------------------------------------------------------------
// Private methods:
// -------------------------------------------------------------------------
private void buildUI() {
// Attribute select:
attributeSelect = new SelectItem("attributeItem");
attributeSelect.setWidth(140);
attributeSelect.setShowTitle(false);
attributeSelect.setValueMap(org.geomajas.gwt.client.widget.attribute.AttributeCriterionPane.
getSearchableAttributes(layer));
attributeSelect.setHint(I18nProvider.getSearch().gridChooseAttribute());
attributeSelect.setShowHintInField(true);
attributeSelect.setValidateOnChange(true);
attributeSelect.setShowErrorStyle(true);
attributeSelect.setRequired(true);
// Operator select:
operatorSelect = new SelectItem("operatorItem");
operatorSelect.setDisabled(true);
operatorSelect.setWidth(140);
operatorSelect.setShowTitle(false);
operatorSelect.setValidateOnChange(true);
operatorSelect.setShowErrorStyle(true);
operatorSelect.setRequired(true);
// Value form item:
valueItem = new AttributeFormItem("valueItem");
valueItem.setShowTitle(false);
valueItem.setDisabled(true);
valueItem.setWidth(150);
// Mechanisms:
attributeSelect.addChangedHandler(new ChangedHandler() {
public void onChanged(ChangedEvent event) {
attributeChanged();
}
});
// Finalize:
DynamicForm form = new DynamicForm();
form.setNumCols(6);
form.setHeight(26);
form.setFields(attributeSelect, operatorSelect, valueItem);
addChild(form);
}
private void attributeChanged() {
selectedAttribute = getSelectedAttribute();
if (selectedAttribute != null) {
// Adjust operator value map and enabled:
operatorSelect.setDisabled(false);
String[] operators = org.geomajas.gwt.client.widget.attribute.AttributeCriterionPane.
getOperatorsForAttributeType(selectedAttribute);
operatorSelect.setValueMap(operators);
operatorSelect.setValue(operators[0]);
// Adjust value form item and enable:
valueItem.setAttributeInfo(selectedAttribute);
valueItem.setDisabled(false);
}
}
private AbstractReadOnlyAttributeInfo getSelectedAttribute() {
Object value = attributeSelect.getValue();
if (value != null) {
for (AbstractAttributeInfo attributeInfo : layer.getLayerInfo().getFeatureInfo().getAttributes()) {
if (attributeInfo instanceof AbstractReadOnlyAttributeInfo && value.equals(
((AbstractReadOnlyAttributeInfo) attributeInfo).getLabel())) {
return (AbstractReadOnlyAttributeInfo) attributeInfo;
}
}
}
return null;
}
private AbstractReadOnlyAttributeInfo getAttributeByName(String name) {
if (name != null) {
for (AbstractAttributeInfo attributeInfo : layer.getLayerInfo().getFeatureInfo().getAttributes()) {
if (attributeInfo instanceof AbstractReadOnlyAttributeInfo && attributeInfo.getName().equals(name)) {
return (AbstractReadOnlyAttributeInfo) attributeInfo;
}
}
}
return null;
}
/**
* <p>
* Editable form item implementation that can edit any kind of feature attribute. It starts by using a default
* <code>TextItem</code> as <code>FormItem</code> representative. Every time the <code>setAttributeInfo</code>
* method is called, a new internal <code>FormItem</code> will be created and shown in the place of the
* <code>TextItem</code>. In order to create the correct representation for each kind of attribute, a
* {@link AttributeFormFieldRegistry} is used.
* </p>
*
* @author Pieter De Graef
*/
private class AttributeFormItem extends CanvasItem {
private DynamicForm form;
private FormItem formItem;
// -------------------------------------------------------------------------
// Constructors:
// -------------------------------------------------------------------------
/**
* Create the form item with the given name. An internal form will already be created, and in that form a
* <code>TextItem</code> will be shown.
*
* @param name form item name
*/
public AttributeFormItem(String name) {
super(name);
form = new DynamicForm();
form.setHeight(26);
formItem = new BlurbItem();
formItem.setShowTitle(false);
formItem.setValue("...................");
form.setFields(formItem);
setCanvas(form);
}
// -------------------------------------------------------------------------
// Public methods:
// -------------------------------------------------------------------------
/**
* Set a new attribute information object. This will alter the internal form, to display a new
* <code>FormItem</code> for the new type of attribute. In order to accomplish this, a
* {@link AttributeFormFieldRegistry} is used.
*
* @param attributeInfo The new attribute definition for which to display the correct <code>FormItem</code>.
*/
public void setAttributeInfo(AbstractReadOnlyAttributeInfo attributeInfo) {
formItem = AttributeFormFieldRegistry.createFormItem(attributeInfo, layer);
if (formItem != null) {
formItem.setDisabled(false);
formItem.setShowTitle(false);
form.setFields(formItem);
form.setDisabled(false);
form.setCanFocus(true);
}
}
/**
* Set a new width on this instance. Delegates to the internal form.
*
* @param width width
*/
public void setWidth(int width) {
form.setWidth(width);
if (formItem != null) {
formItem.setWidth(width);
}
}
/**
* Get the current value form the internal <code>FormItem</code>.
*
* @return value
*/
public Object getValue() {
if (formItem != null) {
return formItem.getValue();
}
return null;
}
/** Get the current value form the internal <code>FormItem</code>. */
public void setValue(String value) {
if (formItem != null) {
formItem.setValue(value);
}
}
/**
* Get the display value form the internal <code>FormItem</code>.
*
* @return value
*/
public String getDisplayValue() {
if (formItem != null) {
return formItem.getDisplayValue();
}
return null;
}
/**
* Return the form for the inner FormItem. On the returned form, validation will work.
*
* @return form
*/
public DynamicForm getForm() {
return form;
}
}
}