Package org.geomajas.widget.searchandfilter.client.widget.attributesearch

Source Code of org.geomajas.widget.searchandfilter.client.widget.attributesearch.AttributeSearchPanel$FeatureSearch

/*
* This is part of Geomajas, a GIS framework, http://www.geomajas.org/.
*
* Copyright 2008-2011 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 java.util.ArrayList;
import java.util.List;

import org.geomajas.gwt.client.i18n.I18nProvider;
import org.geomajas.gwt.client.map.MapModel;
import org.geomajas.gwt.client.map.event.LayerDeselectedEvent;
import org.geomajas.gwt.client.map.event.LayerSelectedEvent;
import org.geomajas.gwt.client.map.event.LayerSelectionHandler;
import org.geomajas.gwt.client.map.event.MapModelEvent;
import org.geomajas.gwt.client.map.event.MapModelHandler;
import org.geomajas.gwt.client.map.layer.Layer;
import org.geomajas.gwt.client.map.layer.VectorLayer;
import org.geomajas.gwt.client.widget.FeatureSearch.LogicalOperator;
import org.geomajas.gwt.client.widget.MapWidget;
import org.geomajas.widget.searchandfilter.client.SearchAndFilterMessages;
import org.geomajas.widget.searchandfilter.client.widget.search.AbstractSearchPanel;
import org.geomajas.widget.searchandfilter.search.dto.AndCriterion;
import org.geomajas.widget.searchandfilter.search.dto.AttributeCriterion;
import org.geomajas.widget.searchandfilter.search.dto.Criterion;
import org.geomajas.widget.searchandfilter.search.dto.OrCriterion;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.shared.HandlerRegistration;
import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.types.VerticalAlignment;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.HTMLPane;
import com.smartgwt.client.widgets.IButton;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.fields.BlurbItem;
import com.smartgwt.client.widgets.form.fields.FormItem;
import com.smartgwt.client.widgets.form.fields.RadioGroupItem;
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 com.smartgwt.client.widgets.layout.HLayout;
import com.smartgwt.client.widgets.layout.LayoutSpacer;
import com.smartgwt.client.widgets.layout.VLayout;
import com.smartgwt.client.widgets.layout.VStack;

/**
* Search panel using (non geometry) attributes.
*
* @see {@link org.geomajas.widget.searchandfilter.client.widget.search.SearchWidgetRegistry}.
* @author Kristof Heirwegh
*/
public class AttributeSearchPanel extends AbstractSearchPanel {

  private static final SearchAndFilterMessages MESSAGES = GWT.create(SearchAndFilterMessages.class);

  private static final String STYLE_SEARCH_ROW = "searchRow";
  private static final String STYLE_SEARCH_HEADER = "searchHeader";
  private static final String STYLE_HEADER_BAR = "headerBar";

  private FeatureSearch featureSearch;

  public AttributeSearchPanel(final MapWidget mapWidget) {
    super(mapWidget);
    featureSearch = new FeatureSearch(mapWidget.getMapModel(), true);
    featureSearch.setWidth100();
    featureSearch.setHeight100();
    setWidth(550);
    setHeight(350);
    addChild(featureSearch);
  }

  /** {@inheritDoc} */
  @Override
  public boolean validate() {
    Criterion cr = featureSearch.getSearchCriteria();
    return (cr != null && cr.isValid());
  }

  /** {@inheritDoc} */
  @Override
  public Criterion getFeatureSearchCriterion() {
    return featureSearch.getSearchCriteria();
  }

  /** {@inheritDoc} */
  @Override
  public VectorLayer getFeatureSearchVectorLayer() {
    return featureSearch.getLayer();
  }

  /** {@inheritDoc} */
  @Override
  public void reset() {
    featureSearch.empty();
  }

  /** {@inheritDoc} */
  @Override
  public void initialize(Criterion criterion) {
    featureSearch.setSearchCriteria(criterion);
  }

  public static boolean canHandle(Criterion criterion) {
    if (criterion == null) {
      return false;
    }
    List<Criterion> critters;
    if (criterion instanceof OrCriterion) {
      critters = ((OrCriterion) criterion).getCriteria();
    } else if (criterion instanceof AndCriterion) {
      critters = ((AndCriterion) criterion).getCriteria();
    } else {
      return false;
    }

    for (Criterion critter : critters) {
      if (!(critter instanceof AttributeCriterion)) {
        return false;
      }
    }
    return true;
  }

  // ----------------------------------------------------------

  /**
   * Adapted from @see {@link FeatureSearch} by @author Pieter De Graef.
   */
  public class FeatureSearch extends Canvas {

    // The vector layer to search in.
    private VectorLayer layer;
    // A form item that shows the user what layer he's searching in.
    private FormItem layerSelect;
    // Logical operator; match one or match all criteria?
    private RadioGroupItem logicalOperatorRadio;

    private VStack criterionStack;

    private VStack buttonStack;

    private MapModel mapModel;

    private List<AttributeCriterionPane> criterionPanes;

    private List<HLayout> buttonPanes;

    private List<HandlerRegistration> addHandlers;

    private List<HandlerRegistration> removeHandlers;

    private boolean manualLayerSelection;

    // -------------------------------------------------------------------------
    // Constructors:
    // -------------------------------------------------------------------------

    /**
     * Create a search widget for searching in a specific map model. This
     * widget will automatically react to the selection of layers within
     * that map model, and redraw to compensate for the selected layer. In
     * other words, searching always happens on the selected layer.
     *
     * @param mapModel
     *            The MapModel containing the possible layer to search in.
     * @param manualLayerSelection
     *            If true, a select box will be shown so the user can select
     *            what layer to search in. The possible list of layers
     *            consists of all the vector layers that are present in the
     *            given MapModel. If false, this widget will react to the
     *            layer select events that come from the MapMdodel. In that
     *            case searching happens in the selected layer (if it's a
     *            vector layer).<br/>
     *            This value cannot be altered anymore.
     */
    public FeatureSearch(MapModel mapModel, boolean manualLayerSelection) {
      super();
      this.mapModel = mapModel;
      this.manualLayerSelection = manualLayerSelection;
      criterionPanes = new ArrayList<AttributeCriterionPane>();
      buttonPanes = new ArrayList<HLayout>();
      addHandlers = new ArrayList<HandlerRegistration>();
      removeHandlers = new ArrayList<HandlerRegistration>();
      buildUI();
      setLogicalOperator(LogicalOperator.AND);
    }

    // -------------------------------------------------------------------------
    // Public methods:
    // -------------------------------------------------------------------------

    /**
     * Add a new empty row in the search grid, at the given position. An
     * single row can be used to create a single criterion.
     *
     * @param index
     *            Row number in the search grid, that indicates where to
     *            add/insert a new empty row.
     */
    public void addEmptyRow(final int index) {
      addEmptyRow(index, null);
    }

    public void addEmptyRow(final int index, AttributeCriterion ac) {
      if (null == layer) {
        return;
      }

      // Empty row:
      AttributeCriterionPane newRow = new AttributeCriterionPane(layer);
      newRow.setHeight(32);
      newRow.setStyleName(STYLE_SEARCH_ROW);

      HLayout btnLayout = new HLayout();
      btnLayout.setHeight(32);
      btnLayout.setMembersMargin(5);
      btnLayout.setAlign(Alignment.CENTER);
      btnLayout.setPadding(4);
      btnLayout.setStyleName(STYLE_SEARCH_ROW);

      IButton btnAddRow = new IButton();
      btnAddRow.setWidth(26);
      btnAddRow.setIcon("[ISOMORPHIC]/geomajas/silk/add.png");
      HandlerRegistration addReg = btnAddRow.addClickHandler(new ClickHandler() {

        public void onClick(ClickEvent event) {
          IButton btnAddRow2 = (IButton) event.getSource();
          for (int i = 0; i < buttonPanes.size(); i++) {
            IButton button = (IButton) buttonPanes.get(i).getMember(0);
            if (btnAddRow2.equals(button)) {
              addEmptyRow(i + 1);
              break;
            }
          }
          buttonPanes.get(0).getMember(1).setDisabled(false);
        }
      });

      IButton btnRemoveRow = new IButton();
      btnRemoveRow.setWidth(26);
      btnRemoveRow.setIcon("[ISOMORPHIC]/geomajas/silk/remove.png");
      HandlerRegistration removeReg = btnRemoveRow.addClickHandler(new ClickHandler() {
        public void onClick(ClickEvent event) {
          IButton sourceBtn = (IButton) event.getSource();
          for (int i = 0; i < buttonPanes.size(); i++) {
            IButton button = (IButton) buttonPanes.get(i).getMember(1);
            if (sourceBtn.equals(button)) {
              criterionStack.removeMember(criterionPanes.remove(i));

              // Remove row 0 from add button/registration:
              buttonStack.removeMember(buttonPanes.remove(i));
              addHandlers.remove(i).removeHandler();
              removeHandlers.remove(i).removeHandler();
              break;
            }
          }
          if (buttonPanes.size() == 1) {
            buttonPanes.get(0).getMember(1).setDisabled(true);
          }
        }
      });
      if (index == 0) {
        btnRemoveRow.setDisabled(true);
      }

      btnLayout.addMember(btnAddRow);
      btnLayout.addMember(btnRemoveRow);

      // Add to the stacks:
      criterionStack.addMember(newRow, index + 1);
      buttonStack.addMember(btnLayout, index + 1);

      // Add to the lists:
      criterionPanes.add(index, newRow);
      buttonPanes.add(index, btnLayout);
      addHandlers.add(index, addReg);
      removeHandlers.add(index, removeReg);

      if (ac != null) {
        newRow.setSearchCriterion(ac);
      }
    }

    public void setSearchCriteria(Criterion criterion) {
      if (criterion != null) {
        List<Criterion> criteria;
        VectorLayer vl = null;
        if (criterion instanceof AndCriterion) {
          criteria = ((AndCriterion) criterion).getCriteria();
          setLogicalOperator(LogicalOperator.AND);
        } else if (criterion instanceof OrCriterion) {
          criteria = ((OrCriterion) criterion).getCriteria();
          setLogicalOperator(LogicalOperator.OR);
        } else {
          SC.warn(MESSAGES.attributeSearchWidgetNoValidCriterionUnsupportedType());
          return;
        }

        for (int i = 0; i < criteria.size(); i++) {
          AttributeCriterion ac = (AttributeCriterion) criteria.get(i);
          if (vl == null) {
            List<VectorLayer> layers = mapModel.getVectorLayersByServerId(ac.getServerLayerId());
            if (layers == null || layers.size() < 1) {
              SC.warn(MESSAGES.attributeSearchWidgetNoValidCriterionNoLayer());
              return;
            }
            vl = layers.get(0);
            setLayer(vl);
            empty(false);
          }
          addEmptyRow(i, ac);
        }
        if (criteria.size() > 1) {
          buttonPanes.get(0).getMember(1).setDisabled(false);
        }
      }
    }

    /**
     * Get the full list of search criteria from the criterion grid.
     *
     * @return entered search criteria
     */
    public Criterion getSearchCriteria() {
      if (layer != null) {
        List<Criterion> criteria;
        Criterion criterion;
        String value = (String) logicalOperatorRadio.getValue();
        if (value.equals(I18nProvider.getSearch().radioOperatorAnd())) {
          criterion = new AndCriterion();
          criteria = ((AndCriterion) criterion).getCriteria();
        } else {
          criterion = new OrCriterion();
          criteria = ((OrCriterion) criterion).getCriteria();
        }

        for (AttributeCriterionPane criterionPane : criterionPanes) {
          if (criterionPane.hasErrors()) {
            SC.warn(I18nProvider.getSearch().warningInvalidCriteria());
            return null;
          }
          AttributeCriterion ac = criterionPane.getSearchCriterion();
          if (ac != null) {
            criteria.add(ac);
          }
        }
        if (criteria == null || criteria.size() == 0) {
          SC.warn(MESSAGES.attributeSearchWidgetNoValidCriterionNoCriteria());
          return null;
        }
        return criterion;
      } else {
        SC.warn(MESSAGES.attributeSearchWidgetNoLayerSelected());
        return null;
      }
    }

    public void empty() {
      empty(true);
    }

    /**
     * Empty the grid, thereby removing all rows. When that is done, a new
     * empty row will be displayed.
     *
     * @param shouldAddEmptyRow should an empty row be added?
     */
    public void empty(boolean shouldAddEmptyRow) {
      for (AttributeCriterionPane criterionPane : criterionPanes) {
        criterionStack.removeMember(criterionPane);
      }
      criterionPanes.clear();
      for (HLayout criterionPane : buttonPanes) {
        buttonStack.removeMember(criterionPane);
      }
      buttonPanes.clear();
      /*
      for (HandlerRegistration handlerRegistration : addHandlers) {
        handlerRegistration.removeHandler();
      }
      addHandlers.clear();
      for (HandlerRegistration handlerRegistration : removeHandlers) {
        handlerRegistration.removeHandler();
      }
      removeHandlers.clear();
      */
      if (shouldAddEmptyRow) {
        addEmptyRow(0);
      }
    }

    // -------------------------------------------------------------------------
    // Getters and setters:
    // -------------------------------------------------------------------------

    /**
     * Set a new value for the logical operator. This operator determines
     * whether all the criteria have to be met in the search, or just one of
     * them.
     *
     * @param operator operator
     */
    public void setLogicalOperator(LogicalOperator operator) {
      switch (operator) {
      case AND:
        logicalOperatorRadio.setValue(I18nProvider.getSearch().radioOperatorAnd());
        break;
      case OR:
        logicalOperatorRadio.setValue(I18nProvider.getSearch().radioOperatorOr());
      }
    }

    /**
     * Return the current value for the logical operator.This operator
     * determines whether all the criteria have to be met in the search, or
     * just one of them.
     *
     * @return logical operator
     */
    public LogicalOperator getLogicalOperator() {
      String value = (String) logicalOperatorRadio.getValue();
      if (value.equals(I18nProvider.getSearch().radioOperatorAnd())) {
        return LogicalOperator.AND;
      }
      return LogicalOperator.OR;
    }

    /**
     * Return the layer onto which searching should happen. (the MapModel's
     * selected layer)
     *
     * @return layer to search
     */
    public VectorLayer getLayer() {
      return layer;
    }

    /**
     * Set a new layer onto which searching should happen.
     *
     * @param layer layer
     */
    public void setLayer(VectorLayer layer) {
      this.layer = layer;
      Object value = layerSelect.getValue();
      if (value == null || !value.equals(layer.getLabel())) {
        layerSelect.setValue(layer.getLabel());
      }
      empty();
    }

    // -------------------------------------------------------------------------
    // Private methods:
    // -------------------------------------------------------------------------

    private void updateLayerList() {
      List<String> layers = new ArrayList<String>();
      for (Layer<?> vLayer : mapModel.getLayers()) {
        if (vLayer instanceof VectorLayer) {
          layers.add(vLayer.getLabel());
        }
      }
      layerSelect.setValueMap(layers.toArray(new String[layers.size()]));
    }

    private void buildUI() {
      // Create the layout:
      VLayout layout = new VLayout();
      layout.setWidth100();
      layout.setHeight100();

      logicalOperatorRadio = new RadioGroupItem("logicalOperator");
      logicalOperatorRadio.setValueMap(I18nProvider.getSearch().radioOperatorOr(), I18nProvider.getSearch()
          .radioOperatorAnd());
      logicalOperatorRadio.setVertical(false);
      logicalOperatorRadio.setRequired(true);
      logicalOperatorRadio.setAlign(Alignment.LEFT);
      logicalOperatorRadio.setWidth(250);
      logicalOperatorRadio.setShowTitle(false);

      HLayout optionLayout = new HLayout();
      optionLayout.setHeight(50);
      optionLayout.setWidth100();

      VLayout leftLayout = new VLayout();
      leftLayout.setAlign(Alignment.LEFT);

      HLayout layerLayout = new HLayout();
      layerLayout.setWidth(420);
      DynamicForm layerForm = new DynamicForm();
      layerForm.setHeight(30);
      if (manualLayerSelection) {
        layerSelect = new SelectItem();
        layerSelect.setTitle(I18nProvider.getSearch().labelLayerSelected());
        layerSelect.setWidth(250);
        layerSelect.setHint(I18nProvider.getSearch().labelNoLayerSelected());
        ((SelectItem) layerSelect).setShowHintInField(true);
        layerSelect.addChangedHandler(new ChangedHandler() {
          public void onChanged(ChangedEvent event) {
            String layerLabel = (String) event.getValue();
            for (Layer<?> vLayer : mapModel.getLayers()) {
              if (vLayer.getLabel().equals(layerLabel)) {
                setLayer((VectorLayer) vLayer);
              }
            }
          }
        });
        mapModel.addMapModelHandler(new MapModelHandler() {
          public void onMapModelChange(MapModelEvent event) {
            updateLayerList();
          }
        });
        updateLayerList();
      } else {
        mapModel.addLayerSelectionHandler(new LayerSelectionHandler() {
          public void onDeselectLayer(LayerDeselectedEvent event) {
            empty();
            updateLabelTitle(I18nProvider.getSearch().labelNoLayerSelected());
          }

          public void onSelectLayer(LayerSelectedEvent event) {
            if (event.getLayer() instanceof VectorLayer) {
              setLayer((VectorLayer) event.getLayer());
              if (event.getLayer() != null) {
                updateLabelTitle(event.getLayer().getLabel());
              }
            }
          }
        });
        layerSelect = new BlurbItem();
        layerSelect.setShowTitle(true);
        layerSelect.setTitle(I18nProvider.getSearch().labelLayerSelected());
        layerSelect.setWidth(250);
        layerSelect.setValue("<b>" + I18nProvider.getSearch().labelNoLayerSelected() + "</b>");
      }
      layerForm.setFields(layerSelect);
      layerLayout.addMember(layerForm);

      leftLayout.addMember(layerLayout);
      DynamicForm logicalForm = new DynamicForm();
      logicalForm.setAutoWidth();
      logicalForm.setLayoutAlign(Alignment.CENTER);
      logicalForm.setFields(logicalOperatorRadio);
      leftLayout.setWidth(420);
      leftLayout.addMember(logicalForm);

      optionLayout.addMember(leftLayout);
      optionLayout.addMember(new LayoutSpacer());

      // Create a header for the criterionStack:
      HLayout headerLayout = new HLayout();
      headerLayout.setHeight(26);
      headerLayout.setStyleName(STYLE_HEADER_BAR);
      HTMLPane attrHeader = new HTMLPane();
      attrHeader.setStyleName(STYLE_SEARCH_HEADER);
      attrHeader.setContents("Attribute");
      attrHeader.setWidth(140);
      HTMLPane operatorHeader = new HTMLPane();
      operatorHeader.setContents("Operator");
      operatorHeader.setWidth(140);
      operatorHeader.setStyleName(STYLE_SEARCH_HEADER);
      HTMLPane valueHeader = new HTMLPane();
      valueHeader.setContents("Value");
      valueHeader.setStyleName(STYLE_SEARCH_HEADER);

      criterionStack = new VStack();
      criterionStack.setAlign(VerticalAlignment.TOP);
      headerLayout.addMember(attrHeader);
      headerLayout.addMember(operatorHeader);
      headerLayout.addMember(valueHeader);
      criterionStack.addMember(headerLayout);

      buttonStack = new VStack();
      buttonStack.setWidth(70);
      buttonStack.setAlign(VerticalAlignment.TOP);
      HTMLPane btnHeader = new HTMLPane();
      btnHeader.setStyleName(STYLE_HEADER_BAR);
      btnHeader.setWidth(70);
      btnHeader.setHeight(26);
      buttonStack.addMember(btnHeader);

      HLayout searchGrid = new HLayout();
      searchGrid.addMember(criterionStack);
      searchGrid.addMember(buttonStack);
      searchGrid.setBorder("1px solid lightgrey");

      layout.addMember(optionLayout);
      layout.addMember(searchGrid);
      addChild(layout);
    }

    private void updateLabelTitle(String title) {
      layerSelect.setValue("<b>" + title + "</b>");
    }
  }
}
TOP

Related Classes of org.geomajas.widget.searchandfilter.client.widget.attributesearch.AttributeSearchPanel$FeatureSearch

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.