/*---------------- FILE HEADER ------------------------------------------
This file is part of deegree.
Copyright (C) 2001-2007 by:
Department of Geography, University of Bonn
http://www.giub.uni-bonn.de/deegree/
lat/lon GmbH
http://www.lat-lon.de
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; either
version 2.1 of the License, or (at your option) any later version.
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.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact:
Andreas Poth
lat/lon GmbH
Aennchenstr. 19
53177 Bonn
Germany
E-Mail: poth@lat-lon.de
Prof. Dr. Klaus Greve
Department of Geography
University of Bonn
Meckenheimer Allee 166
53115 Bonn
Germany
E-Mail: greve@giub.uni-bonn.de
---------------------------------------------------------------------------*/
package org.deegree.igeo.views.swing;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JComboBox;
import javax.swing.JFormattedTextField;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import org.deegree.datatypes.QualifiedName;
import org.deegree.framework.log.ILogger;
import org.deegree.framework.log.LoggerFactory;
import org.deegree.framework.utils.SwingUtils;
import org.deegree.igeo.i18n.Messages;
import org.deegree.igeo.mapmodel.Layer;
import org.deegree.igeo.mapmodel.LayerGroup;
import org.deegree.igeo.mapmodel.MapModel;
import org.deegree.igeo.views.swing.addlayer.QualifiedNameRenderer;
import org.deegree.model.crs.CoordinateSystem;
import org.deegree.model.feature.Feature;
import org.deegree.model.filterencoding.Operation;
import org.deegree.model.filterencoding.OperationDefines;
import org.deegree.model.filterencoding.PropertyName;
import org.deegree.model.filterencoding.SpatialOperation;
import org.deegree.model.spatialschema.Curve;
import org.deegree.model.spatialschema.Envelope;
import org.deegree.model.spatialschema.Geometry;
import org.deegree.model.spatialschema.GeometryException;
import org.deegree.model.spatialschema.GeometryFactory;
import org.deegree.model.spatialschema.Point;
import org.deegree.model.spatialschema.Surface;
/**
* <code>SpatialCriteriaPanel</code>
*
* @author <a href="mailto:buesching@lat-lon.de">Lyn Buesching</a>
* @author last edited by: $Author$
*
* @version $Revision$, $Date$
*
*/
class SpatialCriteriumPanel extends JPanel {
private static final long serialVersionUID = -9121476995238855181L;
private static final ILogger LOG = LoggerFactory.getLogger( SpatialCriteriumPanel.class );
private enum GEOMTYPE {
CURVE, POINT, SURFACE, MIXED
};
private List<SpatialOperator> spatialOperators;
// spatial operator
private int selectedSpaOp = OperationDefines.UNKNOWN;
// geometry to compare
private String selectedRefGeom = BBOX_GEOM;
public static final String BBOX_GEOM = "BBOX_GEOM";
public static final String SELECTED_GEOM = "SELECTED_GEOM";
private List<QualifiedName> geomPropNames;
private MapModel mapModel;
private JComboBox geomPropsCombo;
private JFormattedTextField dwithinValue;
private JFormattedTextField beyondValue;
private List<Geometry> selectedGeometries;
private GEOMTYPE selectedGeomType;
/*
* @param geomPropNames list of all available property names of the type GEOMETRY
*
* @param mapModelAdapter the mapModelAdaper
*/
SpatialCriteriumPanel( List<QualifiedName> geomPropNames, MapModel mapModel ) {
this.geomPropNames = geomPropNames;
this.mapModel = mapModel;
// init the list containing all spatial operations
spatialOperators = new ArrayList<SpatialOperator>();
String no = Messages.getMessage( Locale.getDefault(), "$MD10166" );
String noTT = Messages.getMessage( Locale.getDefault(), "$MD10167" );
spatialOperators.add( new SpatialOperator( OperationDefines.UNKNOWN, no, noTT ) );
String bbox = Messages.getMessage( Locale.getDefault(), "$MD10168" );
String bboxTT = Messages.getMessage( Locale.getDefault(), "$MD10169" );
spatialOperators.add( new SpatialOperator( OperationDefines.BBOX, bbox, bboxTT ) );
String contains = Messages.getMessage( Locale.getDefault(), "$MD10170" );
String containsTT = Messages.getMessage( Locale.getDefault(), "$MD10171" );
spatialOperators.add( new SpatialOperator( OperationDefines.CONTAINS, contains, containsTT ) );
String crosses = Messages.getMessage( Locale.getDefault(), "$MD10172" );
String crossesTT = Messages.getMessage( Locale.getDefault(), "$MD10173" );
spatialOperators.add( new SpatialOperator( OperationDefines.CROSSES, crosses, crossesTT ) );
String disjoint = Messages.getMessage( Locale.getDefault(), "$MD10174" );
String disjointTT = Messages.getMessage( Locale.getDefault(), "$MD10175" );
spatialOperators.add( new SpatialOperator( OperationDefines.DISJOINT, disjoint, disjointTT ) );
String equals = Messages.getMessage( Locale.getDefault(), "$MD10176" );
String equalsTT = Messages.getMessage( Locale.getDefault(), "$MD10177" );
spatialOperators.add( new SpatialOperator( OperationDefines.EQUALS, equals, equalsTT ) );
String intersects = Messages.getMessage( Locale.getDefault(), "$MD10178" );
String intersectsTT = Messages.getMessage( Locale.getDefault(), "$MD10179" );
spatialOperators.add( new SpatialOperator( OperationDefines.INTERSECTS, intersects, intersectsTT ) );
String overlaps = Messages.getMessage( Locale.getDefault(), "$MD10180" );
String overlapsTT = Messages.getMessage( Locale.getDefault(), "$MD10181" );
spatialOperators.add( new SpatialOperator( OperationDefines.OVERLAPS, overlaps, overlapsTT ) );
String touches = Messages.getMessage( Locale.getDefault(), "$MD10182" );
String touchesTT = Messages.getMessage( Locale.getDefault(), "$MD10183" );
spatialOperators.add( new SpatialOperator( OperationDefines.TOUCHES, touches, touchesTT ) );
String within = Messages.getMessage( Locale.getDefault(), "$MD10184" );
String withinTT = Messages.getMessage( Locale.getDefault(), "$MD10185" );
spatialOperators.add( new SpatialOperator( OperationDefines.WITHIN, within, withinTT ) );
String beyond = Messages.getMessage( Locale.getDefault(), "$MD10186" );
String beyondTT = Messages.getMessage( Locale.getDefault(), "$MD10187" );
spatialOperators.add( new SpatialOperator( OperationDefines.BEYOND, beyond, beyondTT ) );
String dwithin = Messages.getMessage( Locale.getDefault(), "$MD10188" );
String dwithinTT = Messages.getMessage( Locale.getDefault(), "$MD10189" );
spatialOperators.add( new SpatialOperator( OperationDefines.DWITHIN, dwithin, dwithinTT ) );
selectedGeometries = getSelectedGeometries( mapModel.getLayerGroups() );
// init the gui
init();
}
private void init() {
GridBagConstraints gbc = SwingUtils.initPanel( this );
// combo box to choose geometry property
JPanel geomPropPanel = new JPanel();
JLabel geomPropLabel = new JLabel( Messages.getMessage( Locale.getDefault(), "$MD10161" ) );
geomPropsCombo = new JComboBox();
geomPropsCombo.setRenderer( new QualifiedNameRenderer() );
geomPropsCombo.setPreferredSize( new Dimension( 200, 22 ) );
geomPropPanel.add( geomPropLabel );
geomPropPanel.add( geomPropsCombo );
for ( QualifiedName name : geomPropNames ) {
geomPropsCombo.addItem( name );
}
// action listener for spatial operators to get the selected
ActionListener spatialOpAl = new ActionListener() {
public void actionPerformed( ActionEvent e ) {
JRadioButton rb = (JRadioButton) e.getSource();
selectedSpaOp = OperationDefines.getIdByName( rb.getActionCommand() );
if ( selectedSpaOp == OperationDefines.BEYOND ) {
beyondValue.setEnabled( true );
dwithinValue.setEnabled( false );
} else if ( selectedSpaOp == OperationDefines.DWITHIN ) {
dwithinValue.setEnabled( true );
beyondValue.setEnabled( false );
} else {
beyondValue.setEnabled( false );
dwithinValue.setEnabled( false );
}
}
};
// create a radioButton for every spatial operator and add them to the panel
JPanel spatialOpPanel = new JPanel();
GridBagConstraints spatialOpGbc = SwingUtils.initPanel( spatialOpPanel );
spatialOpGbc.anchor = GridBagConstraints.LINE_START;
ButtonGroup spatOpGroup = new ButtonGroup();
for ( SpatialOperator spatOp : this.spatialOperators ) {
JRadioButton rb = new JRadioButton( spatOp.text );
rb.setToolTipText( spatOp.toolTipText );
rb.setActionCommand( spatOp.getOperationName() );
rb.addActionListener( spatialOpAl );
spatOpGroup.add( rb );
spatialOpPanel.add( rb, spatialOpGbc );
++spatialOpGbc.gridy;
if ( spatOp.operationId == OperationDefines.UNKNOWN ) {
rb.setSelected( true );
}
}
// text fields for BEYOND/DWITHIN operation
Dimension textFieldDim = new Dimension( 150, 20 );
beyondValue = new JFormattedTextField();
beyondValue.setValue( new Double( 0.0 ) );
beyondValue.setPreferredSize( textFieldDim );
dwithinValue = new JFormattedTextField();
dwithinValue.setPreferredSize( textFieldDim );
dwithinValue.setValue( new Double( 0.0 ) );
beyondValue.setEnabled( false );
dwithinValue.setEnabled( false );
gbc.gridx = 1;
gbc.gridy = spatialOpPanel.getComponentCount() - 2;
spatialOpPanel.add( beyondValue, gbc );
++gbc.gridy;
spatialOpPanel.add( dwithinValue, gbc );
spatialOpPanel.setBorder( BorderFactory.createTitledBorder( Messages.getMessage( Locale.getDefault(),
"$MD10162" ) ) );
// actionListener to get the selected reference geometry
ActionListener geomAl = new ActionListener() {
public void actionPerformed( ActionEvent e ) {
JRadioButton rb = (JRadioButton) e.getSource();
selectedRefGeom = rb.getActionCommand();
}
};
// create panel with available reference geometries
JPanel compareGeomPanel = new JPanel();
compareGeomPanel.setBorder( BorderFactory.createTitledBorder( Messages.getMessage( Locale.getDefault(),
"$MD10163" ) ) );
JRadioButton bbox = new JRadioButton( Messages.getMessage( Locale.getDefault(), "$MD10164" ) );
JRadioButton selectedGeom = new JRadioButton( Messages.getMessage( Locale.getDefault(), "$MD10165" ) );
if ( selectedGeometries == null || selectedGeometries.size() == 0 ) {
selectedGeom.setEnabled( false );
}
ButtonGroup compGeomGroup = new ButtonGroup();
compGeomGroup.add( bbox );
compareGeomPanel.add( bbox );
bbox.setActionCommand( BBOX_GEOM );
bbox.addActionListener( geomAl );
compGeomGroup.add( selectedGeom );
compareGeomPanel.add( selectedGeom );
selectedGeom.setActionCommand( SELECTED_GEOM );
selectedGeom.addActionListener( geomAl );
bbox.setSelected( true );
// add all components to spatial panel
gbc.anchor = GridBagConstraints.CENTER;
this.add( geomPropPanel, gbc );
gbc.weightx = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
++gbc.gridy;
this.add( spatialOpPanel, gbc );
gbc.weightx = 0;
gbc.fill = GridBagConstraints.NONE;
++gbc.gridy;
this.add( compareGeomPanel, gbc );
}
/**
* @return the selected property name
*/
private PropertyName getPropertyName() {
QualifiedName qName = (QualifiedName) this.geomPropsCombo.getSelectedItem();
return new PropertyName( qName );
}
/**
* @return the selected operator
*/
private int getOperator() {
return selectedSpaOp;
}
/**
* @return the reference geometry
*/
private Geometry getReferenceGeometry() {
Geometry geom = null;
if ( this.selectedRefGeom.equals( SELECTED_GEOM ) ) {
Envelope extent = this.mapModel.getEnvelope();
CoordinateSystem crs = extent.getCoordinateSystem();
// create MultiXXX dependent on the type of the geometry to avoid problems with
// MultiGeometries id not needed
switch ( selectedGeomType ) {
case CURVE:
Curve[] curveList = (Curve[]) selectedGeometries.toArray( new Curve[selectedGeometries.size()] );
geom = GeometryFactory.createMultiCurve( curveList, crs );
break;
case POINT:
Point[] pointList = (Point[]) selectedGeometries.toArray( new Point[selectedGeometries.size()] );
geom = GeometryFactory.createMultiPoint( pointList, crs );
break;
case SURFACE:
Surface[] surfaceList = (Surface[]) selectedGeometries.toArray( new Surface[selectedGeometries.size()] );
geom = GeometryFactory.createMultiSurface( surfaceList, crs );
break;
default:
Geometry[] geomList = (Geometry[]) selectedGeometries.toArray( new Geometry[selectedGeometries.size()] );
geom = GeometryFactory.createMultiGeometry( geomList, crs );
break;
}
} else {
Envelope extent = this.mapModel.getEnvelope();
CoordinateSystem crs = extent.getCoordinateSystem();
try {
geom = GeometryFactory.createSurface( extent, crs );
} catch ( GeometryException e ) {
LOG.logError( Messages.getMessage( Locale.getDefault(), "$DG10020" ), e );
}
}
return geom;
}
private List<Geometry> getSelectedGeometries( List<LayerGroup> layerGroups ) {
List<Geometry> selectedGeometries = new ArrayList<Geometry>();
for ( LayerGroup layerGroup : layerGroups ) {
selectedGeometries.addAll( getSelectedGeometries( ( layerGroup.getLayerGroups() ) ) );
for ( Layer layer : layerGroup.getLayers() ) {
Iterator<Feature> iterator = layer.getSelectedFeatures().iterator();
while ( iterator.hasNext() ) {
Feature feature = iterator.next();
Geometry geom = feature.getDefaultGeometryPropertyValue();
// detect type of the geometry
if ( ( selectedGeomType == null || selectedGeomType.equals( GEOMTYPE.CURVE ) )
&& geom instanceof Curve ) {
selectedGeomType = GEOMTYPE.CURVE;
} else if ( ( selectedGeomType == null || selectedGeomType.equals( GEOMTYPE.POINT ) )
&& geom instanceof Point ) {
selectedGeomType = GEOMTYPE.POINT;
} else if ( ( selectedGeomType == null || selectedGeomType.equals( GEOMTYPE.SURFACE ) )
&& geom instanceof Surface ) {
selectedGeomType = GEOMTYPE.SURFACE;
} else {
selectedGeomType = GEOMTYPE.MIXED;
}
selectedGeometries.add( geom );
}
}
}
return selectedGeometries;
}
/**
* @return the spatial operation created in this dialog
*/
public Operation getOperation() {
SpatialOperation spatialOp = null;
switch ( this.selectedSpaOp ) {
case OperationDefines.BBOX:
case OperationDefines.WITHIN:
case OperationDefines.CONTAINS:
case OperationDefines.CROSSES:
case OperationDefines.DISJOINT:
case OperationDefines.EQUALS:
case OperationDefines.INTERSECTS:
case OperationDefines.OVERLAPS:
case OperationDefines.TOUCHES: {
spatialOp = new SpatialOperation( getOperator(), getPropertyName(), getReferenceGeometry() );
break;
}
case OperationDefines.DWITHIN: {
double distDWitihn = new Double( dwithinValue.getText() );
spatialOp = new SpatialOperation( getOperator(), getPropertyName(), getReferenceGeometry(), distDWitihn );
break;
}
case OperationDefines.BEYOND: {
double distBeyond = new Double( beyondValue.getText() );
spatialOp = new SpatialOperation( getOperator(), getPropertyName(), getReferenceGeometry(), distBeyond );
break;
}
}
return spatialOp;
}
/**
* The <code>SpatialOperator</code> combines the type of the operation with the text shown in
* the gui and a toolTip.
*
* @author <a href="mailto:buesching@lat-lon.de">Lyn Buesching</a>
* @author last edited by: $Author$
*
* @version $Revision$, $Date$
*
*/
private class SpatialOperator {
int operationId;
String text;
String toolTipText;
/**
* @param operationId
* the {@link OperationDefines} id
* @param text
* the text
* @param toolTipText
* the toolTip text
*/
SpatialOperator( int operationId, String text, String toolTipText ) {
this.operationId = operationId;
this.text = text;
this.toolTipText = toolTipText;
}
/**
* @return the name of the operation assigned to the operationId defined in class
* {@link OperationDefines}
*/
String getOperationName() {
return OperationDefines.getNameById( operationId );
}
}
}