/*
* The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
* for visualizing and manipulating spatial features with geometry and attributes.
*
* JUMP is Copyright (C) 2003 Vivid Solutions
*
* This program implements extensions to JUMP and is
* Copyright (C) 2008 Integrated Systems Analysts, Inc.
*
* 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:
*
* Integrated Systems Analysts, Inc.
* 630C Anchors St., Suite 101
* Fort Walton Beach, Florida
* USA
*
* (850)862-7321
*/
package org.openjump.core.ui.plugin.tools;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
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.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JTextField;
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.workbench.WorkbenchContext;
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.GenericNames;
import com.vividsolutions.jump.workbench.ui.LayerNamePanelProxy;
import com.vividsolutions.jump.workbench.ui.MenuNames;
import com.vividsolutions.jump.workbench.ui.MultiInputDialog;
/**
* Based on CalculateAreasAndLengthsPlugIn.
*
*/
public class AutoAssignAttributePlugIn extends AbstractPlugIn {
//TODO: translation
private static String LAYER_COMBO_BOX = GenericNames.LAYER;
private static String DEST_COMBO_BOX = "Destination attribute";
private static String SOURCE_COMBO_BOX = "Source attribute";
private static String FROM_SOURCE_CHECK_BOX = "Assign from other attribute";
private static final String A_CHECK_BOX = "invisible checkbox";
private static String AUTOINC_CHECK_BOX = "Auto-increment";
private static String INC_VALUE_EDIT_BOX = "Increment by";
private static String SELECTED_CHECK_BOX = "Selected features only";
private static String ASSIGN_VALUE_TEXT_BOX = "Assign this value";
private static String SELECTONLYONONELAYER = "Select features on only one layer";
private static String DESCRIPTION = "Assign a value from another attribute, " +
"a value, an auto-increment number or a combination of a value " +
"and an auto-increment number";
//private static String DESCRIPTION = I18N.get("org.openjump.sigle.plugin.ReplaceValuePlugIn.Description");
private int autoInc;
private Layer destinationLayer;
private FeatureSchema schema;
private String attributeName;
private String sourceAttributeName;
private int destinationAttributeIndex;
private int sourceAttributeIndex;
private AttributeType attributeType;
private boolean autoIncrement;
private int incValue;
private boolean assignFromSource;
private boolean selectedFeaturesOnly;
private String textToAssign;
private String numeric;
private JTextField incfield = null;
public void initialize(PlugInContext context) throws Exception
{
context.getFeatureInstaller().addMainMenuItem(this,
new String[] { MenuNames.TOOLS, MenuNames.TOOLS_EDIT_ATTRIBUTES},
this.getName() + "...", false, null,
this.createEnableCheck(context.getWorkbenchContext()));
DEST_COMBO_BOX = I18N.get("org.openjump.core.ui.plugin.tools.AutoAssignAttributePlugIn.Destination-attribute");
SOURCE_COMBO_BOX = I18N.get("org.openjump.core.ui.plugin.tools.AutoAssignAttributePlugIn.Source-attribute");
FROM_SOURCE_CHECK_BOX = I18N.get("org.openjump.core.ui.plugin.tools.AutoAssignAttributePlugIn.Assign-from-other-attribute");
//A_CHECK_BOX = "invisible checkbox";
AUTOINC_CHECK_BOX = I18N.get("org.openjump.core.ui.plugin.tools.AutoAssignAttributePlugIn.Auto-increment");
INC_VALUE_EDIT_BOX = I18N.get("org.openjump.core.ui.plugin.tools.AutoAssignAttributePlugIn.Increment-by");
SELECTED_CHECK_BOX = I18N.get("org.openjump.core.ui.plugin.tools.AutoAssignAttributePlugIn.Selected-features-only");
ASSIGN_VALUE_TEXT_BOX = I18N.get("org.openjump.core.ui.plugin.tools.AutoAssignAttributePlugIn.Assign-this-value");
SELECTONLYONONELAYER = I18N.get("org.openjump.core.ui.plugin.tools.AutoAssignAttributePlugIn.Select-features-on-only-one-layer");
DESCRIPTION = I18N.get("org.openjump.core.ui.plugin.tools.AutoAssignAttributePlugIn.Description");
//DESCRIPTION = I18N.get("org.openjump.sigle.plugin.ReplaceValuePlugIn.Description");
}
public String getName(){
return I18N.get("org.openjump.core.ui.plugin.tools.AutoAssignAttributePlugIn.Auto-Assign-Attribute");
}
public boolean execute(PlugInContext context) throws Exception {
MultiInputDialog dialog = prompt(context);
if (!dialog.wasOKPressed()) {
return false;
}
getDialogValues(dialog);
assignValues(context);
return true;
}
private MultiInputDialog prompt(PlugInContext context) {
final MultiInputDialog dialog =
new MultiInputDialog(context.getWorkbenchFrame(), getName(), true);
dialog.setSideBarDescription(DESCRIPTION);
dialog.addEditableLayerComboBox(
LAYER_COMBO_BOX,
null,
null,
context.getLayerManager());
initComboFields(dialog, A_CHECK_BOX, DEST_COMBO_BOX, 0);
dialog.addCheckBox(AUTOINC_CHECK_BOX, true);
incfield = dialog.addIntegerField(INC_VALUE_EDIT_BOX, 1, 4, "Auto-increment number by this value");
dialog.indentLabel(INC_VALUE_EDIT_BOX);
initComboFields(dialog, FROM_SOURCE_CHECK_BOX, SOURCE_COMBO_BOX, 1);
dialog.getCheckBox(FROM_SOURCE_CHECK_BOX).addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
dialog.getComboBox(SOURCE_COMBO_BOX).setEnabled(
dialog.getCheckBox(FROM_SOURCE_CHECK_BOX).isSelected());
boolean fromSelected = dialog.getCheckBox(FROM_SOURCE_CHECK_BOX).isSelected();
dialog.getLabel(SOURCE_COMBO_BOX).setEnabled(fromSelected);
JCheckBox checkbox = dialog.getCheckBox(AUTOINC_CHECK_BOX);
checkbox.setEnabled(!fromSelected);
incfield.setEnabled(!fromSelected);
if (fromSelected)
checkbox.setSelected(false);
}
});
initEnableChecks(dialog);
boolean selectionExists = context.getLayerViewPanel().getSelectionManager()
.getFeatureSelection().getSelectedItems().size() > 0;
dialog.addCheckBox(SELECTED_CHECK_BOX, selectionExists);
dialog.addTextField(ASSIGN_VALUE_TEXT_BOX, "", 15, null,
"Enter value to assign. Numeric portion used as start value.");
loadValues(dialog, context);
dialog.getCheckBox(A_CHECK_BOX).setVisible(false); //*LDB
dialog.setVisible(true);
if (dialog.wasOKPressed()) {
saveValues(dialog, context);
}
return dialog;
}
private void getDialogValues(MultiInputDialog dialog) {
destinationLayer = dialog.getLayer(LAYER_COMBO_BOX);
attributeName = dialog.getText(DEST_COMBO_BOX);
sourceAttributeName = dialog.getText(SOURCE_COMBO_BOX);
schema = destinationLayer.getFeatureCollectionWrapper().getFeatureSchema();
destinationAttributeIndex = schema.getAttributeIndex(attributeName);
sourceAttributeIndex = schema.getAttributeIndex(sourceAttributeName);
attributeType = schema.getAttributeType(destinationAttributeIndex);
autoIncrement = dialog.getBoolean(AUTOINC_CHECK_BOX);
incValue = dialog.getInteger(INC_VALUE_EDIT_BOX);
selectedFeaturesOnly = dialog.getBoolean(SELECTED_CHECK_BOX);
textToAssign = dialog.getText(ASSIGN_VALUE_TEXT_BOX);
numeric = parseNumber(textToAssign);
if (autoIncrement) {
if (numeric.length() == 0)
autoInc = 0;
else
autoInc = new Integer(numeric).intValue();
} else
autoInc = 0;
assignFromSource = dialog.getBoolean(FROM_SOURCE_CHECK_BOX);
}
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() + FROM_SOURCE_CHECK_BOX,
dialog.getCheckBox(FROM_SOURCE_CHECK_BOX).isSelected());
blackboard.put(
namespace() + DEST_COMBO_BOX,
dialog.getComboBox(DEST_COMBO_BOX).getSelectedItem());
blackboard.put(
namespace() + SOURCE_COMBO_BOX,
dialog.getComboBox(SOURCE_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(FROM_SOURCE_CHECK_BOX),
blackboard.get(namespace() + FROM_SOURCE_CHECK_BOX, false));
dialog.getComboBox(DEST_COMBO_BOX).setSelectedItem(
CollectionUtil.ifNotIn(
blackboard.get(namespace() + DEST_COMBO_BOX),
GUIUtil.items(dialog.getComboBox(DEST_COMBO_BOX)),
dialog.getComboBox(DEST_COMBO_BOX).getSelectedItem()));
dialog.getComboBox(SOURCE_COMBO_BOX).setSelectedItem(
CollectionUtil.ifNotIn(
blackboard.get(namespace() + SOURCE_COMBO_BOX),
GUIUtil.items(dialog.getComboBox(SOURCE_COMBO_BOX)),
dialog.getComboBox(SOURCE_COMBO_BOX).getSelectedItem()));
}
private String namespace() {
return getClass().getName() + " - ";
}
private void initEnableChecks(final MultiInputDialog dialog) {
dialog
.addEnableChecks(
SOURCE_COMBO_BOX,
Arrays
.asList(
new Object[] {
new EnableCheck() {
public String check(JComponent component) {
return dialog.getBoolean(FROM_SOURCE_CHECK_BOX)
&& dialog.getText(DEST_COMBO_BOX).equals(
dialog.getText(SOURCE_COMBO_BOX))
? "Source and destination attributes must be different"
: null;
}
}
}));
}
private String attributeName(List attributeNames, int preferredIndex) {
return (String) attributeNames.get(
attributeNames.size() > preferredIndex ? preferredIndex : 0);
}
private void initComboFields(
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
.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(String d);
}
private Map typeToConverterMap = new HashMap() {
{
put(AttributeType.STRING, new Converter() {
public Object convert(String d) {
return d;
}
});
put(AttributeType.INTEGER, new Converter() {
public Object convert(String d) {
String s = parseNumber(d);
if (s.length() == 0)
return new Integer(0);
return new Integer(s);
}
});
put(AttributeType.DOUBLE, new Converter() {
public Object convert(String d) {
String s = parseNumber(d);
if (s.length() == 0)
return new Double(0);
return new Double(parseNumber(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 String parseNumber(String assignText) {
int b=0; int e=0;
for (int i=0; i<assignText.length(); i++) {
if ( Character.isDigit(assignText.charAt(i)) ) {
b=i; e=i;
while ( e < assignText.length() && Character.isDigit(assignText.charAt(e)) )
e++;
return assignText.substring(b, e);
}
}
return "";
}
private void assignValues(PlugInContext context) {
Iterator iterator;
if (selectedFeaturesOnly) {
Collection layers = context.getLayerViewPanel().getSelectionManager()
.getLayersWithSelectedItems();
if (layers.size() > 1) {
context.getWorkbenchFrame().warnUser(SELECTONLYONONELAYER);
}
iterator = context.getLayerViewPanel().getSelectionManager()
.getFeaturesWithSelectedItems().iterator();
} else {
iterator = destinationLayer.getFeatureCollectionWrapper().getFeatures().iterator();
}
for (Iterator i = iterator; i.hasNext(); ) {
Feature feature = (Feature) i.next();
String s = textToAssign;
if (autoIncrement) {
String value = "" + autoInc;
autoInc += incValue;
if (numeric.length() == 0)
s = value;
else
s = textToAssign.replaceFirst(numeric, value);
} else {
if (assignFromSource) {
s = feature.getAttribute(sourceAttributeIndex).toString();
if (numeric.length() > 0)
s = textToAssign.replaceFirst(numeric, s);
}
}
Object object = ((Converter) typeToConverterMap.get(attributeType)).convert(s);
feature.setAttribute( destinationAttributeIndex, object);
}
}
public MultiEnableCheck createEnableCheck(WorkbenchContext workbenchContext) {
EnableCheckFactory checkFactory = new EnableCheckFactory(workbenchContext);
return new MultiEnableCheck()
.add(checkFactory.createWindowWithLayerManagerMustBeActiveCheck())
.add(checkFactory.createAtLeastNLayersMustExistCheck(1))
.add(checkFactory.createAtLeastNLayersMustBeEditableCheck(1));
}
}