package fr.lteconsulting.hexa.client.form; import java.util.ArrayList; import java.util.HashMap; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Style.Display; import com.google.gwt.dom.client.Style.FontWeight; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.dom.client.Style.VerticalAlign; import com.google.gwt.json.client.JSONObject; import com.google.gwt.json.client.JSONValue; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.AcceptsOneWidget; import com.google.gwt.user.client.ui.FlexTable; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.SimplePanel; import com.google.gwt.user.client.ui.Widget; import fr.lteconsulting.hexa.client.application.archi.View; import fr.lteconsulting.hexa.client.form.fieldtypes.FieldType; import fr.lteconsulting.hexa.client.form.fieldtypes.FieldType.FieldChangeHandler; import fr.lteconsulting.hexa.client.form.fieldtypes.FieldType.FieldChangeHandlerManager; import fr.lteconsulting.hexa.client.interfaces.IAsyncCallback; import fr.lteconsulting.hexa.client.tools.HTMLStream; public class FormManager implements View { public interface Constraint { void install( FormManager formManager ); boolean evaluate(); void display(); } public interface Marshall<T> { T get( JSONValue value ); JSONValue get( T object ); } class Info { String name; int row; Info( String name, int row ) { this.name = name; this.row = row; } GroupInfo isGroup() { if( this instanceof GroupInfo ) return (GroupInfo) this; return null; } FieldInfo isField() { if( this instanceof FieldInfo ) return (FieldInfo) this; return null; } } class GroupInfo extends Info { public GroupInfo( String name, GroupInfo parent, int row ) { super( name, row ); if( parent != null ) parent.addChild( this ); else fields.add( this ); } ArrayList<Info> children = null; void addChild( Info child ) { if( children == null ) children = new ArrayList<Info>(); children.add( child ); } } class FieldInfo extends Info { FieldType type = null; Widget widget = null; FieldInfo( String name, GroupInfo parent, int row, FieldType type, Widget widget ) { super( name, row ); this.type = type; this.widget = widget; if( parent != null ) parent.addChild( this ); else fields.add( this ); } } ArrayList<Constraint> constraints = new ArrayList<FormManager.Constraint>(); FlexTable table = new FlexTable(); public FormManager() { } public boolean validate() { boolean result = true; for( Constraint c : constraints ) { if( !c.evaluate() ) result = false; c.display(); } if( !result ) { Window.alert( "Please correct the form as some fields are not valid (they are indicated in red)." ); } return result; } public boolean isValidated() { boolean result = true; for( Constraint c : constraints ) { if( !c.evaluate() ) result = false; c.display(); } return result; } @Override public Widget asWidget() { return table; } public void showField( Object field, boolean fShow ) { FieldInfo info = (FieldInfo) field; if( fShow ) table.getRowFormatter().getElement( info.row ).getStyle().clearDisplay(); else table.getRowFormatter().getElement( info.row ).getStyle().setDisplay( Display.NONE ); } // TODO here temporarily HashMap<FieldInfo, HTMLStream> fieldConstraintSlots = new HashMap<FieldInfo, HTMLStream>(); ArrayList<Info> fields = new ArrayList<Info>(); HashMap<FieldInfo, Object> fieldWatcherRegistrations = null; HashMap<FieldInfo, ArrayList<Constraint>> fieldsWatchingConstraints = null; HashMap<FieldInfo, ArrayList<IAsyncCallback<Object>>> fieldsWatchers = null; public AcceptsOneWidget addConstraintSlot( Constraint client, Object field ) { FieldInfo info = (FieldInfo) field; HTMLStream stream = fieldConstraintSlots.get( info ); if( stream == null ) { stream = new HTMLStream(); fieldConstraintSlots.put( info, stream ); table.setWidget( info.row, 2, stream ); } SimplePanel slot = new SimplePanel(); stream.addLeft( slot ); return slot; } private void prepareFieldToBeWatched( FieldInfo info ) { if( fieldWatcherRegistrations == null ) fieldWatcherRegistrations = new HashMap<FieldInfo, Object>(); // ensure we are registered to this field's changes Object registration = fieldWatcherRegistrations.get( info ); if( registration == null ) { FieldChangeHandlerManager mng = info.type.getHandlerManager( info.widget ); if( mng == null ) return; registration = mng.addChangeHandler( fieldChangeHandler, info ); fieldWatcherRegistrations.put( info, registration ); } } public void watchField( Object field, IAsyncCallback<Object> callback ) { FieldInfo info = (FieldInfo) field; prepareFieldToBeWatched( info ); // add the constraint to the watchers list if( fieldsWatchers == null ) fieldsWatchers = new HashMap<FieldInfo, ArrayList<IAsyncCallback<Object>>>(); ArrayList<IAsyncCallback<Object>> watchers = fieldsWatchers.get( info ); if( watchers == null ) { watchers = new ArrayList<IAsyncCallback<Object>>(); fieldsWatchers.put( info, watchers ); } watchers.add( callback ); } public void watchConstraintField( Constraint client, Object field ) { FieldInfo info = (FieldInfo) field; prepareFieldToBeWatched( info ); // add the constraint to the watchers list if( fieldsWatchingConstraints == null ) fieldsWatchingConstraints = new HashMap<FieldInfo, ArrayList<Constraint>>(); ArrayList<Constraint> constraints = fieldsWatchingConstraints.get( info ); if( constraints == null ) { constraints = new ArrayList<FormManager.Constraint>(); fieldsWatchingConstraints.put( info, constraints ); } constraints.add( client ); } FieldChangeHandler fieldChangeHandler = new FieldChangeHandler() { @Override public void onFieldChange( Object cookie ) { FieldInfo info = (FieldInfo) cookie; GWT.log( "changed field in form " + info.name ); if( fieldsWatchingConstraints != null ) { ArrayList<Constraint> constraints = fieldsWatchingConstraints.get( info ); if( constraints != null ) { for( Constraint c : constraints ) c.display(); } } if( fieldsWatchers != null ) { ArrayList<IAsyncCallback<Object>> watchers = fieldsWatchers.get( info ); if( watchers != null ) { for( IAsyncCallback<Object> watcher : watchers ) watcher.onSuccess( info ); } } } }; /* * HashMap<FieldInfo,HTMLStream> fieldCommentsSlots = new HashMap<FieldInfo, * HTMLStream>(); public AcceptsOneWidget addCommentSlot( Object field ) { * FieldInfo info = (FieldInfo)field; * * HTMLStream stream = fieldCommentsSlots.get( info ); if( stream == null ) * { stream = new HTMLStream(); fieldCommentsSlots.put( info, stream ); * * table.setWidget( info.row, 3, stream ); * table.getCellFormatter().getElement( info.row, 3 * ).getStyle().setFontWeight( FontWeight.NORMAL ); } * * SimplePanel slot = new SimplePanel(); stream.addLeft( slot ); * * return slot; } */ public Object addGroup( String display, String name, Object parent ) { int row = display != null ? table.getRowCount() : -1; // create the new group GroupInfo parentInfo = (GroupInfo) parent; GroupInfo info = new GroupInfo( name, parentInfo, row ); // display the new group if( display != null && row >= 0 ) { table.setHTML( row, 0, display ); table.getCellFormatter().getElement( row, 0 ).getStyle().setVerticalAlign( VerticalAlign.TOP ); table.getCellFormatter().getElement( row, 0 ).setAttribute( "colSpan", "2" ); table.getCellFormatter().getElement( row, 0 ).getStyle().setPaddingTop( 25, Unit.PX ); table.getCellFormatter().getElement( row, 0 ).getStyle().setPaddingBottom( 10, Unit.PX ); table.getCellFormatter().getElement( row, 0 ).getStyle().setFontWeight( FontWeight.BOLD ); } return info; } public Object addField( String display, String name, FieldType fieldType ) { return addField( display, name, fieldType, null ); } public Object addField( String display, String name, FieldType fieldType, Object parent ) { return addField( display, name, fieldType, fieldType.getWidget(), parent ); } public Object addField( String display, String name, FieldType fieldType, Widget fieldWidget, Object parent ) { int row = table.getRowCount(); // create the new field GroupInfo parentInfo = (GroupInfo) parent; FieldInfo info = new FieldInfo( name, parentInfo, row, fieldType, fieldWidget ); // Display the new field if( display != null ) { HTMLStream stream = new HTMLStream(); stream.addRight( new HTML( display ) ); stream.clFl(); table.setWidget( row, 0, stream ); } table.setWidget( row, 1, info.widget ); table.getCellFormatter().getElement( row, 0 ).getStyle().setVerticalAlign( VerticalAlign.TOP ); table.getCellFormatter().getElement( row, 1 ).getStyle().setVerticalAlign( VerticalAlign.TOP ); table.getCellFormatter().getElement( row, 0 ).getStyle().setFontWeight( FontWeight.BOLD ); return info; } public JSONObject getJSONSerialized() { return getGroupSerialized( fields ); } JSONObject getGroupSerialized( Iterable<Info> infos ) { JSONObject object = new JSONObject(); for( Info info : infos ) { FieldInfo field = info.isField(); if( field != null ) { if( field.name != null ) object.put( field.name, getFieldValue( field ) ); } else { GroupInfo group = info.isGroup(); object.put( group.name, getGroupSerialized( group.children ) ); } } // Window.alert( "Serialized form : " + object.toString() ); return object; } public void addSection( String text ) { int row = table.getRowCount(); table.setText( row, 0, text ); table.getCellFormatter().getElement( row, 0 ).getStyle().setVerticalAlign( VerticalAlign.TOP ); table.getCellFormatter().getElement( row, 0 ).setAttribute( "colSpan", "2" ); table.getCellFormatter().getElement( row, 0 ).getStyle().setPaddingTop( 25, Unit.PX ); table.getCellFormatter().getElement( row, 0 ).getStyle().setPaddingBottom( 10, Unit.PX ); } public void addHTMLSection( String html ) { int row = table.getRowCount(); table.setHTML( row, 0, html ); table.getCellFormatter().getElement( row, 0 ).getStyle().setVerticalAlign( VerticalAlign.TOP ); table.getCellFormatter().getElement( row, 0 ).setAttribute( "colSpan", "2" ); table.getCellFormatter().getElement( row, 0 ).getStyle().setPaddingTop( 25, Unit.PX ); table.getCellFormatter().getElement( row, 0 ).getStyle().setPaddingBottom( 10, Unit.PX ); } public void addConstraint( Constraint constraint ) { constraints.add( constraint ); // put constraint in its context constraint.install( this ); constraint.display(); } public void setFieldValue( Object field, JSONValue value ) { FieldInfo info = (FieldInfo) field; info.type.setValue( info.widget, value ); } public JSONValue getFieldValue( Object field ) { FieldInfo info = (FieldInfo) field; return info.type.getValue( info.widget ); } }