/* * Ext GWT 2.2.4 - Ext for GWT * Copyright(c) 2007-2010, Ext JS, LLC. * licensing@extjs.com * * http://extjs.com/license */ package com.extjs.gxt.ui.client.widget.form; import java.util.ArrayList; import java.util.List; import com.extjs.gxt.ui.client.GXT; import com.extjs.gxt.ui.client.core.El; import com.extjs.gxt.ui.client.core.XDOM; import com.extjs.gxt.ui.client.event.BaseEvent; import com.extjs.gxt.ui.client.event.Events; import com.extjs.gxt.ui.client.event.FormEvent; import com.extjs.gxt.ui.client.util.Size; import com.extjs.gxt.ui.client.widget.Component; import com.extjs.gxt.ui.client.widget.Container; import com.extjs.gxt.ui.client.widget.ContentPanel; import com.extjs.gxt.ui.client.widget.layout.FormLayout; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.GWT.UncaughtExceptionHandler; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.DeferredCommand; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.impl.FormPanelImpl; import com.google.gwt.user.client.ui.impl.FormPanelImplHost; /** * A panel for displaying form widgets. By default, FormPanel uses a FormLayout, * but this may be overridden when using nested layouts. See {@link FormLayout} * for more documentation. * * <p/> * FormPanel supports nested layout containers. Fields should only be added to * layout containers with a form layout. The form panel settings only apply to * the panel's direct children. * * <dl> * <dt><b>Events:</b></dt> * * <dd><b>BeforeSubmit</b> : FormEvent(this)<br> * <div>Fires before the form is submitted. Only applies when using HTML * submits. Listeners can cancel the action by calling * {@link BaseEvent#setCancelled(boolean)}.</div> * <ul> * <li>formPanel : this</li> * </ul> * </dd> * * <dd><b>Submit</b> : FormEvent(this, resultHtml)<br> * <div>Fires after the form has been submitted. Only applies when using HTML * submits.</div> * <ul> * <li>formPanel : this</li> * <li>resultHtml : the response html</li> * </ul> * </dd> * </dl> * * <dl> * <dt>Inherited Events:</dt> * <dd>ContentPanel BeforeExpand</dd> * <dd>ContentPanel Expand</dd> * <dd>ContentPanel BeforeCollapse</dd> * <dd>ContentPanel Collapse</dd> * <dd>ContentPanel BeforeClose</dd> * <dd>ContentPanel Close</dd> * <dd>LayoutContainer AfterLayout</dd> * <dd>ScrollContainer Scroll</dd> * <dd>Container BeforeAdd</dd> * <dd>Container Add</dd> * <dd>Container BeforeRemove</dd> * <dd>Container Remove</dd> * <dd>BoxComponent Move</dd> * <dd>BoxComponent Resize</dd> * <dd>Component Enable</dd> * <dd>Component Disable</dd> * <dd>Component BeforeHide</dd> * <dd>Component Hide</dd> * <dd>Component BeforeShow</dd> * <dd>Component Show</dd> * <dd>Component Attach</dd> * <dd>Component Detach</dd> * <dd>Component BeforeRender</dd> * <dd>Component Render</dd> * <dd>Component BrowserEvent</dd> * <dd>Component BeforeStateRestore</dd> * <dd>Component StateRestore</dd> * <dd>Component BeforeStateSave</dd> * <dd>Component SaveState</dd> * </dl> */ @SuppressWarnings("deprecation") public class FormPanel extends ContentPanel implements FormPanelImplHost { /** * Form encoding enumeration. */ public enum Encoding { MULTIPART("multipart/form-data"), URLENCODED("application/x-www-form-urlencoded"); private final String value; private Encoding(String value) { this.value = value; } public String value() { return value; } } /** * Label alignment enumeration. */ public enum LabelAlign { LEFT, TOP, RIGHT; } /** * Form method enumeration. */ public enum Method { GET, POST; } private static FormPanelImpl impl = GWT.create(FormPanelImpl.class); private static int formId = 0; private LabelAlign labelAlign = LabelAlign.LEFT; private int labelWidth = 75; private int fieldWidth = 210; private String labelSeparator = ":"; private boolean hideLabels; private int padding = 10; private El form; private Method method = Method.GET; private Encoding encoding; private String action = "javascript:;"; private String frameName; private Element iframe; private String target; /** * Creates a new form panel. */ public FormPanel() { frameName = "gxt.formpanel-" + (++formId); setTarget(frameName); } /** * Clears all values from all fields. */ public void clear() { for (Field<?> f : getFields()) { f.clear(); } } /** * Resets the dirty state for all fields by setting the original value to be * equal to the current value. */ @SuppressWarnings({"unchecked", "rawtypes"}) public void clearDirtyFields() { for (Field f : getFields()) { if (f.isDirty()) { f.setOriginalValue(f.getValue()); } } } /** * Resets all field values. */ public void reset() { for (Field<?> f : getFields()) { f.reset(); } } /** * Returns the form's action. * * @return the action url */ public String getAction() { return action; } /** * Returns the encoding. * * @return the encoding */ public Encoding getEncoding() { return encoding; } /** * Returns all of the panel's child fields. Fields in nested containers are * included in the returned list. * * @return the fields */ public List<Field<?>> getFields() { List<Field<?>> fields = new ArrayList<Field<?>>(); getChildFields(this, fields); return fields; } /** * Returns the field width. * * @return the field width */ public int getFieldWidth() { return fieldWidth; } /** * Returns true if labels are being hidden. * * @return the hide label state */ public boolean getHideLabels() { return hideLabels; } /** * Returns the label alignment. * * @return the label alignment */ public LabelAlign getLabelAlign() { return labelAlign; } /** * Returns the label separator. * * @return the label separator */ public String getLabelSeparator() { return labelSeparator; } /** * Returns the default width. * * @return the label width */ public int getLabelWidth() { return labelWidth; } @Override public El getLayoutTarget() { return form; } /** * Returns the form's method. Only applies when using standard HTML form * submits. * * @return the method the method */ public Method getMethod() { return method; } /** * Returns the panel's padding. * * @return the padding */ public int getPadding() { return padding; } /** * Gets the form's "target". * * @return the form's target. */ public String getTarget() { return target; } /** * Returns true if any of the form's fields are dirty. * * @return true for dirty */ public boolean isDirty() { for (Field<?> f : getFields()) { if (f.isDirty()) { return true; } } return false; } /** * Returns true if the form is invalid. * * @return true if all fields are valid */ public boolean isValid() { return isValid(false); } /** * Returns the form's valid state by querying all child fields. * * @param preventMark true for silent validation (no invalid event and field * is not marked invalid) * * @return true if all fields are valid */ public boolean isValid(boolean preventMark) { boolean valid = true; for (Field<?> f : getFields()) { if (!f.isValid(preventMark)) { valid = false; } } return valid; } public boolean onFormSubmit() { UncaughtExceptionHandler handler = GWT.getUncaughtExceptionHandler(); if (handler != null) { return onFormSubmitAndCatch(handler); } else { return onFormSubmitImpl(); } } public void onFrameLoad() { UncaughtExceptionHandler handler = GWT.getUncaughtExceptionHandler(); if (handler != null) { onFrameLoadAndCatch(handler); } else { onFrameLoadImpl(); } } /** * Sets the action of the form. * * @param url the action */ public void setAction(String url) { this.action = url; if (rendered) { form.dom.setAttribute("action", url); } } /** * Sets the encoding used for submitting this form. * * @param encoding the encoding */ public void setEncoding(Encoding encoding) { this.encoding = encoding; if (rendered) { impl.setEncoding(form.dom, encoding.value); } } /** * Sets the default field width (defaults to 210). * * @param fieldWidth the field width */ public void setFieldWidth(int fieldWidth) { this.fieldWidth = fieldWidth; } /** * True to hide field labels by default (defaults to false). * * @param hideLabels true to hide labels */ public void setHideLabels(boolean hideLabels) { this.hideLabels = hideLabels; } /** * Sets the label alignment. * * @param align the alignment */ public void setLabelAlign(LabelAlign align) { this.labelAlign = align; } /** * Sets the label separator (defaults to ':'). * * @param labelSeparator the label separator */ public void setLabelSeparator(String labelSeparator) { this.labelSeparator = labelSeparator; } /** * Sets the default label width. * * @param labelWidth the label width */ public void setLabelWidth(int labelWidth) { this.labelWidth = labelWidth; } /** * Specifies if the form will be submitted using an HTTP Post or Get request * (defaults to GET). * * @param method the method */ public void setMethod(Method method) { this.method = method; if (rendered) { form.dom.setAttribute("method", method.name().toLowerCase()); } } /** * Sets the padding to be applied to the FormPanel body (defaults to 10). * * @param padding the padding */ public void setPadding(int padding) { this.padding = padding; } /** * Sets all of the panel's fields read only state. * * @param readOnly true for read only */ public void setReadOnly(boolean readOnly) { for (Field<?> f : getFields()) { f.setReadOnly(readOnly); } } /** * Submits the form. */ public void submit() { if (fireEvent(Events.BeforeSubmit, new FormEvent(this))) { impl.submit(form.dom, iframe); } } @Override protected Size adjustBodySize() { return body.getFrameSize(); } @Override protected void onAttach() { super.onAttach(); createFrame(); XDOM.getBody().appendChild(iframe); impl.hookEvents(iframe, form.dom, this); } @Override protected void onDetach() { super.onDetach(); impl.unhookEvents(iframe, form.dom); XDOM.getBody().removeChild(iframe); iframe = null; } @Override protected void onRender(Element target, int index) { super.onRender(target, index); body.setStyleAttribute("background", "none"); form = new El(DOM.createForm()); form.setStyleAttribute("overflow", "hidden"); body.appendChild(form.dom); setMethod(method); setTarget(this.target); if (encoding != null) { setEncoding(encoding); } if (action != null) { setAction(action); } getLayoutTarget().setStyleAttribute("padding", padding + "px"); if (getLayout() == null) { FormLayout layout = new FormLayout(); layout.setDefaultWidth(fieldWidth); layout.setLabelWidth(labelWidth); layout.setLabelAlign(labelAlign); layout.setLabelSeparator(labelSeparator); layout.setHideLabels(hideLabels); setLayout(layout); } form.addEventsSunk(Event.ONLOAD); setAriaRole("region"); } protected void createFrame() { Element dummy = DOM.createDiv(); DOM.setInnerHTML(dummy, "<iframe id=\"" + XDOM.getUniqueId() + "\"" + ((GXT.isIE && GXT.isSecure) ? (" src=\"" + GXT.SSL_SECURE_URL + "\"") : "") + " name='" + frameName + "' style='position:absolute;width:0;height:0;border:0'>"); iframe = DOM.getFirstChild(dummy); } @SuppressWarnings("unchecked") protected void getChildFields(Container<Component> c, List<Field<?>> fields) { for (Component comp : c.getItems()) { if (comp instanceof Field) { fields.add((Field<?>) comp); } else if (comp instanceof Container) { getChildFields((Container<Component>) comp, fields); } } } private boolean onFormSubmitAndCatch(UncaughtExceptionHandler handler) { try { return onFormSubmitImpl(); } catch (Throwable e) { handler.onUncaughtException(e); return false; } } private boolean onFormSubmitImpl() { return fireEvent(Events.BeforeSubmit, new FormEvent(this)); } protected void onFrameLoadAndCatch(UncaughtExceptionHandler handler) { try { onFrameLoadImpl(); } catch (Throwable e) { handler.onUncaughtException(e); } } protected void onFrameLoadImpl() { DeferredCommand.addCommand(new Command() { public void execute() { fireEvent(Events.Submit, new FormEvent(FormPanel.this, impl.getContents(iframe))); } }); } protected void setTarget(String target) { this.target = target; if (rendered) { form.dom.setPropertyString("target", target); } } }