package com.towel.bind.annotation; import java.awt.Container; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import javax.swing.JCheckBox; import javax.swing.text.JTextComponent; import com.towel.bind.Binder; import com.towel.bind.modifier.ComponentModifier; import com.towel.bind.modifier.JCheckBoxModifier; import com.towel.bind.modifier.JTextComponentModifier; import com.towel.el.FieldResolver; import com.towel.el.annotation.AnnotationResolver; import com.towel.exc.ExceptionCollecter; /** * A component binder for JTextComponents. The Binder look for the parameters in * the getName method of each JTextComponent of the Container. * * Use the setName in the components you want. You need at least the name of the * field you want to bind. * * jTextComponent.setName("[name:attrName]") * * If the field need a formatter you pass it as "[fmt:fmtName]" The fmtName must * match with one formatter passed in the constructor. * * If you want a default value if in the object are blank you can use * "[dflt:Text]" if the value in the object is null or empty this text will * assume in the component * * Binder is typed. And the Class argument need to be the class of the binded * objects will be. * * To update the view you need to call the method updateView(Object obj) and to * update the model updateModel(Object target). * * If you need more than one Binder in the Container maybe you need use the * prefix to shows to the binder the fields must be to each class. If you * setName with "[pfx:cads]" you need pass cads to map only the cads fields. * * Example: jTextField.setName("[name:personName]") * jTextField2.setName("[name:age][fmt:int]"); binder = new Binder(container, * Person.class,new IntFormatter()); binder.updateView(personObject); //change * the fields values binder.updateModel(personObject); * * jTextField.setName("[pfx:person][name:personName]") * jTextField2.setName("[pfx:cia][name:name]"); * * personBinder = new Binder("person",container,Person.class); ciaBinder = new * Binder("cia",container, Cia.class); * * @author Marcos Vasconcelos */ public class AnnotatedBinder implements Binder { private List<ComponentModifier> comps; public AnnotatedBinder(Container comp) { comps = new ArrayList<ComponentModifier>(); Class<?> form = comp.getClass(); if (!form.isAnnotationPresent(Form.class)) throw new IllegalArgumentException( "Class should implements com.towel.bind.annotation.Form"); Class<?> clazz = form.getAnnotation(Form.class).value(); try { for (Field f : form.getDeclaredFields()) { if (f.isAnnotationPresent(Bindable.class)) { f.setAccessible(true); Bindable bind = f.getAnnotation(Bindable.class); FieldResolver resolver = null; if (bind.resolvable()) { resolver = new AnnotationResolver(clazz) .resolveSingle(bind.field()); } else { resolver = new FieldResolver(clazz, bind.field(), bind .handler().newInstance()); resolver.setFormatter(bind.formatter().newInstance()); } if (JTextComponent.class.isAssignableFrom(f.getType())) comps.add(new JTextComponentModifier((JTextComponent) f .get(comp), resolver)); if (JCheckBox.class.isAssignableFrom(f.getType())) { comps.add(new JCheckBoxModifier( (JCheckBox) f.get(comp), resolver)); } } } } catch (Exception e) { e.printStackTrace(); } } public void updateView(Object obj) { ExceptionCollecter collecter = new ExceptionCollecter(); for (ComponentModifier modifier : comps) try { modifier.updateComponent(obj); } catch (Exception e) { collecter.collect(e); } // if (!collecter.isEmpty()) // collecter.throwException(); } public void updateModel(Object obj) { ExceptionCollecter collecter = new ExceptionCollecter(); for (ComponentModifier modifier : comps) try { modifier.updateModel(obj); } catch (Exception e) { collecter.collect(e); } // if (!collecter.isEmpty()) // collecter.throwException(); } public final static String FORMATTER = "fmt"; public final static String DEFAULT = "dflt"; public final static String DEFAULT_COND = "dflt_con"; public final static String NAME = "name"; public final static String PREFIX = "pfx"; }