/*
* 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.Style.Orientation;
import com.extjs.gxt.ui.client.core.El;
import com.extjs.gxt.ui.client.event.ComponentEvent;
import com.extjs.gxt.ui.client.widget.Component;
import com.extjs.gxt.ui.client.widget.ComponentHelper;
import com.extjs.gxt.ui.client.widget.HorizontalPanel;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.VerticalPanel;
import com.extjs.gxt.ui.client.widget.layout.TableData;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
/**
* A field that displays multiple fields in a single row or column.
*
* <dl>
* <dt>Inherited Events:</dt>
* <dd>Field Focus</dd>
* <dd>Field Blur</dd>
* <dd>Field Change</dd>
* <dd>Field Invalid</dd>
* <dd>Field Valid</dd>
* <dd>Field KeyPress</dd>
* <dd>Field SpecialKey</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>
*/
public class MultiField<D> extends Field<D> {
protected List<Field<?>> fields;
protected LayoutContainer lc;
protected Orientation orientation = Orientation.HORIZONTAL;
protected int spacing;
protected Validator validator;
private boolean resizeFields;
/**
* Creates a new multi-field.
*/
public MultiField() {
fields = new ArrayList<Field<?>>();
baseStyle = "x-form-group";
invalidStyle = "none";
}
/**
* Creates a new multi-field.
*
* @param fieldLabel the field label
* @param fields the field(s) to add
*/
public MultiField(String fieldLabel, Field<?>... fields) {
this();
setFieldLabel(fieldLabel);
for (Field<?> f : fields) {
add(f);
}
}
/**
* Adds a field (pre-render).
*
* @param field the field to add
*/
public void add(Field<?> field) {
assertPreRender();
fields.add(field);
}
@Override
public void clear() {
for (Field<?> f : fields) {
f.clear();
}
clearInvalid();
}
/**
* Returns the field at the index.
*
* @param index the index
* @return the field
*/
public Field<?> get(int index) {
return fields.get(index);
}
/**
* Returns all the child field's.
*
* @return the fields
*/
public List<Field<?>> getAll() {
return new ArrayList<Field<?>>(fields);
}
/**
* Returns the fields orientation.
*
* @return the orientation
*/
public Orientation getOrientation() {
return (orientation);
}
/**
* Returns the field's spacing.
*
* @return the spacing
*/
public int getSpacing() {
return spacing;
}
/**
* Returns the field's validator.
*
* @return the validator
*/
public Validator getValidator() {
return validator;
}
/**
* Returns true if child fields are being resized.
*
* @return the resize field state
*/
public boolean isResizeFields() {
return resizeFields;
}
@Override
public boolean isValid(boolean silent) {
boolean ret = super.isValid(silent);
for (Field<?> f : fields) {
if (!f.isValid(silent)) {
return false;
}
}
return ret;
}
@Override
public void onBrowserEvent(Event event) {
}
@Override
public void onComponentEvent(ComponentEvent ce) {
}
@Override
public void reset() {
for (Field<?> f : fields) {
f.reset();
}
clearInvalid();
}
/**
* Sets the fields orientation (defaults to horizontal).
*
* @param orientation the orientation
*/
public void setOrientation(Orientation orientation) {
this.orientation = orientation;
}
@Override
public void setReadOnly(boolean readOnly) {
for (Field<?> field : fields) {
field.setReadOnly(readOnly);
}
}
/**
* True to resize the child fields to fit available space (defaults to false).
*
* @param resizeFields true to resize children
*/
public void setResizeFields(boolean resizeFields) {
this.resizeFields = resizeFields;
}
/**
* Sets the amount of spacing between fields. Spacing is applied to the right
* of each field for horizontal orientation and applied to the bottom of each
* field for vertical orientation (defaults to 0, pre-render).
*
* @param spacing the spacing in pixels
*/
public void setSpacing(int spacing) {
this.spacing = spacing;
}
/**
* Sets the field's validator.
*
* @param validator the validator
*/
public void setValidator(Validator validator) {
this.validator = validator;
}
@Override
protected void doAttachChildren() {
ComponentHelper.doAttach(lc);
if (GXT.isIE) {
el().repaint();
}
}
@Override
protected void doDetachChildren() {
ComponentHelper.doDetach(lc);
}
@Override
protected El getInputEl() {
if (fields.size() > 0) {
return fields.get(0).getInputEl();
}
return super.getInputEl();
}
@Override
protected void notifyHide() {
super.notifyHide();
doNotify(lc, false);
}
@Override
protected void notifyShow() {
super.notifyShow();
doNotify(lc, true);
}
@Override
protected void onDisable() {
super.onDisable();
lc.disable();
}
@Override
protected void onEnable() {
super.onEnable();
lc.enable();
}
@Override
protected void onRender(Element target, int index) {
boolean vertical = orientation == Orientation.VERTICAL;
if (vertical) {
lc = new VerticalPanel();
} else {
lc = new HorizontalPanel();
}
if (GXT.isIE) {
lc.setStyleAttribute("position", "relative");
}
for (int i = 0, len = fields.size(); i < len; i++) {
Field<?> f = fields.get(i);
boolean last = i == (fields.size() - 1);
TableData data = (TableData) ComponentHelper.getLayoutData(f);
if (data == null) {
data = new TableData();
}
String style = "position: static;";
if (vertical && !last && spacing > 0) {
style += "paddingBottom:" + spacing + "px;";
} else if (!vertical && !last && spacing > 0) {
style += "paddingRight:" + spacing + "px;";
}
data.setStyle(style);
lc.add(f, data);
}
lc.render(target, index);
ComponentHelper.setParent(this, lc);
setElement(lc.getElement());
}
@Override
protected void onResize(int width, int height) {
super.onResize(width, height);
if (resizeFields) {
if (orientation == Orientation.HORIZONTAL) {
if (!GXT.isBorderBox) {
width -= ((fields.size() - 1) * spacing);
}
int w = width / fields.size();
for (Field<?> f : fields) {
f.setWidth(w);
}
} else {
for (Field<?> f : fields) {
f.setWidth(width);
}
}
}
if (GXT.isIE) {
el().repaint();
}
}
@Override
protected boolean validateValue(String value) {
// validate multi field
if (validator != null) {
String msg = validator.validate(this, value);
if (msg != null) {
markInvalid(msg);
return false;
}
}
clearInvalid();
return true;
}
private native void doNotify(Component c, boolean show) /*-{
if(show){
c.@com.extjs.gxt.ui.client.widget.Component::notifyShow()()
} else {
c.@com.extjs.gxt.ui.client.widget.Component::notifyHide()();
}
}-*/;
}