/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2006-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library 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
* Lesser General Public License for more details.
*/
package org.geotools.gui.swing.map.map2d.stream;
import org.geotools.gui.swing.map.map2d.*;
import java.awt.BorderLayout;
import java.awt.Color;
import java.beans.PropertyChangeEvent;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JComponent;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.gui.swing.map.map2d.decoration.MapDecoration;
import org.geotools.gui.swing.map.map2d.stream.event.StrategyEvent;
import org.geotools.gui.swing.map.map2d.stream.event.SelectionEvent;
import org.geotools.gui.swing.map.map2d.stream.handler.DefaultSelectionHandler;
import org.geotools.gui.swing.map.map2d.stream.handler.SelectionHandler;
import org.geotools.gui.swing.map.map2d.stream.listener.SelectionListener;
import org.geotools.gui.swing.map.map2d.stream.strategy.StreamingStrategy;
import org.geotools.gui.swing.map.map2d.stream.strategy.SingleBufferedImageStrategy;
import org.geotools.gui.swing.misc.FacilitiesFactory;
import org.geotools.gui.swing.misc.GeometryClassFilter;
import org.geotools.map.DefaultMapContext;
import org.geotools.map.MapContext;
import org.geotools.map.MapLayer;
import org.geotools.map.event.MapLayerListEvent;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.styling.FeatureTypeStyle;
import org.geotools.styling.Fill;
import org.geotools.styling.Graphic;
import org.geotools.styling.LineSymbolizer;
import org.geotools.styling.Mark;
import org.geotools.styling.PointSymbolizer;
import org.geotools.styling.PolygonSymbolizer;
import org.geotools.styling.Rule;
import org.geotools.styling.Stroke;
import org.geotools.styling.Style;
import org.geotools.styling.StyleBuilder;
import org.geotools.styling.Symbolizer;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.expression.Expression;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.TransformException;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.geom.MultiPoint;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
/**
* Default implementation of selectableMap2D
*
* @author Johann Sorel
*/
class JStreamSelectMap extends JStreamNavMap implements SelectableMap2D {
/**
* Geometry factory for JTS geometry creation
*/
protected GeometryFactory GEOMETRY_FACTORY = null;
/**
* Facilities factory to duplicate MapLayers
*/
protected FacilitiesFactory FACILITIES_FACTORY = null;
/**
* Style builder for sld style creation
*/
protected StyleBuilder STYLE_BUILDER = null;
/**
* Filter factory 2
*/
protected FilterFactory2 FILTER_FACTORY_2 = null;
private final StreamingStrategy selectionStrategy = new SingleBufferedImageStrategy();
private final MapContext selectionMapContext = new DefaultMapContext(DefaultGeographicCRS.WGS84);
private final BufferComponent selectedDecoration = new BufferComponent();
private final Map<MapLayer, MapLayer> copies = new HashMap<MapLayer, MapLayer>();
private MapContext oldMapcontext = null;
private Color selectionStyleColor = Color.GREEN;
private Geometry selectionGeometrie = null;
private SelectionHandler selectionHandler = new DefaultSelectionHandler();
private SELECTION_FILTER selectionFilter = SELECTION_FILTER.INTERSECTS;
/**
* create a default JDefaultSelectableMap2D
*/
protected JStreamSelectMap() {
super();
//I made it like this so that matisse handle this widget
try{
GEOMETRY_FACTORY = new GeometryFactory();
FACILITIES_FACTORY = new FacilitiesFactory();
STYLE_BUILDER = new StyleBuilder();
FILTER_FACTORY_2 = (FilterFactory2) CommonFactoryFinder.getFilterFactory(null);
}catch(Exception e){}
init();
}
private void init(){
selectionStrategy.setContext(selectionMapContext);
addMapDecoration(selectedDecoration);
}
/**
* transform a mouse coordinate in JTS Geometry using the CRS of the mapcontext
* @param mx : x coordinate of the mouse on the map (in pixel)
* @param my : y coordinate of the mouse on the map (in pixel)
* @return JTS geometry (corresponding to a square of 6x6 pixel around mouse coordinate)
*/
protected Geometry mousePositionToGeometry(int mx, int my) {
Coordinate[] coord = new Coordinate[5];
int taille = 4;
coord[0] = renderingStrategy.toMapCoord(mx - taille, my - taille);
coord[1] = renderingStrategy.toMapCoord(mx - taille, my + taille);
coord[2] = renderingStrategy.toMapCoord(mx + taille, my + taille);
coord[3] = renderingStrategy.toMapCoord(mx + taille, my - taille);
coord[4] = coord[0];
LinearRing lr1 = GEOMETRY_FACTORY.createLinearRing(coord);
return GEOMETRY_FACTORY.createPolygon(lr1, null);
}
/**
* create a filter corresponding to the layer features intersecting the geom
* @param geom : the intersect JTS geometry used by the filter
* @param layer : MapLayer for which the filter is made
* @return Filter
*/
public Filter createFilter(Geometry geom, SELECTION_FILTER filter, MapLayer layer) {
Filter f = null;
geom = FACILITIES_FACTORY.projectGeometry(geom, renderingStrategy.getContext(), layer);
try {
String name = layer.getFeatureSource().getSchema().getGeometryDescriptor().getLocalName();
if (name.equals("")) {
name = "the_geom";
}
Expression exp1 = FILTER_FACTORY_2.property(name);
Expression exp2 = FILTER_FACTORY_2.literal(geom);
switch (filter) {
case CONTAINS:
f = FILTER_FACTORY_2.contains(exp1, exp2);
break;
case CROSSES:
f = FILTER_FACTORY_2.crosses(exp1, exp2);
break;
case DISJOINT:
f = FILTER_FACTORY_2.disjoint(exp1, exp2);
break;
case INTERSECTS:
f = FILTER_FACTORY_2.intersects(exp1, exp2);
break;
case OVERLAPS:
f = FILTER_FACTORY_2.overlaps(exp1, exp2);
break;
case TOUCHES:
f = FILTER_FACTORY_2.touches(exp1, exp2);
break;
case WITHIN:
f = FILTER_FACTORY_2.within(exp1, exp2);
break;
}
} catch (Exception e) {
e.printStackTrace();
}
return f;
}
private Style createStyle(MapLayer layer) {
Class jtsClass = layer.getFeatureSource().getSchema().getGeometryDescriptor().getType().getBinding();
if (jtsClass.equals(Point.class) || jtsClass.equals(MultiPoint.class)) {
Fill fill = STYLE_BUILDER.createFill(selectionStyleColor, 0.6f);
Stroke stroke = STYLE_BUILDER.createStroke(selectionStyleColor, 2);
stroke.setOpacity(STYLE_BUILDER.literalExpression(1f));
Mark mark = STYLE_BUILDER.createMark("circle", fill, stroke);
Graphic gra = STYLE_BUILDER.createGraphic();
gra.setOpacity(STYLE_BUILDER.literalExpression(1f));
gra.setMarks(new Mark[]{mark});
gra.setSize(STYLE_BUILDER.literalExpression(15));
PointSymbolizer ps = STYLE_BUILDER.createPointSymbolizer(gra);
Style pointSelectionStyle = STYLE_BUILDER.createStyle();
pointSelectionStyle.addFeatureTypeStyle(STYLE_BUILDER.createFeatureTypeStyle(ps));
return pointSelectionStyle;
} else if (jtsClass.equals(LineString.class) || jtsClass.equals(MultiLineString.class)) {
Fill fill = STYLE_BUILDER.createFill(selectionStyleColor, 0.6f);
Stroke stroke = STYLE_BUILDER.createStroke(selectionStyleColor, 2);
stroke.setOpacity(STYLE_BUILDER.literalExpression(1f));
Mark mark = STYLE_BUILDER.createMark("circle", fill, stroke);
Graphic gra = STYLE_BUILDER.createGraphic();
gra.setOpacity(STYLE_BUILDER.literalExpression(1f));
gra.setMarks(new Mark[]{mark});
gra.setSize(STYLE_BUILDER.literalExpression(5));
PointSymbolizer ps = STYLE_BUILDER.createPointSymbolizer(gra);
LineSymbolizer ls = STYLE_BUILDER.createLineSymbolizer(stroke);
Rule r1 = STYLE_BUILDER.createRule(new Symbolizer[]{ps});
Rule r2 = STYLE_BUILDER.createRule(new Symbolizer[]{ls});
Style lineSelectionStyle = STYLE_BUILDER.createStyle();
lineSelectionStyle.addFeatureTypeStyle(STYLE_BUILDER.createFeatureTypeStyle(null, new Rule[]{r1, r2}));
return lineSelectionStyle;
} else if (jtsClass.equals(Polygon.class) || jtsClass.equals(MultiPolygon.class)) {
Fill fill = STYLE_BUILDER.createFill(selectionStyleColor, 0.6f);
Stroke stroke = STYLE_BUILDER.createStroke(selectionStyleColor, 2);
stroke.setOpacity(STYLE_BUILDER.literalExpression(1f));
PolygonSymbolizer pls = STYLE_BUILDER.createPolygonSymbolizer(stroke, fill);
Mark mark = STYLE_BUILDER.createMark("circle", fill, stroke);
Graphic gra = STYLE_BUILDER.createGraphic();
gra.setOpacity(STYLE_BUILDER.literalExpression(1f));
gra.setMarks(new Mark[]{mark});
gra.setSize(STYLE_BUILDER.literalExpression(5));
PointSymbolizer ps = STYLE_BUILDER.createPointSymbolizer(gra);
Rule r1 = STYLE_BUILDER.createRule(new Symbolizer[]{ps});
Rule r3 = STYLE_BUILDER.createRule(new Symbolizer[]{pls});
Style polySelectionStyle = STYLE_BUILDER.createStyle();
polySelectionStyle.addFeatureTypeStyle(STYLE_BUILDER.createFeatureTypeStyle(null, new Rule[]{r1, r3}));
return polySelectionStyle;
}
Fill fill = STYLE_BUILDER.createFill(selectionStyleColor, 0.4f);
Stroke stroke = STYLE_BUILDER.createStroke(selectionStyleColor, 2);
stroke.setOpacity(STYLE_BUILDER.literalExpression(0.6f));
PolygonSymbolizer pls = STYLE_BUILDER.createPolygonSymbolizer(stroke, fill);
Mark mark = STYLE_BUILDER.createMark("circle", fill, stroke);
Graphic gra = STYLE_BUILDER.createGraphic();
gra.setOpacity(STYLE_BUILDER.literalExpression(0.6f));
gra.setMarks(new Mark[]{mark});
gra.setSize(STYLE_BUILDER.literalExpression(14));
PointSymbolizer ps = STYLE_BUILDER.createPointSymbolizer(gra);
LineSymbolizer ls = STYLE_BUILDER.createLineSymbolizer(stroke);
Rule r1 = STYLE_BUILDER.createRule(new Symbolizer[]{ps});
r1.setFilter(new GeometryClassFilter(Point.class, MultiPoint.class));
Rule r2 = STYLE_BUILDER.createRule(new Symbolizer[]{ls});
r2.setFilter(new GeometryClassFilter(LineString.class, MultiLineString.class));
Rule r3 = STYLE_BUILDER.createRule(new Symbolizer[]{pls});
r3.setFilter(new GeometryClassFilter(Polygon.class, MultiPolygon.class));
Style LineSelectionStyle = STYLE_BUILDER.createStyle();
LineSelectionStyle.addFeatureTypeStyle(STYLE_BUILDER.createFeatureTypeStyle(null, new Rule[]{r1, r2, r3}));
return LineSelectionStyle;
}
private void applyStyleFilter(Style style, Filter f) {
for (FeatureTypeStyle fts : style.getFeatureTypeStyles()) {
for (Rule r : fts.getRules()) {
r.setFilter(f);
}
}
}
private void fireSelectionChanged(Geometry oldgeo, Geometry newgeo) {
SelectionEvent mce = new SelectionEvent(this, oldgeo,newgeo, selectionFilter, selectionHandler);
SelectionListener[] lst = getSelectableMap2DListeners();
for (SelectionListener l : lst) {
l.selectionChanged(mce);
}
}
private void fireFilterChanged(SELECTION_FILTER oldfilter,SELECTION_FILTER newfilter) {
SelectionEvent mce = new SelectionEvent(this, selectionGeometrie, oldfilter, newfilter, selectionHandler);
SelectionListener[] lst = getSelectableMap2DListeners();
for (SelectionListener l : lst) {
l.selectionFilterChanged(mce);
}
}
private void fireHandlerChanged(SelectionHandler oldhandler, SelectionHandler newhandler) {
SelectionEvent mce = new SelectionEvent(this, selectionGeometrie, selectionFilter, oldhandler, newhandler);
SelectionListener[] lst = getSelectableMap2DListeners();
for (SelectionListener l : lst) {
l.selectionHandlerChanged(mce);
}
}
//---------------------MAP2D OVERLOAD---------------------------------------
@Override
public void setActionState(ACTION_STATE state) {
if (state == ACTION_STATE.SELECT && !selectionHandler.isInstalled()) {
selectionHandler.install(this);
} else if (state != ACTION_STATE.SELECT && selectionHandler.isInstalled()) {
selectionHandler.uninstall();
}
super.setActionState(state);
}
@Override
protected void mapAreaChanged(StrategyEvent event) {
super.mapAreaChanged(event);
MapContext context = renderingStrategy.getContext();
try {
selectionMapContext.setCoordinateReferenceSystem(context.getCoordinateReferenceSystem());
} catch (TransformException ex) {
ex.printStackTrace();
} catch (FactoryException ex) {
ex.printStackTrace();
}
selectionStrategy.setMapArea(event.getMapArea());
}
@Override
public void propertyChange(PropertyChangeEvent arg0) {
super.propertyChange(arg0);
MapContext context = renderingStrategy.getContext();
try {
selectionMapContext.setCoordinateReferenceSystem(context.getCoordinateReferenceSystem());
} catch (TransformException ex) {
ex.printStackTrace();
} catch (FactoryException ex) {
ex.printStackTrace();
}
selectionStrategy.refresh();
}
@Override
protected void mapContextChanged(StrategyEvent event) {
super.mapContextChanged(event);
if (event.getContext() != oldMapcontext) {
oldMapcontext = event.getContext();
selectionMapContext.clearLayerList();
copies.clear();
MapContext context = event.getContext();
try {
selectionMapContext.setCoordinateReferenceSystem(context.getCoordinateReferenceSystem());
selectionStrategy.setMapArea(renderingStrategy.getMapArea());
} catch (TransformException ex) {
ex.printStackTrace();
} catch (FactoryException ex) {
ex.printStackTrace();
}
}
}
@Override
public void setRenderingStrategy(StreamingStrategy stratege) {
if (actionState == ACTION_STATE.SELECT && selectionHandler.isInstalled()) {
selectionHandler.uninstall();
}
super.setRenderingStrategy(stratege);
if (actionState == ACTION_STATE.SELECT) {
selectionHandler.install(this);
}
}
@Override
protected void setRendering(boolean render) {
super.setRendering(render);
MapContext context = renderingStrategy.getContext();
try {
selectionMapContext.setCoordinateReferenceSystem(context.getCoordinateReferenceSystem());
} catch (TransformException ex) {
ex.printStackTrace();
} catch (FactoryException ex) {
ex.printStackTrace();
}
selectionStrategy.setMapArea(renderingStrategy.getMapArea());
selectionStrategy.refresh();
}
@Override
public void dispose() {
super.dispose();
selectionStrategy.dispose();
}
@Override
public void layerRemoved(MapLayerListEvent event) {
super.layerRemoved(event);
removeSelectableLayer(event.getLayer());
}
//----------------------SELECTABLE MAP2D------------------------------------
private void addSelectableLayerNU(MapLayer layer) {
if (layer != null) {
MapLayer copy = FACILITIES_FACTORY.duplicateLayer(layer);
copy.setStyle(createStyle(layer));
if (selectionGeometrie != null) {
try {
Filter f = createFilter(selectionGeometrie, selectionFilter, copy);
applyStyleFilter(copy.getStyle(), f);
} catch (Exception e) {
e.printStackTrace();
}
} else {
applyStyleFilter(copy.getStyle(), Filter.EXCLUDE);
}
selectionMapContext.addLayer(copy);
if (selectionMapContext.getLayerCount() == 1) {
selectionStrategy.setMapArea(renderingStrategy.getMapArea());
}
copies.put(layer, copy);
}
}
public void addSelectableLayer(MapLayer layer) {
addSelectableLayerNU(layer);
selectionStrategy.refresh();
}
public void addSelectableLayer(MapLayer[] layers) {
if (layers != null) {
for (MapLayer layer : layers) {
addSelectableLayerNU(layer);
}
selectionStrategy.refresh();
}
}
public void removeSelectableLayer(MapLayer layer) {
MapLayer copy = copies.remove(layer);
selectionMapContext.removeLayer(copy);
}
public MapLayer[] getSelectableLayer() {
return copies.keySet().toArray(new MapLayer[0]);
}
public boolean isLayerSelectable(MapLayer layer) {
return copies.containsKey(layer);
}
public void setSelectionFilter(SELECTION_FILTER newFilter) {
if (newFilter == null) {
throw new NullPointerException();
} else if (newFilter != selectionFilter) {
SELECTION_FILTER oldFilter = selectionFilter;
selectionFilter = newFilter;
fireFilterChanged(oldFilter,newFilter);
}
}
public SELECTION_FILTER getSelectionFilter() {
return selectionFilter;
}
public void setSelectionHandler(SelectionHandler newHandler) {
if (newHandler == null) {
throw new NullPointerException();
} else if (newHandler != selectionHandler) {
if (selectionHandler.isInstalled()) {
selectionHandler.uninstall();
}
SelectionHandler oldHandler = selectionHandler;
selectionHandler = newHandler;
if (actionState == ACTION_STATE.SELECT) {
selectionHandler.install(this);
}
fireHandlerChanged(oldHandler,newHandler);
}
}
public SelectionHandler getSelectionHandler() {
return selectionHandler;
}
public void doSelection(double x, double y) {
Geometry geometry = GEOMETRY_FACTORY.createPoint(new Coordinate(x, y));
doSelection(geometry);
}
public void doSelection(Geometry newGeo) {
Geometry oldGeo = selectionGeometrie;
selectionGeometrie = newGeo;
Filter f = null;
if (selectionMapContext.getLayerCount() == 0) {
return;
}
for (MapLayer layer : selectionMapContext.getLayers()) {
try {
f = createFilter(newGeo, selectionFilter, layer);
applyStyleFilter(layer.getStyle(), f);
} catch (Exception e) {
e.printStackTrace();
}
}
selectionStrategy.refresh();
fireSelectionChanged(oldGeo,newGeo);
}
public void addSelectableMap2DListener(SelectionListener listener) {
MAP2DLISTENERS.add(SelectionListener.class, listener);
}
public void removeSelectableMap2DListener(SelectionListener listener) {
MAP2DLISTENERS.remove(SelectionListener.class, listener);
}
public SelectionListener[] getSelectableMap2DListeners() {
return MAP2DLISTENERS.getListeners(SelectionListener.class);
}
//---------------------PRIVATE CLASSES--------------------------------------
private class BufferComponent extends JComponent implements MapDecoration {
public BufferComponent() {
setLayout(new BorderLayout());
add(selectionStrategy.getComponent());
}
public void refresh() {
}
public JComponent geComponent() {
return this;
}
public void setMap2D(Map2D map) {
}
public Map2D getMap2D() {
return null;
}
public void dispose() {
}
}
}