package org.tessell.widgets.form;
import static org.tessell.widgets.Widgets.newFlowPanel;
import java.util.ArrayList;
import org.tessell.gwt.user.client.ui.IsFlowPanel;
import org.tessell.gwt.user.client.ui.IsHTMLPanel;
import org.tessell.model.dsl.Binder;
import org.tessell.model.properties.PropertyGroup;
import org.tessell.presenter.BasicPresenter;
import org.tessell.util.HTMLPanelBuilder;
import org.tessell.util.OnEnterKeyHandler;
import org.tessell.widgets.form.actions.FormAction;
import org.tessell.widgets.form.lines.FormLine;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.HasAllKeyHandlers;
import com.google.gwt.event.logical.shared.AttachEvent;
/**
* Given a list of bindings, handles the boilerplate HTML layout/logic of forms.
*
* A form is broken down into: lines and actions.
*/
public class FormPresenter extends BasicPresenter<IsFlowPanel> {
private final ArrayList<FormLine> formLines = new ArrayList<FormLine>();
private final ArrayList<FormAction> formActions = new ArrayList<FormAction>();
private final PropertyGroup all = new PropertyGroup("all");
private final String id;
private final Binder binder = new Binder();
private final FormLayout layout;
private boolean needsRender = true;
private FormAction defaultAction;
public FormPresenter(String id) {
this(id, new DefaultFormLayout());
}
public FormPresenter(String id, FormLayout layout) {
super(newFlowPanel());
this.id = id;
this.layout = layout;
}
@Override
public void onBind() {
super.onBind();
registerHandler(view.addAttachHandler(new OnViewAttached()));
}
/** @return a property that all of our fields are valid. */
public PropertyGroup allValid() {
return all;
}
/** Adds {@code line}. */
public void add(FormLine line) {
formLines.add(line);
line.bind(this, all, binder);
renderNeeded();
}
/** Adds {@code action}. */
public void add(FormAction action) {
formActions.add(action);
action.bind(this, binder);
renderNeeded();
defaultAction = action;
}
public void focusFirstLine() {
if (formLines.size() > 0) {
formLines.get(0).focus();
}
}
/** Renders all of our lines into our view. */
private void render() {
HTMLPanelBuilder hb = new HTMLPanelBuilder();
layout.render(this, hb);
insertHtml(hb.toHTMLPanel());
needsRender = false;
}
private void renderNeeded() {
if (!GWT.isClient() || view.isAttached()) {
// in unit tests, render should be cheap
render();
} else {
// Wait until we're attached
needsRender = true;
}
}
private void insertHtml(IsHTMLPanel panel) {
if (view.getWidgetCount() > 0) {
view.remove(0);
}
view.add(panel);
}
public String getId() {
return id;
}
public ArrayList<FormLine> getFormLines() {
return formLines;
}
public ArrayList<FormAction> getFormActions() {
return formActions;
}
public void setDefaultAction(FormAction defaultAction) {
this.defaultAction = defaultAction;
}
public void watchForEnterKey(final HasAllKeyHandlers source) {
OnEnterKeyHandler h = new OnEnterKeyHandler(new Runnable() {
public void run() {
if (defaultAction != null) {
defaultAction.trigger();
}
}
});
source.addKeyUpHandler(h);
source.addKeyDownHandler(h);
}
private final class OnViewAttached implements AttachEvent.Handler {
public void onAttachOrDetach(AttachEvent event) {
if (event.isAttached() && needsRender) {
render();
}
}
}
}