Package org.geomajas.gwt.client.controller

Source Code of org.geomajas.gwt.client.controller.SelectionController

/*
* 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.gwt.client.controller;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.geomajas.command.CommandResponse;
import org.geomajas.command.dto.SearchByLocationRequest;
import org.geomajas.command.dto.SearchByLocationResponse;
import org.geomajas.gwt.client.action.menu.DeselectAllAction;
import org.geomajas.gwt.client.action.menu.ToggleSelectionAction;
import org.geomajas.gwt.client.command.CommandCallback;
import org.geomajas.gwt.client.command.GwtCommand;
import org.geomajas.gwt.client.command.GwtCommandDispatcher;
import org.geomajas.gwt.client.map.MapModel;
import org.geomajas.gwt.client.map.feature.Feature;
import org.geomajas.gwt.client.map.layer.Layer;
import org.geomajas.gwt.client.map.layer.VectorLayer;
import org.geomajas.gwt.client.spatial.Bbox;
import org.geomajas.gwt.client.spatial.geometry.Polygon;
import org.geomajas.gwt.client.util.GeometryConverter;
import org.geomajas.gwt.client.widget.MapWidget;
import org.geomajas.gwt.client.widget.MapWidget.RenderGroup;
import org.geomajas.gwt.client.widget.MapWidget.RenderStatus;

import com.google.gwt.event.dom.client.MouseUpEvent;
import com.smartgwt.client.widgets.menu.Menu;

/**
* Allow selection of features, either by clicking on individual features, or by dragging a rectangle and selecting all
* features which (for a certain percentage) fall into the indicated area.
*
* @author Joachim Van der Auwera
* @author Pieter De Graef
*/
public class SelectionController extends AbstractRectangleController {

  private boolean shiftOrCtrl;

  private Menu menu;

  private int clickTimeout; // timeout in milliseconds for handling as click versus dragging

  private float coverageRatio; // coverage percentage which is used to determine a feature as selected

  private boolean priorityToSelectedLayer; // give priority to the selected layer on when toggling

  private int pixelTolerance;

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

  /**
   * Create a new selection controller, that controls selection on the given map through user interaction.
   *
   * @param mapWidget
   *            The map onto whom you want to control selection.
   * @param clickTimeout
   *            Timeout in milliseconds for handling as click versus dragging.
   * @param coverageRatio
   *            Coverage percentage which is used to determine a feature as selected. This is only used when dragging
   *            a rectangle to select in. Must be a floating value between 0 and 1.
   * @param priorityToSelectedLayer
   *            Activate or disable priority to the selected layer. This works only if there is a selected layer, and
   *            that selected layer is a {@link VectorLayer}. In all other cases, the selection toggle will occur on
   *            the first object that is encountered. In other words it will depend on the layer drawing order,
   *            starting at the top.
   * @param pixelTolerance
   *            Number of pixels that describes the tolerance allowed when trying to select features.
   */
  public SelectionController(MapWidget mapWidget, int clickTimeout, float coverageRatio,
      boolean priorityToSelectedLayer, int pixelTolerance) {
    super(mapWidget);

    this.clickTimeout = clickTimeout;
    this.coverageRatio = coverageRatio;
    this.priorityToSelectedLayer = priorityToSelectedLayer;
    this.pixelTolerance = pixelTolerance;
  }

  // -------------------------------------------------------------------------
  // GraphicsController implementation:
  // -------------------------------------------------------------------------

  @Override
  public void onActivate() {
    menu = new Menu();
    menu.addItem(new ToggleSelectionAction(mapWidget, pixelTolerance));
    menu.addItem(new DeselectAllAction(mapWidget.getMapModel()));
    mapWidget.setContextMenu(menu);
  }

  @Override
  public void onDeactivate() {
    super.onDeactivate();
    onDoubleClick(null);
    menu.destroy();
    menu = null;
    mapWidget.setContextMenu(null);
    if (dragging) {
      dragging = false;
      mapWidget.render(rectangle, RenderGroup.SCREEN, RenderStatus.DELETE);
    }
  }

  /**
   * First mouse button: publish a toggle event on the selection topic for the referenced MapWidget. Second mouse
   * button opens a menu.
   *
   * @param event
   *            event
   */
  @Override
  public void onMouseUp(MouseUpEvent event) {
    // handle click if any?
    if (dragging) {
      // shift or CTRL is used when depressed either at beginning or end:
      shiftOrCtrl = (event.isShiftKeyDown() || event.isControlKeyDown());

      if (timestamp + clickTimeout > new Date().getTime()
          && (bounds.getWidth() < pixelTolerance || bounds.getHeight() < pixelTolerance)) {
        stopDragging();
        // click behavior instead of drag
        ToggleSelectionAction action = new ToggleSelectionAction(mapWidget, priorityToSelectedLayer,
            pixelTolerance);
        action.toggle(getScreenPosition(event), !shiftOrCtrl);
        return;
      }
    }
    // normal "rectangle" handling
    super.onMouseUp(event);
  }

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

  /**
   * Coverage percentage which is used to determine a feature as selected. This is only used when dragging a rectangle
   * to select in. Must be a floating value between 0 and 1.
   */
  public float getCoverageRatio() {
    return coverageRatio;
  }

  /**
   * Set a new coverage percentage which is used to determine a feature as selected. This is only used when dragging a
   * rectangle to select in. Must be a floating value between 0 and 1.
   */
  public void setCoverageRatio(float coverageRatio) {
    this.coverageRatio = coverageRatio;
  }

  /**
   * Will priority be given to the selected layer? This works only if there is a selected layer, and that selected
   * layer is a {@link VectorLayer}. In all other cases, the selection toggle will occur on the first object that is
   * encountered. In other words it will depend on the layer drawing order, starting at the top.
   */
  public boolean isPriorityToSelectedLayer() {
    return priorityToSelectedLayer;
  }

  /**
   * Activate or disable priority to the selected layer. This works only if there is a selected layer, and that
   * selected layer is a {@link VectorLayer}. In all other cases, the selection toggle will occur on the first object
   * that is encountered. In other words it will depend on the layer drawing order, starting at the top.
   */
  public void setPriorityToSelectedLayer(boolean priorityToSelectedLayer) {
    this.priorityToSelectedLayer = priorityToSelectedLayer;
  }

  /**
   * Number of pixels that describes the tolerance allowed when trying to select features.
   */
  public int getPixelTolerance() {
    return pixelTolerance;
  }

  /**
   * Number of pixels that describes the tolerance allowed when trying to select features.
   *
   * @param pixelTolerance
   *            The new value.
   */
  public void setPixelTolerance(int pixelTolerance) {
    this.pixelTolerance = pixelTolerance;
  }

  // -------------------------------------------------------------------------
  // Private and protected methods:
  // -------------------------------------------------------------------------

  @Override
  protected void selectRectangle(Bbox selectedArea) {
    // we can clear here !
    if (!shiftOrCtrl) {
      MapModel mapModel = mapWidget.getMapModel();
      mapModel.clearSelectedFeatures();
    }
    GwtCommand commandRequest = new GwtCommand(SearchByLocationRequest.COMMAND);
    SearchByLocationRequest request = new SearchByLocationRequest();
    request.setLayerIds(getSelectionLayerIds());
    for (Layer<?> layer : mapWidget.getMapModel().getLayers()) {
      if (layer.isShowing() && layer instanceof VectorLayer) {
        request.setFilter(layer.getServerLayerId(), ((VectorLayer) layer).getFilter());
      }
    }

    Polygon polygon = mapWidget.getMapModel().getGeometryFactory().createPolygon(selectedArea);
    request.setLocation(GeometryConverter.toDto(polygon));
    request.setCrs(mapWidget.getMapModel().getCrs());
    request.setQueryType(SearchByLocationRequest.QUERY_INTERSECTS);
    request.setRatio(coverageRatio);
    request.setSearchType(SearchByLocationRequest.SEARCH_ALL_LAYERS);
    request.setFeatureIncludes(GwtCommandDispatcher.getInstance().getLazyFeatureIncludesSelect());
    commandRequest.setCommandRequest(request);
    GwtCommandDispatcher.getInstance().execute(commandRequest, new CommandCallback<CommandResponse>() {

      public void execute(CommandResponse commandResponse) {
        if (commandResponse instanceof SearchByLocationResponse) {
          SearchByLocationResponse response = (SearchByLocationResponse) commandResponse;
          Map<String, List<org.geomajas.layer.feature.Feature>> featureMap = response.getFeatureMap();
          for (String layerId : featureMap.keySet()) {
            selectFeatures(layerId, featureMap.get(layerId));
          }
        }
      }
    });
  }

  private String[] getSelectionLayerIds() {
    Layer<?> layer = mapWidget.getMapModel().getSelectedLayer();
    List<String> ids = new ArrayList<String>();
    if (layer != null && layer instanceof VectorLayer) {
      ids.add(layer.getServerLayerId());
    } else {
      for (VectorLayer v : mapWidget.getMapModel().getVectorLayers()) {
        if (v.isShowing()) {
          ids.add(v.getServerLayerId());
        }
      }
    }
    return ids.toArray(new String[ids.size()]);
  }

  private void selectFeatures(String serverLayerId, List<org.geomajas.layer.feature.Feature> orgFeatures) {
    List<VectorLayer> layers = mapWidget.getMapModel().getVectorLayersByServerId(serverLayerId);
    Layer<?> selectedLayer = mapWidget.getMapModel().getSelectedLayer();
    for (VectorLayer vectorLayer : layers) {
      if (isSelectionTargetLayer(vectorLayer, selectedLayer)) {
        for (org.geomajas.layer.feature.Feature orgFeature : orgFeatures) {
          Feature feature = new Feature(orgFeature, vectorLayer);
          vectorLayer.getFeatureStore().addFeature(feature);
          vectorLayer.selectFeature(feature);
        }
      }
    }
  }

  private boolean isSelectionTargetLayer(VectorLayer targetLayer, Layer<?> selectedLayer) {
    if (!targetLayer.isShowing()) {
      return false;
    } else {
      if (priorityToSelectedLayer && selectedLayer != null) {
        return (selectedLayer.equals(targetLayer));
      }
      return true;
    }
  }
}
TOP

Related Classes of org.geomajas.gwt.client.controller.SelectionController

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.