package org.openjump.core.ui.plugin.queries; import java.math.BigDecimal; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.Iterator; import java.util.List; import java.util.regex.Pattern; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryCollection; import com.vividsolutions.jump.feature.Feature; import com.vividsolutions.jump.feature.FeatureCollection; import com.vividsolutions.jump.util.FlexibleDateParser; import com.vividsolutions.jump.workbench.model.Layer; import com.vividsolutions.jump.workbench.plugin.PlugInContext; /** * Condition * @author Michael MICHAUD * @version 0.2.2 * version 0.2.2 (2010-01-27) * added Date management * better null handling * version 0.2.1 (2007-08-10) * version 0.2 (2005-10-16) */ public class Condition { //private static final SimpleDateFormat DATE_PARSER = new SimpleDateFormat(); private static final SimpleDateFormat[] DATE_PARSERS = new SimpleDateFormat[]{ new SimpleDateFormat(), new SimpleDateFormat("dd/MM/yy"), new SimpleDateFormat("dd/MM/yyyy"), new SimpleDateFormat("dd-MM-yy"), new SimpleDateFormat("dd-MM-yyyy"), new SimpleDateFormat("yyyy-MM-dd"), new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"), new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss"), new SimpleDateFormat("yyyy") }; private static final FlexibleDateParser FLEXIBLE_DATE_PARSER = new FlexibleDateParser(); QueryDialog query; Function ft; Operator op; Pattern pattern; // only used for match & find functions PlugInContext context; public Condition(QueryDialog query, PlugInContext context) { this.query = query; this.ft=query.function; this.op=query.operator; if (op==Operator.MATC || op==Operator.FIND) { if (query.caseSensitive.getState()) pattern = Pattern.compile((String)query.valueCB.getSelectedValue()); else pattern = Pattern.compile((String)query.valueCB.getSelectedValue(), Pattern.CASE_INSENSITIVE); } this.context = context; } public String toString() { String att = query.attribute.trim().equals("")?"GEOMETRY":query.attribute; String func = ft.toString().trim().equals("")?"":"."+ft; return "" + att + func + " " + op + " \"" + query.valueCB.getSelectedValue() + "\""; } public boolean test(Feature feature) throws Exception { Object o = null; //System.out.print("Nature de l'attribut : "); if(query.attributeType=='G') { //System.out.println(" geometrique"); //System.out.println("Operator = " + op); o = feature.getGeometry(); if(ft.type=='G') return test(gfunction((Geometry)o)); else if(ft.type=='N') return test(nfunction((Geometry)o)); else if(ft.type=='B') return test(bfunction((Geometry)o)); else return false; } else { // System.out.println(" semantique"); // attributes which does not exist for this feature must have // been eliminated before the test procedure // (see QueryDialog#executeQuery()) o = feature.getAttribute(query.attribute); // [mmichaud 2010-01-25] added null case processing if (ft == Function.ISNULL) return test(o==null); if (o == null) { // Here, we assume that the user consider "null" different from // any user input in the value combobox except if (op == Operator.NE || op == Operator.BNE || op == Operator.DIFF) { if (query.valueCB.getSelectedValue().toString().trim().length()==0) { return false; } else return true; } if (op == Operator.EQ || op == Operator.BEQ || op == Operator.EQUA) { if (query.valueCB.getSelectedValue().toString().trim().length()==0) { return true; } else return false; } // Here, we assume that user would like to have // true for name = "" if name = null // true for name <> "A" if name = null if(ft.type == 'S') return test(sfunction("")); else if(ft.type == 'N') return test(nfunction("")); } if(o instanceof Boolean) return test(((Boolean)o).booleanValue()); else if(o instanceof Integer) return test(((Integer)o).doubleValue()); else if(o instanceof Long) return test(((Long)o).doubleValue()); else if(o instanceof Double) return test(((Double)o).doubleValue()); else if(o instanceof BigDecimal) return test(((BigDecimal)o).doubleValue()); else if(o instanceof Date) return test(dfunction((Date)o)); else if(o instanceof String && ft.type == 'S') return test(sfunction((String)o)); else if(o instanceof String && ft.type == 'N') return test(nfunction((String)o)); else return false; } } private boolean test(boolean b) throws Exception { boolean value = query.valueCB.getSelectedIndex()==0?true:false; if (b==value && op==Operator.BEQ) return true; else if (b!=value && op==Operator.BNE) return true; else return false; } private boolean test(double d) throws Exception { double value = Double.parseDouble((String)query.valueCB.getSelectedValue()); if (op==Operator.EQ && d==value) return true; else if (op==Operator.NE && d!=value) return true; else if (op==Operator.LT && d<value) return true; else if (op==Operator.GT && d>value) return true; else if (op==Operator.LE && d<=value) return true; else if (op==Operator.GE && d>=value) return true; else return false; } private boolean test(Date d) throws Exception { Date value = null; for (SimpleDateFormat sdf : DATE_PARSERS) { try {value = sdf.parse((String)query.valueCB.getSelectedValue());} catch(Exception e){} if (value != null) break; } if (value == null) { try {value = FLEXIBLE_DATE_PARSER.parse((String)query.valueCB.getSelectedValue(), true);} catch(Exception e){} } if (op==Operator.EQ && d==value) return true; else if (op==Operator.NE && d!=value) return true; else if (op==Operator.EQ && d.equals(value)) return true; else if (op==Operator.NE && !d.equals(value)) return true; else if (op==Operator.LT && d.before(value)) return true; else if (op==Operator.GT && d.after(value)) return true; else if (op==Operator.LE && (d.before(value) || d.equals(value))) return true; else if (op==Operator.GE && (d.after(value) || d.equals(value))) return true; else return false; } private boolean test(String s) throws Exception { String value = (String)query.valueCB.getSelectedValue(); if (query.caseSensitive.getState()) { if (op==Operator.EQUA) return s.equals(value); else if (op==Operator.DIFF) return !s.equals(value); else if (op==Operator.STAR) return s.startsWith(value); else if (op==Operator.ENDS) return s.endsWith(value); else if (op==Operator.MATC) return pattern.matcher(s).matches(); else if (op==Operator.FIND) return pattern.matcher(s).find(); else if (op==Operator.BEFO) return s.compareTo(value)<=0; else if (op==Operator.AFTE) return s.compareTo(value)>=0; else return false; } else { if (op==Operator.EQUA) return s.equalsIgnoreCase(value); else if (op==Operator.DIFF) return !s.equalsIgnoreCase(value); else if (op==Operator.STAR) return s.toUpperCase().startsWith(value.toUpperCase()); else if (op==Operator.ENDS) return s.toUpperCase().endsWith(value.toUpperCase()); else if (op==Operator.MATC) return pattern.matcher(s).matches(); else if (op==Operator.FIND) return pattern.matcher(s).find(); else if (op==Operator.BEFO) return s.compareToIgnoreCase(value)<=0; else if (op==Operator.AFTE) return s.compareToIgnoreCase(value)>=0; else return false; } } private boolean test(Geometry g) throws Exception { int pos = query.valueCB.getSelectedIndex(); // Target Geometry is the selection // System.out.println("position de la valeur selectionnee : " + pos); // pos 1 = selected features case if (pos == QueryDialog.SELECTION) { for (Iterator it = query.selection.iterator() ; it.hasNext() ;) { Geometry p = (Geometry)it.next(); if (op==Operator.INTER && g.intersects(p)) return true; else if (op==Operator.CONTA && g.contains(p)) return true; else if (op==Operator.WITHI && g.within(p)) return true; else if (op==Operator.WSTRI && g.relate(p, "TFFTFF***")) return true; else if (op==Operator.WDIST && g.distance(p)<op.arg) return true; else if (op==Operator.TOUCH && g.touches(p)) return true; else if (op==Operator.CROSS && g.crosses(p)) return true; else if (op==Operator.OVERL && g.overlaps(p)) return true; else if (op==Operator.DISJO && g.disjoint(p)) return true; else; } return false; } // pos 2 = selected layers case else if (pos == QueryDialog.SELECTED_LAYERS) { Layer[] ll = context.getLayerNamePanel().getSelectedLayers(); for (int i = 0 ; i < ll.length ; i++) { FeatureCollection fc = ll[i].getFeatureCollectionWrapper(); for (Iterator it = fc.iterator() ; it.hasNext() ;) { Geometry p = ((Feature)it.next()).getGeometry(); if (op==Operator.INTER && g.intersects(p)) return true; else if (op==Operator.CONTA && g.contains(p)) return true; else if (op==Operator.WITHI && g.within(p)) return true; else if (op==Operator.WSTRI && g.relate(p, "TFFTFF***")) return true; else if (op==Operator.WDIST && g.distance(p)<op.arg) return true; else if (op==Operator.TOUCH && g.touches(p)) return true; else if (op==Operator.CROSS && g.crosses(p)) return true; else if (op==Operator.OVERL && g.overlaps(p)) return true; else if (op==Operator.DISJO && g.disjoint(p)) return true; else; } return false; } } // pos 0 = all layers case else if (pos == QueryDialog.ALL_LAYERS) { List ll = context.getLayerManager().getLayers(); for (int i = 0 ; i < ll.size() ; i++) { FeatureCollection fc = ((Layer)ll.get(i)).getFeatureCollectionWrapper(); for (Iterator it = fc.iterator() ; it.hasNext() ;) { Geometry p = ((Feature)it.next()).getGeometry(); if (op==Operator.INTER && g.intersects(p)) return true; else if (op==Operator.CONTA && g.contains(p)) return true; else if (op==Operator.WITHI && g.within(p)) return true; else if (op==Operator.WSTRI && g.relate(p, "TFFTFF***")) return true; else if (op==Operator.WDIST && g.distance(p)<op.arg) return true; else if (op==Operator.TOUCH && g.touches(p)) return true; else if (op==Operator.CROSS && g.crosses(p)) return true; else if (op==Operator.OVERL && g.overlaps(p)) return true; else if (op==Operator.DISJO && g.disjoint(p)) return true; else; } return false; } } else { Layer layer = context.getLayerManager().getLayer((String)query.valueCB.getSelectedValue()); FeatureCollection fc = layer.getFeatureCollectionWrapper(); for (Iterator it = fc.iterator() ; it.hasNext() ;) { Geometry p = ((Feature)it.next()).getGeometry(); if (op==Operator.INTER && g.intersects(p)) return true; else if (op==Operator.CONTA && g.contains(p)) return true; else if (op==Operator.WITHI && g.within(p)) return true; else if (op==Operator.WSTRI && g.relate(p, "TFFTFF***")) return true; else if (op==Operator.WDIST && g.distance(p)<op.arg) return true; else if (op==Operator.TOUCH && g.touches(p)) return true; else if (op==Operator.CROSS && g.crosses(p)) return true; else if (op==Operator.OVERL && g.overlaps(p)) return true; else if (op==Operator.DISJO && g.disjoint(p)) return true; else; } return false; } return false; } //************************************************************************** // apply functions //************************************************************************** private String sfunction(String s) { if (ft==Function.SNOF) return s; else if (ft==Function.TRIM) return s.trim(); else if (ft==Function.SUBS && ft.args.length==1) { return s.substring(ft.args[0]); } else if (ft==Function.SUBS && ft.args.length==2) { return s.substring(ft.args[0], ft.args[1]); } else return s; } private double nfunction(String s) { if (ft==Function.LENG) return (double)s.length(); else return 0.0; } private Geometry gfunction(Geometry g) { //System.out.println("geometric function"); if (ft==Function.GNOF) return g; else if (ft==Function.CENT) return g.getInteriorPoint(); else if (ft==Function.BUFF) return g.buffer(ft.arg); else return g; } private Date dfunction(Date d) { //System.out.println("date function"); if (ft==Function.DNOF) return d; else if (ft==Function.DDAY || ft==Function.DYEA) { Calendar cal = new GregorianCalendar(); cal.setTime(d); Calendar rcal = new GregorianCalendar(); rcal.clear(); if (ft==Function.DDAY) { rcal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH)); } else if (ft==Function.DYEA) { rcal.set(Calendar.YEAR, cal.get(Calendar.YEAR)); } return rcal.getTime(); } else return d; } private double nfunction(Geometry g) { //System.out.println("numeric function"); if (ft==Function.LENG) return g.getLength(); else if (ft==Function.AREA) return g.getArea(); else if (ft==Function.NBPT) return (double)g.getNumPoints(); else if (ft==Function.NBPA) { if (g.isEmpty()) return 0; else if (g instanceof GeometryCollection) return ((GeometryCollection)g).getNumGeometries(); else return 1; } else return 0.0; } private boolean bfunction(Geometry g) { //System.out.println("boolean function"); if (ft==Function.EMPT) return g.isEmpty(); else if (ft==Function.SIMP) return g.isSimple(); else if (ft==Function.VALI) return g.isValid(); else return false; } }