/*
* uDig - User Friendly Desktop Internet GIS client http://udig.refractions.net (C) 2004,
* Refractions Research Inc. 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 net.refractions.udig.wps.internal.ui;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import net.refractions.udig.project.ui.internal.properties.FeaturePropertySource;
import net.refractions.udig.wps.internal.Messages;
import org.eclipse.ui.views.properties.IPropertyDescriptor;
import org.eclipse.ui.views.properties.IPropertySource2;
import org.eclipse.ui.views.properties.PropertyDescriptor;
import org.eclipse.ui.views.properties.PropertySheetEntry;
import org.eclipse.ui.views.properties.TextPropertyDescriptor;
import org.geotools.data.Parameter;
import org.opengis.feature.simple.SimpleFeature;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.io.WKTReader;
import com.vividsolutions.jts.io.WKTWriter;
/**
* An adaptor to let Parameters be placed in a property sheet for editing.
*
* @author GDavis, Refractions Research
* @since 1.1.0
*/
public class InputParamPropertySource implements IPropertySource2 {
private Map<String, Parameter< ? >> parameterInfo;
private Map<String, Object> paramValues;
private Map<String, Object> originalParamValues;
//IPropertyDescriptor[] descriptors;
private Map<String, IPropertyDescriptor> descriptors;
private final String keySuffix = "_LIST_";
/** Are the attributes editable in cell editors (default) */
private boolean editable = true;
public InputParamPropertySource(Map<String, Parameter< ? >> p, Map<String, Object> value) {
init( p, value, editable);
}
public InputParamPropertySource( Map<String, Parameter< ? >> p, Map<String, Object> value, boolean edit ) {
init( p, value, edit);
}
private void init( Map<String, Parameter< ? >> p, Map<String, Object> value, boolean edit ) {
this.parameterInfo = p;
this.paramValues = value;
this.originalParamValues = value;
this.editable = edit;
}
public Object getEditableValue() {
if (this.paramValues == null) {
this.paramValues = new HashMap<String, Object>();
}
return this.paramValues;
}
public IPropertyDescriptor[] getPropertyDescriptors() {
if (this.descriptors == null && this.parameterInfo == null) {
return new PropertyDescriptor[]{new PropertyDescriptor("ID",Messages.WPSProcessView_noInputs)}; //$NON-NLS-1$
}
// if we don't have any descriptors yet, create the base ones
if (this.descriptors == null) {
this.descriptors = new HashMap<String, IPropertyDescriptor>();
Iterator<Entry<String, Parameter< ? >>> iterator = this.parameterInfo.entrySet().iterator();
while (iterator.hasNext()) {
Entry<String, Parameter< ? >> entry = iterator.next();
Parameter< ? > param = entry.getValue();
TextPropertyDescriptor tpd = null;
int i=1;
String key;
// If this parameter supports more than 1 value, then
// create a category for them. Also, any param that
// can have more than 1 value will have a key appended by
// "_LIST_X" where X is a number of 1 or greater. This needs to be
// caught when searching for values based on their key.
if (param.maxOccurs == -1 || param.maxOccurs > 1 || param.minOccurs > 1) {
key = new String(entry.getKey()+this.keySuffix+i);
tpd = new TextPropertyDescriptor(key, new String(param.title.toString()+" "+i)); //$NON-NLS-1$
tpd.setCategory(param.title.toString());
}
else {
key = entry.getKey();
tpd = new TextPropertyDescriptor(entry.getKey(),param.title.toString());
}
this.descriptors.put(key, tpd);
// if this parameter has a min requirement that is more than 1, create
// a property descriptor for each in the list of min
while (i < param.minOccurs) {
i++;
key = new String(entry.getKey()+this.keySuffix+i);
tpd = new TextPropertyDescriptor(key, new String(param.title.toString()+" "+i)); //$NON-NLS-1$
tpd.setCategory(param.title.toString());
this.descriptors.put(key, tpd);
}
}
}
// return an array of descriptors
return (IPropertyDescriptor[])this.descriptors.values().toArray(
new IPropertyDescriptor[this.descriptors.size()]);
}
public Object getPropertyValue( Object id ) {
if (this.parameterInfo == null) {
return null;
}
// loop through each parameter and find the object id
String idString = (String) id;
String baseId = getBaseKey(idString);
Iterator<Entry<String, Parameter< ? >>> iterator = this.parameterInfo.entrySet().iterator();
while (iterator.hasNext()) {
Entry<String, Parameter< ? >> entry = iterator.next();
if (baseId.equals(entry.getKey())) {
Parameter< ? > param = entry.getValue();
return getParamValue(param, idString);
}
}
return null;
}
/**
* Because input param keys can be appended by "_LIST_X" where X is a number 1 or
* greater, we need to be able to fetch the base key name.
*
* @param idString
* @return base key name with the "_LIST_X" removed
*/
private String getBaseKey( String idString ) {
int indexOf = idString.indexOf(this.keySuffix);
if (indexOf > -1 && indexOf > 0) {
idString = idString.substring(0, indexOf);
}
return idString;
}
/**
* Check if the given param has a value set, and return it
*
* @param param
* @param key the key of the input value
* @return the param's value, or null if there isn't one
*/
private Object getParamValue( Parameter< ? > param, String key ) {
if (param == null || this.paramValues == null) {
return Messages.WPSPropertySource_clickToAdd;
}
String baseId = getBaseKey(key);
Iterator<Entry<String, Object>> iterator = this.paramValues.entrySet().iterator();
while (iterator.hasNext()) {
Entry<String, Object> entry = iterator.next();
if (baseId.equals(entry.getKey())) {
Object obj = entry.getValue();
// if the value is a Map, get the obj from there with the
// original key (not the base key)
if (obj instanceof Map) {
obj = ((Map)obj).get(key);
if (obj == null) {
return Messages.WPSPropertySource_clickToAdd;
}
return getValue(obj);
}
return getValue(obj);
}
}
return Messages.WPSPropertySource_clickToAdd;
}
/**
* Determine what value to return by the type of object given
*
* @param obj
* @return value for editing
*/
private Object getValue( Object obj ) {
if (obj instanceof Geometry) {
return geomToText((Geometry)obj);
//return new GeomPropertySource((Geometry)obj);
}
else if (obj instanceof SimpleFeature) {
return new FeaturePropertySource((SimpleFeature)obj);
}
else if (obj == null) {
return null;
}
// default to string value
return obj.toString();
}
private Object geomToText(Geometry geom) {
WKTWriter writer = new WKTWriter();
String text = writer.write(geom);
text = text.replaceAll("[\\n\\r\\t]", " ");
return text;
}
public boolean isPropertySet( Object id ) {
// TODO: check for the given property
if (this.originalParamValues != null) {
return true;
}
return false;
}
public void resetPropertyValue( Object id ) {
// TODO: reset just the given property
this.paramValues = this.originalParamValues;
}
public void setPropertyValue( Object id, Object value ) {
// loop through each parameter and find the object id
String idString = (String) id;
String baseId = getBaseKey(idString);
Iterator<Entry<String, Parameter< ? >>> iterator = this.parameterInfo.entrySet().iterator();
while (iterator.hasNext()) {
Entry<String, Parameter< ? >> entry = iterator.next();
if (baseId.equals(entry.getKey())) {
Parameter< ? > param = entry.getValue();
setParamValue(param, value, idString);
}
}
}
/**
* Set the given param's value in the corresponding value map
*
* @param param parameter to set
* @param value to set
* @param key
*/
private void setParamValue( Parameter< ? > param, Object value, String key ) {
if (param == null) {
return;
}
if (this.paramValues == null) {
this.paramValues = new HashMap<String, Object>();
}
// if the param values already has a value for this key and it's a
// map, update that map
Map<String, Object> values = null;
Object object = this.paramValues.get(param.key);
if (object != null && object instanceof Map) {
values = ((Map<String, Object>)object);
}
else {
values = new HashMap<String, Object>();
}
// Our value is going to be a String since everything is using a
// TextPropertySource, so figure out what sort of object to make from
// it.
try {
if (param.type == Geometry.class) {
WKTReader reader = new WKTReader( new GeometryFactory() );
value = reader.read((String)value);
values.put(key, value);
}
else if (param.type == Double.class) {
value = new Double((String)value);
values.put(key, value);
}
else if (param.type == Integer.class) {
value = new Integer((String)value);
values.put(key, value);
}
} catch (Exception e) {
// invalid WKT/Double/Int, reset the text back and return
return;
}
this.paramValues.put(param.key, values);
}
public boolean isPropertyResettable( Object id ) {
return true;
}
public Map<String, Object> getParamValues() {
return this.paramValues;
}
/**
* Add a new descriptor based on the selection given
*
* @param currentSelection
*/
public void addNewDescriptor(PropertySheetEntry currentSelection) {
if (currentSelection == null) {
return;
}
// Determine the info we need to add a new descriptor based on the given
// selection object
String category = currentSelection.getCategory();
String displayName = currentSelection.getDisplayName();
String lookupname = displayName;
if (category != null && !category.equals("")) { //$NON-NLS-1$
lookupname = category;
}
Parameter< ? > param = getParamFromName(lookupname);
if (param != null) {
// figure out what is the next key that should be used
String base = new String(param.key+this.keySuffix);
int i = 1;
String key = new String(base+i);
while (this.descriptors.containsKey(key)) {
i++;
key = new String(base+i);
}
// add a new descriptor
TextPropertyDescriptor tpd = new TextPropertyDescriptor(key, new String(param.title.toString()+" "+i)); //$NON-NLS-1$
tpd.setCategory(category);
this.descriptors.put(key, tpd);
}
}
/**
* Lookup the parameter from the given name
*
* @param lookupname
* @return param that matches
*/
public Parameter< ? > getParamFromName( String lookupname ) {
if (lookupname == null) {
return null;
}
Iterator<Entry<String, Parameter< ? >>> iterator = this.parameterInfo.entrySet().iterator();
while (iterator.hasNext()) {
Entry<String, Parameter< ? >> entry = iterator.next();
Parameter< ? > param = entry.getValue();
if (param.title.toString().equals(lookupname)) {
return param;
}
}
return null;
}
/**
* Delete any descriptor and matching input value for the given display name
*
* @param lookupname
* @return true if it was deleted, false if nothing was deleted
*/
public boolean deleteFromDisplayName( String lookupname ) {
if (lookupname == null) {
return false;
}
Iterator<Entry<String, IPropertyDescriptor>> iterator = this.descriptors.entrySet().iterator();
while (iterator.hasNext()) {
Entry<String, IPropertyDescriptor> entry = iterator.next();
IPropertyDescriptor descr = entry.getValue();
if (descr.getDisplayName().equals(lookupname)) {
// delete the descriptor by exact key name
String key = entry.getKey();
this.descriptors.remove(key);
// find the input param from the category key name and delete
// from its internal map by the exact name
String baseKey = getBaseKey(key);
if (baseKey != null && !baseKey.equals("")) { //$NON-NLS-1$
Object object = this.paramValues.get(baseKey);
if (object != null && object instanceof Map) {
Map<String, Object> values = (Map<String, Object>) object;
values.remove(key);
}
}
return true;
}
}
return false;
}
/**
* Return the number of items already existing in the given category
*
* @param cat
* @return number of items in cat
*/
public int getCategoryCount(String cat) {
if (cat == null || cat.equals("")) { //$NON-NLS-1$
return 0;
}
Iterator<Entry<String, IPropertyDescriptor>> iterator = this.descriptors.entrySet().iterator();
int count = 0;
while (iterator.hasNext()) {
Entry<String, IPropertyDescriptor> next = iterator.next();
IPropertyDescriptor descr = next.getValue();
if (cat.equals(descr.getCategory())) {
count++;
}
}
return count;
}
/**
* Find the first property id (key) that matches the given display name
*
* @param displayName
* @return first matching property id, or null if not found
*/
public String getPropertyIdFromDisplayName( String displayName ) {
if (displayName == null) {
return null;
}
Iterator<Entry<String, IPropertyDescriptor>> iterator = this.descriptors.entrySet().iterator();
while (iterator.hasNext()) {
Entry<String, IPropertyDescriptor> entry = iterator.next();
IPropertyDescriptor descr = entry.getValue();
if (descr.getDisplayName().equals(displayName)) {
return entry.getKey();
}
}
return null;
}
}