package org.autoplot.dom;
import java.awt.Component;
import java.beans.IntrospectionException;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.das2.graph.DasCanvasComponent;
import org.das2.util.LoggerManager;
import org.jdesktop.beansbinding.Converter;
/**
* It is apparent that the overhead of BeansBinding is so great that a lightweight
* binding engine would dramatically improve performance. This encapsulates.
*
* @author jbf
*/
public class BindingSupport {
private static final Logger logger= org.das2.util.LoggerManager.getLogger("autoplot");
protected BindingSupport() {
implBindingContexts = new HashMap();
//sources= new HashMap();
}
private static class BindingImpl {
PropertyChangeListener srcListener;
PropertyChangeListener dstListener;
DomNode src;
Object dst;
String dstProp;
String srcProp;
Method dstSetter;
Method srcSetter;
Method dstGetter;
Method srcGetter;
@Override
public String toString() {
if ( dst instanceof DomNode ) {
return src+"."+srcProp+" \u2194\t"+dst+"."+dstProp;
} else if ( dst instanceof DasCanvasComponent ) {
return src+"."+srcProp+" \u2194\t\""+((DasCanvasComponent)dst).getDasName()+"\"."+dstProp;
} else if ( dst instanceof Component ) {
return src+"."+srcProp+" \u2194\t\""+((Component)dst).getName()+"\"."+dstProp;
} else {
return src+"."+srcProp+" \u2194\t\""+dst+"\"."+dstProp;
}
}
}
/**
* converter for objects which have a toString/parse pair. This works for:
*
* - DatumRange
*
- Datum
*
- Color
*
* The convertForward method captures the class of the object.
*/
public static final Converter toStringConverter= new Converter() {
Class c= null;
Object instance;
@Override
public Object convertForward(Object value) {
instance= value;
if ( c==null ) {
c= instance.getClass();
}
if ( c==java.awt.Color.class ) {
return org.das2.util.ColorUtil.nameForColor((java.awt.Color)value);
} else {
return value.toString();
}
}
@Override
public Object convertReverse(Object value) {
if ( c.isAssignableFrom( org.das2.datum.Datum.class ) ) {
try {
return org.das2.datum.DatumUtil.parse((String)value);
} catch (ParseException ex) {
return instance;
}
} else if ( c.isAssignableFrom( org.das2.datum.DatumRange.class ) ) {
try {
return org.das2.datum.DatumRangeUtil.parseTimeRange((String)value);
} catch (ParseException ex) {
return instance;
}
} else if ( c.isAssignableFrom( java.awt.Color.class ) ) {
return org.das2.util.ColorUtil.decodeColor((String)value);
}
return value.toString();
}
};
private static class MyPropChangeListener implements PropertyChangeListener {
final Object p;
final Method setter;
final Method getter;
final Converter c;
final boolean forward;
final String srcProp;
final String pprop;
private MyPropChangeListener( final Object p, final Method setter, final Method getter, final Converter c,
final boolean forward, final String srcProp, final String pprop ) {
this.p= p;
this.setter= setter;
this.getter= getter;
this.c= c;
this.forward= forward;
this.srcProp= srcProp;
this.pprop= pprop;
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
LoggerManager.logPropertyChangeEvent(evt);
try {
if (c == null) {
Object oldValue= getter.invoke( p );
if ( oldValue==null ) {
System.err.println("oldValue is null!!!");
}
if ( oldValue!=null && oldValue.equals(evt.getNewValue() ) ) return;
if ( new Exception().getStackTrace().length > 300 ) {
System.err.println("setter: "+setter);
System.err.println("old:" + evt.getOldValue() + " new:"+evt.getNewValue() );
System.err.println("this is that bad state, where bindings get us into a infinite loop!");
} else {
setter.invoke(p, evt.getNewValue());
}
} else {
if ( Thread.currentThread().getStackTrace().length>200 ) {
System.err.println("Problem detected in stack trace, circular call indicated by stackTraceLength>200");
return; // put an end to it so it doesn't crash
}
if (forward) {
setter.invoke(p, c.convertForward(evt.getNewValue()));
} else {
setter.invoke(p, c.convertReverse(evt.getNewValue()));
}
}
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
private PropertyChangeListener propListener(final Object p, final Method setter, final Method getter, final Converter c, final boolean forward, final String srcProp, final String pprop ) {
return new MyPropChangeListener( p, setter, getter, c, forward, srcProp, pprop );
}
final Map