/*
* The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
* for visualizing and manipulating spatial features with geometry and attributes.
*
* Copyright (C) 2003 Vivid Solutions
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* For more information, contact:
*
* Vivid Solutions
* Suite #1A
* 2328 Government Street
* Victoria BC V8T 5G5
* Canada
*
* (250)385-6040
* www.vividsolutions.com
*/
package com.vividsolutions.jump.workbench.ui.plugin.analysis;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.*;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JRadioButton;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jump.I18N;
import com.vividsolutions.jump.feature.*;
import com.vividsolutions.jump.task.TaskMonitor;
import com.vividsolutions.jump.util.StringUtil;
import com.vividsolutions.jump.workbench.WorkbenchContext;
import com.vividsolutions.jump.workbench.model.Layer;
import com.vividsolutions.jump.workbench.model.StandardCategoryNames;
import com.vividsolutions.jump.workbench.plugin.*;
import com.vividsolutions.jump.workbench.plugin.util.*;
import com.vividsolutions.jump.workbench.ui.GUIUtil;
import com.vividsolutions.jump.workbench.ui.GenericNames;
import com.vividsolutions.jump.workbench.ui.MenuNames;
import com.vividsolutions.jump.workbench.ui.MultiInputDialog;
import com.vividsolutions.jump.workbench.ui.SelectionManager;
import com.vividsolutions.jump.workbench.ui.plugin.FeatureInstaller;
/**
* Queries a layer by a spatial predicate.
*/
public class AttributeQueryPlugIn
extends AbstractPlugIn
implements ThreadedPlugIn
{
private static String ATTR_GEOMETRY_AREA = I18N.get("ui.plugin.analysis.AttributeQueryPlugIn.Geometry.Area");
private static String ATTR_GEOMETRY_LENGTH = I18N.get("ui.plugin.analysis.AttributeQueryPlugIn.Geometry.Length");
private static String ATTR_GEOMETRY_NUMPOINTS = I18N.get("ui.plugin.analysis.AttributeQueryPlugIn.Geometry.NumPoints");
private static String ATTR_GEOMETRY_NUMCOMPONENTS = I18N.get("ui.plugin.analysis.AttributeQueryPlugIn.Geometry.NumComponents");
private static String ATTR_GEOMETRY_ISCLOSED = I18N.get("ui.plugin.analysis.AttributeQueryPlugIn.Geometry.IsClosed");
private static String ATTR_GEOMETRY_ISSIMPLE = I18N.get("ui.plugin.analysis.AttributeQueryPlugIn.Geometry.IsSimple");
private static String ATTR_GEOMETRY_ISVALID = I18N.get("ui.plugin.analysis.AttributeQueryPlugIn.Geometry.IsValid");
private static String ATTR_GEOMETRY_TYPE = I18N.get("ui.plugin.analysis.AttributeQueryPlugIn.Geometry.Type");
// MD - could easily add this later
//private final static String DIALOG_COMPLEMENT = "Complement Result";
private Collection functionNames;
private MultiInputDialog dialog;
private Layer srcLayer;
private String attrName;
private String funcNameToRun;
private String value = "";
private boolean complementResult = false;
private boolean exceptionThrown = false;
private JRadioButton updateSourceRB;
private JRadioButton createNewLayerRB;
private boolean createLayer = true;
public AttributeQueryPlugIn() {
functionNames = AttributePredicate.getNames();
}
private String categoryName = StandardCategoryNames.RESULT;
public void setCategoryName(String value) {
categoryName = value;
}
public void initialize(PlugInContext context) throws Exception
{
FeatureInstaller featureInstaller = new FeatureInstaller(context.getWorkbenchContext());
featureInstaller.addMainMenuItem(
this, //exe
new String[] {MenuNames.TOOLS, MenuNames.TOOLS_QUERIES}, //menu path
this.getName() + "..." , //name methode .getName recieved by AbstractPlugIn
false, //checkbox
null, //icon
createEnableCheck(context.getWorkbenchContext())); //enable check
}
public static MultiEnableCheck createEnableCheck(WorkbenchContext workbenchContext) {
EnableCheckFactory checkFactory = new EnableCheckFactory(workbenchContext);
return new MultiEnableCheck()
.add(checkFactory.createWindowWithLayerNamePanelMustBeActiveCheck())
.add(checkFactory.createAtLeastNLayersMustExistCheck(1));
}
public String getName(){
return I18N.get("ui.plugin.analysis.AttributeQueryPlugIn.Attribute-Query");
}
public boolean execute(PlugInContext context) throws Exception {
//[sstein] reset for correct language
ATTR_GEOMETRY_AREA = I18N.get("ui.plugin.analysis.AttributeQueryPlugIn.Geometry.Area");
ATTR_GEOMETRY_LENGTH = I18N.get("ui.plugin.analysis.AttributeQueryPlugIn.Geometry.Length");
ATTR_GEOMETRY_NUMPOINTS = I18N.get("ui.plugin.analysis.AttributeQueryPlugIn.Geometry.NumPoints");
ATTR_GEOMETRY_NUMCOMPONENTS = I18N.get("ui.plugin.analysis.AttributeQueryPlugIn.Geometry.NumComponents");
ATTR_GEOMETRY_ISCLOSED = I18N.get("ui.plugin.analysis.AttributeQueryPlugIn.Geometry.IsClosed");
ATTR_GEOMETRY_ISSIMPLE = I18N.get("ui.plugin.analysis.AttributeQueryPlugIn.Geometry.IsSimple");
ATTR_GEOMETRY_ISVALID = I18N.get("ui.plugin.analysis.AttributeQueryPlugIn.Geometry.IsValid");
ATTR_GEOMETRY_TYPE = I18N.get("ui.plugin.analysis.AttributeQueryPlugIn.Geometry.Type");
dialog = new MultiInputDialog(context.getWorkbenchFrame(), getName(), true);
setDialogValues(dialog, context);
GUIUtil.centreOnWindow(dialog);
dialog.setVisible(true);
if (! dialog.wasOKPressed()) { return false; }
getDialogValues(dialog);
// input-proofing
if (srcLayer == null) return false;
if (StringUtil.isEmpty(value)) return false;
if (StringUtil.isEmpty(attrName)) return false;
if (StringUtil.isEmpty(funcNameToRun)) return false;
return true;
}
public void run(TaskMonitor monitor, PlugInContext context)
throws Exception {
monitor.allowCancellationRequests();
monitor.report(I18N.get("ui.plugin.analysis.SpatialQueryPlugIn.Executing-query")+"...");
FeatureCollection sourceFC = srcLayer.getFeatureCollectionWrapper();
if (monitor.isCancelRequested()) return;
FeatureCollection resultFC = executeQuery(sourceFC, attrName, value);
if (createLayer) {
String outputLayerName = LayerNameGenerator.generateOperationOnLayerName(
funcNameToRun,
srcLayer.getName());
context.getLayerManager().addCategory(categoryName);
context.addLayer(categoryName, outputLayerName, resultFC);
} else {
SelectionManager selectionManager = context.getLayerViewPanel().getSelectionManager();
selectionManager.clear();
selectionManager.getFeatureSelection().selectItems( srcLayer, resultFC.getFeatures() );
}
if (exceptionThrown) {
context.getWorkbenchFrame().warnUser(I18N.get("ui.plugin.analysis.SpatialQueryPlugIn.Errors-found-while-executing-query"));
}
}
private FeatureCollection executeQuery(
FeatureCollection sourceFC,
String attrName,
String value){
AttributePredicate pred = AttributePredicate.getPredicate(funcNameToRun);
FeatureCollection resultFC = new FeatureDataset(sourceFC.getFeatureSchema());
for (Iterator i = sourceFC.iterator(); i.hasNext(); ) {
Feature f = (Feature) i.next();
Object fVal = getValue(f, attrName);
boolean predResult = pred.isTrue(fVal, value);
if (complementResult)
predResult = ! predResult;
if (predResult) {
if (createLayer) {
resultFC.add(f.clone(true));
} else {
resultFC.add(f);
}
}
}
return resultFC;
}
private Object getValue(Feature f, String attrName) {
if (attrName == ATTR_GEOMETRY_AREA) {
Geometry g = f.getGeometry();
double area = (g == null) ? 0.0 : g.getArea();
return new Double(area);
}
if (attrName == ATTR_GEOMETRY_LENGTH) {
Geometry g = f.getGeometry();
double len = (g == null) ? 0.0 : g.getLength();
return new Double(len);
}
if (attrName == ATTR_GEOMETRY_NUMPOINTS) {
Geometry g = f.getGeometry();
double len = (g == null) ? 0.0 : g.getNumPoints();
return new Double(len);
}
if (attrName == ATTR_GEOMETRY_NUMCOMPONENTS) {
Geometry g = f.getGeometry();
double len = (g == null) ? 0.0 : g.getNumGeometries();
return new Double(len);
}
if (attrName == ATTR_GEOMETRY_ISCLOSED) {
Geometry g = f.getGeometry();
if (g instanceof LineString)
return new Boolean( ((LineString) g).isClosed());
if (g instanceof MultiLineString)
return new Boolean( ((MultiLineString) g).isClosed());
return new Boolean(false);
}
if (attrName == ATTR_GEOMETRY_ISSIMPLE) {
Geometry g = f.getGeometry();
boolean bool = g.isSimple();
return new Boolean(bool);
}
if (attrName == ATTR_GEOMETRY_ISVALID) {
Geometry g = f.getGeometry();
boolean bool = g.isValid();
return new Boolean(bool);
}
if (attrName == ATTR_GEOMETRY_TYPE) {
Geometry g = f.getGeometry();
return StringUtil.classNameWithoutQualifiers(g.getClass().getName());
}
return f.getAttribute(attrName);
}
private static String LAYER = GenericNames.SOURCE_LAYER;
private static String ATTRIBUTE = I18N.get("ui.plugin.analysis.AttributeQueryPlugIn.Attribute");
private static String PREDICATE = I18N.get("ui.plugin.analysis.SpatialQueryPlugIn.Relation");
private static String VALUE = I18N.get("ui.plugin.analysis.AttributeQueryPlugIn.Value");
private static String DIALOG_COMPLEMENT = I18N.get("ui.plugin.analysis.SpatialQueryPlugIn.Complement-Result");
private static String UPDATE_SRC = I18N.get("ui.plugin.analysis.SpatialQueryPlugIn.Select-features-in-the-source-layer");
private static String CREATE_LYR = I18N.get("ui.plugin.analysis.SpatialQueryPlugIn.Create-a-new-layer-for-the-results");
private JComboBox attrComboBox;
private void setDialogValues(MultiInputDialog dialog, PlugInContext context){
//[sstein] reset for language
LAYER = GenericNames.SOURCE_LAYER;
ATTRIBUTE = I18N.get("ui.plugin.analysis.AttributeQueryPlugIn.Attribute");
PREDICATE = I18N.get("ui.plugin.analysis.SpatialQueryPlugIn.Relation");
VALUE = I18N.get("ui.plugin.analysis.AttributeQueryPlugIn.Value");
DIALOG_COMPLEMENT = I18N.get("ui.plugin.analysis.SpatialQueryPlugIn.Complement-Result");
UPDATE_SRC = I18N.get("ui.plugin.analysis.SpatialQueryPlugIn.Select-features-in-the-source-layer");
CREATE_LYR = I18N.get("ui.plugin.analysis.SpatialQueryPlugIn.Create-a-new-layer-for-the-results");
dialog.setSideBarDescription(
I18N.get("ui.plugin.analysis.AttributeQueryPlugIn.Finds-the-Source-features-which-have-attribute-values-satisfying-a-given-condition"));
//Set initial layer values to the first and second layers in the layer list.
//In #initialize we've already checked that the number of layers >= 1. [Jon Aquino]
Layer initLayer = (srcLayer == null)? context.getCandidateLayer(0) : srcLayer;
JComboBox lyrCombo = dialog.addLayerComboBox(LAYER, initLayer, context.getLayerManager());
lyrCombo.addItemListener(new LayerItemListener());
attrComboBox = dialog.addComboBox(ATTRIBUTE, attrName, functionNames, null);
dialog.addComboBox(PREDICATE, funcNameToRun, functionNames, null);
dialog.addTextField(VALUE, value, 20, null, null);
dialog.addCheckBox(DIALOG_COMPLEMENT, complementResult);
final String OUTPUT_GROUP = "OUTPUT_GROUP";
createNewLayerRB = dialog.addRadioButton(CREATE_LYR, OUTPUT_GROUP, createLayer,CREATE_LYR);
updateSourceRB = dialog.addRadioButton(UPDATE_SRC, OUTPUT_GROUP, !createLayer, UPDATE_SRC);
updateUI(initLayer);
}
private void getDialogValues(MultiInputDialog dialog) {
srcLayer = dialog.getLayer(LAYER);
attrName = dialog.getText(ATTRIBUTE);
funcNameToRun = dialog.getText(PREDICATE);
value = dialog.getText(VALUE);
complementResult = dialog.getBoolean(DIALOG_COMPLEMENT);
createLayer = dialog.getBoolean(CREATE_LYR);
}
private void updateUI(Layer lyr) {
List attrNames = null;
if (lyr != null) {
FeatureCollection fc = lyr.getFeatureCollectionWrapper();
FeatureSchema fs = fc.getFeatureSchema();
attrNames = getAttributeNames(fs);
} else {
attrNames = new ArrayList();
}
attrComboBox.setModel(new DefaultComboBoxModel(new Vector(attrNames)));
attrComboBox.setSelectedItem(attrName);
}
private static List getAttributeNames(FeatureSchema fs) {
List names = new ArrayList();
for (int i = 0; i < fs.getAttributeCount(); i++) {
if (fs.getAttributeType(i) != AttributeType.GEOMETRY)
names.add(fs.getAttributeName(i));
}
names.add(ATTR_GEOMETRY_AREA);
names.add(ATTR_GEOMETRY_LENGTH);
names.add(ATTR_GEOMETRY_NUMPOINTS);
names.add(ATTR_GEOMETRY_NUMCOMPONENTS);
names.add(ATTR_GEOMETRY_ISCLOSED);
names.add(ATTR_GEOMETRY_ISSIMPLE);
names.add(ATTR_GEOMETRY_ISVALID);
names.add(ATTR_GEOMETRY_TYPE);
return names;
}
private class LayerItemListener implements ItemListener {
public void itemStateChanged(ItemEvent e) {
updateUI((Layer) e.getItem());
}
}
}