/* * 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.ActionEvent; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Vector; import javax.swing.DefaultComboBoxModel; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jump.I18N; import com.vividsolutions.jump.feature.AttributeType; import com.vividsolutions.jump.feature.Feature; import com.vividsolutions.jump.feature.FeatureSchema; import com.vividsolutions.jump.util.Blackboard; import com.vividsolutions.jump.util.CollectionUtil; import com.vividsolutions.jump.util.StringUtil; import com.vividsolutions.jump.workbench.WorkbenchContext; import com.vividsolutions.jump.workbench.model.FeatureEventType; import com.vividsolutions.jump.workbench.model.Layer; import com.vividsolutions.jump.workbench.plugin.AbstractPlugIn; import com.vividsolutions.jump.workbench.plugin.EnableCheck; import com.vividsolutions.jump.workbench.plugin.EnableCheckFactory; import com.vividsolutions.jump.workbench.plugin.MultiEnableCheck; import com.vividsolutions.jump.workbench.plugin.PlugInContext; import com.vividsolutions.jump.workbench.ui.GUIUtil; import com.vividsolutions.jump.workbench.ui.LayerNamePanelProxy; import com.vividsolutions.jump.workbench.ui.MenuNames; import com.vividsolutions.jump.workbench.ui.MultiInputDialog; import com.vividsolutions.jump.workbench.ui.WorkbenchFrame; import com.vividsolutions.jump.workbench.ui.images.IconLoader; import com.vividsolutions.jump.workbench.ui.plugin.FeatureInstaller; /** * Calculates areas and lengths from information obtained * from the user via a {@link MultiInputDialog}. * */ public class CalculateAreasAndLengthsPlugIn extends AbstractPlugIn { private String LAYER_COMBO_BOX = I18N.get("ui.plugin.analysis.CalculateAreasAndLengthsPlugIn.layer"); private String AREA_COMBO_BOX = I18N.get("ui.plugin.analysis.CalculateAreasAndLengthsPlugIn.area-attribute-name"); private String LENGTH_COMBO_BOX = I18N.get("ui.plugin.analysis.CalculateAreasAndLengthsPlugIn.length-attribute-name"); private String LENGTH_CHECK_BOX = I18N.get("ui.plugin.analysis.CalculateAreasAndLengthsPlugIn.calculate-length"); private String AREA_CHECK_BOX = I18N.get("ui.plugin.analysis.CalculateAreasAndLengthsPlugIn.calculate-area"); public void initialize(PlugInContext context) throws Exception { FeatureInstaller featureInstaller = new FeatureInstaller(context.getWorkbenchContext()); featureInstaller.addMainMenuItem( this, new String[] {MenuNames.TOOLS, MenuNames.TOOLS_EDIT_ATTRIBUTES}, this.getName() + "...", false, //checkbox null, //icon createEnableCheck(context.getWorkbenchContext())); } public boolean execute(PlugInContext context) throws Exception { //[sstein, 16.07.2006] set again to obtain correct language LAYER_COMBO_BOX = I18N.get("ui.plugin.analysis.CalculateAreasAndLengthsPlugIn.layer"); AREA_COMBO_BOX = I18N.get("ui.plugin.analysis.CalculateAreasAndLengthsPlugIn.area-attribute-name"); LENGTH_COMBO_BOX = I18N.get("ui.plugin.analysis.CalculateAreasAndLengthsPlugIn.length-attribute-name"); LENGTH_CHECK_BOX = I18N.get("ui.plugin.analysis.CalculateAreasAndLengthsPlugIn.calculate-length"); AREA_CHECK_BOX = I18N.get("ui.plugin.analysis.CalculateAreasAndLengthsPlugIn.calculate-area"); //<<TODO>> Undo? [Jon Aquino] //<<TODO>> Two-phase commit? [Jon Aquino] MultiInputDialog dialog = prompt(context); if (!dialog.wasOKPressed()) { return false; } if (dialog.getBoolean(AREA_CHECK_BOX)) { updateAreas(dialog.getLayer(LAYER_COMBO_BOX), dialog.getText(AREA_COMBO_BOX)); } if (dialog.getBoolean(LENGTH_CHECK_BOX)) { updateLengths( dialog.getLayer(LAYER_COMBO_BOX), dialog.getText(LENGTH_COMBO_BOX)); } context.getLayerManager().fireFeaturesChanged( dialog.getLayer(LAYER_COMBO_BOX).getFeatureCollectionWrapper().getFeatures(), FeatureEventType.ATTRIBUTES_MODIFIED, dialog.getLayer(LAYER_COMBO_BOX)); return true; } private MultiInputDialog prompt(PlugInContext context) { final MultiInputDialog dialog = new MultiInputDialog(context.getWorkbenchFrame(), getName(), true); dialog.addEditableLayerComboBox( LAYER_COMBO_BOX, null, null, context.getLayerManager()); initFields(dialog, AREA_CHECK_BOX, AREA_COMBO_BOX, 0); initFields(dialog, LENGTH_CHECK_BOX, LENGTH_COMBO_BOX, 1); initEnableChecks(dialog); loadValues(dialog, context); dialog.setVisible(true); if (dialog.wasOKPressed()) { saveValues(dialog, context); } return dialog; } private void saveValues(MultiInputDialog dialog, PlugInContext context) { Blackboard blackboard = context.getLayerManager().getBlackboard(); blackboard.put(namespace() + LAYER_COMBO_BOX, dialog.getLayer(LAYER_COMBO_BOX)); blackboard.put( namespace() + AREA_CHECK_BOX, dialog.getCheckBox(AREA_CHECK_BOX).isSelected()); blackboard.put( namespace() + LENGTH_CHECK_BOX, dialog.getCheckBox(LENGTH_CHECK_BOX).isSelected()); blackboard.put( namespace() + AREA_COMBO_BOX, dialog.getComboBox(AREA_COMBO_BOX).getSelectedItem()); blackboard.put( namespace() + LENGTH_COMBO_BOX, dialog.getComboBox(LENGTH_COMBO_BOX).getSelectedItem()); } private void loadValues(MultiInputDialog dialog, PlugInContext context) { Blackboard blackboard = context.getLayerManager().getBlackboard(); dialog.getComboBox(LAYER_COMBO_BOX).setSelectedItem( CollectionUtil.ifNotIn( blackboard.get(namespace() + LAYER_COMBO_BOX), GUIUtil.items(dialog.getComboBox(LAYER_COMBO_BOX)), candidateLayer(context))); GUIUtil.setSelectedWithClick( dialog.getCheckBox(AREA_CHECK_BOX), blackboard.get(namespace() + AREA_CHECK_BOX, true)); GUIUtil.setSelectedWithClick( dialog.getCheckBox(LENGTH_CHECK_BOX), blackboard.get(namespace() + LENGTH_CHECK_BOX, true)); dialog.getComboBox(AREA_COMBO_BOX).setSelectedItem( CollectionUtil.ifNotIn( blackboard.get(namespace() + AREA_COMBO_BOX), GUIUtil.items(dialog.getComboBox(AREA_COMBO_BOX)), dialog.getComboBox(AREA_COMBO_BOX).getSelectedItem())); dialog.getComboBox(LENGTH_COMBO_BOX).setSelectedItem( CollectionUtil.ifNotIn( blackboard.get(namespace() + LENGTH_COMBO_BOX), GUIUtil.items(dialog.getComboBox(LENGTH_COMBO_BOX)), dialog.getComboBox(LENGTH_COMBO_BOX).getSelectedItem())); } private String namespace() { return getClass().getName() + " - "; } private void initEnableChecks(final MultiInputDialog dialog) { dialog .addEnableChecks( LENGTH_COMBO_BOX, Arrays .asList( new Object[] { new EnableCheck() { public String check(JComponent component) { return dialog.getBoolean(AREA_CHECK_BOX) && dialog.getBoolean(LENGTH_CHECK_BOX) && dialog.getText(AREA_COMBO_BOX).equals( dialog.getText(LENGTH_COMBO_BOX)) ? I18N.get("ui.plugin.analysis.CalculateAreasAndLengthsPlugIn.area-and-length-attribute-names-must-be-different") : null; } } })); } private String attributeName(List attributeNames, int preferredIndex) { return (String) attributeNames.get( attributeNames.size() > preferredIndex ? preferredIndex : 0); } private void initFields( final MultiInputDialog dialog, final String checkBoxFieldName, final String comboBoxFieldName, final int preferredCandidateAttributeIndex) { dialog.addCheckBox(checkBoxFieldName, true); dialog.addComboBox(comboBoxFieldName, null, new ArrayList(), null); dialog.getComboBox(LAYER_COMBO_BOX).addActionListener(new ActionListener() { private Layer lastLayer = null; public void actionPerformed(ActionEvent e) { Layer newLayer = (Layer) dialog.getComboBox(LAYER_COMBO_BOX).getSelectedItem(); if (lastLayer == newLayer) { return; } lastLayer = newLayer; dialog.getComboBox(comboBoxFieldName).setModel( new DefaultComboBoxModel( new Vector(candidateAttributeNames(newLayer)))); if (!candidateAttributeNames(newLayer).isEmpty()) { dialog.getComboBox(comboBoxFieldName).setSelectedItem( attributeName( candidateAttributeNames(newLayer), preferredCandidateAttributeIndex)); } } }); dialog.getCheckBox(checkBoxFieldName).addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { dialog.getComboBox(comboBoxFieldName).setEnabled( dialog.getCheckBox(checkBoxFieldName).isSelected()); dialog.getLabel(comboBoxFieldName).setEnabled( dialog.getCheckBox(checkBoxFieldName).isSelected()); } }); dialog .addEnableChecks( comboBoxFieldName, Arrays .asList( new Object[] { new EnableCheck() { public String check(JComponent component) { return dialog.getBoolean(checkBoxFieldName) && dialog.getComboBox(comboBoxFieldName).getItemCount() == 0 ? "Layer has no string, integer, or double attributes" : null; } } })); dialog.indentLabel(comboBoxFieldName); } private Layer candidateLayer(PlugInContext context) { if (context.getActiveInternalFrame() instanceof LayerNamePanelProxy) { Layer[] selectedLayers = context.getSelectedLayers(); for (int i = 0; i < selectedLayers.length; i++) { if (selectedLayers[i].isEditable()) { return selectedLayers[i]; } } } return (Layer) context.getLayerManager().getEditableLayers().iterator().next(); } private static interface Converter { public Object convert(double d); } private Map typeToConverterMap = new HashMap() { { put(AttributeType.STRING, new Converter() { public Object convert(double d) { return "" + d; } }); put(AttributeType.INTEGER, new Converter() { public Object convert(double d) { return new Integer((int) d); } }); put(AttributeType.DOUBLE, new Converter() { public Object convert(double d) { return new Double(d); } }); } }; private List candidateAttributeNames(Layer layer) { ArrayList candidateAttributeNames = new ArrayList(); FeatureSchema schema = layer.getFeatureCollectionWrapper().getFeatureSchema(); for (int i = 0; i < schema.getAttributeCount(); i++) { if (typeToConverterMap.keySet().contains(schema.getAttributeType(i))) { candidateAttributeNames.add(schema.getAttributeName(i)); } } return candidateAttributeNames; } private static interface Op { public double compute(Geometry g); } private void updateLengths(Layer layer, String attributeName) { update(layer, attributeName, new Op() { public double compute(Geometry g) { return g.getLength(); } }); } private void update(Layer layer, String attributeName, Op op) { int attributeIndex = layer.getFeatureCollectionWrapper().getFeatureSchema().getAttributeIndex( attributeName); AttributeType attributeType = layer.getFeatureCollectionWrapper().getFeatureSchema().getAttributeType( attributeIndex); for (Iterator i = layer.getFeatureCollectionWrapper().getFeatures().iterator(); i.hasNext(); ) { Feature feature = (Feature) i.next(); feature.setAttribute( attributeIndex, convert(op.compute(feature.getGeometry()), attributeType)); } } private Object convert(double d, AttributeType attributeType) { return ((Converter) typeToConverterMap.get(attributeType)).convert(d); } private void updateAreas(Layer layer, String attributeName) { update(layer, attributeName, new Op() { public double compute(Geometry g) { return g.getArea(); } }); } public MultiEnableCheck createEnableCheck(WorkbenchContext workbenchContext) { EnableCheckFactory checkFactory = new EnableCheckFactory(workbenchContext); return new MultiEnableCheck() .add(checkFactory.createWindowWithLayerManagerMustBeActiveCheck()) .add(checkFactory.createAtLeastNLayersMustExistCheck(1)) .add(checkFactory.createAtLeastNLayersMustBeEditableCheck(1)); } }