/*
* Ext GWT - Ext for GWT
* Copyright(c) 2007-2009, Ext JS, LLC.
* licensing@extjs.com
*
* http://extjs.com/license
*/
package com.extjs.gxt.ui.client.widget.form;
import com.extjs.gxt.ui.client.core.El;
import com.extjs.gxt.ui.client.event.BaseEvent;
import com.extjs.gxt.ui.client.event.ComponentEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.FieldSetEvent;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.widget.Component;
import com.extjs.gxt.ui.client.widget.ComponentHelper;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.button.ToolButton;
import com.google.gwt.dom.client.InputElement;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
/**
* A container that wraps its content in a HTML fieldset.
*
* <dl>
* <dt><b>Events:</b></dt>
*
* <dd><b>BeforeExpand</b> : FieldSetEvent(fieldSet)<br>
* <div>Fires before the panel is expanded. Listeners can cancel the action by
* calling {@link BaseEvent#setCancelled(boolean)}.</div>
* <ul>
* <li>fieldSet : this</li>
* </ul>
* </dd>
*
* <dd><b>Expand</b> : FieldSetEvent(fieldSet)<br>
* <div>Fires after the panel is expanded</div>
* <ul>
* <li>fieldSet : this</li>
* </ul>
* </dd>
*
* <dd><b>BeforeCollapse</b> : FieldSetEvent(fieldSet)<br>
* <div>Fires before the panel is collpased. Listeners can cancel the action by
* calling {@link BaseEvent#setCancelled(boolean)}.</div>
* <ul>
* <li>fieldSet : this</li>
* </ul>
* </dd>
*
* <dd><b>Collapse</b> : FieldSetEvent(fieldSet)<br>
* <div>Fires after the panel is collapsed.</div>
* <ul>
* <li>fieldSet : this</li>
* </ul>
* </dd>
* </dl>
*
* <dl>
* <dt>Inherited Events:</dt>
* <dd>LayoutContainer AfterLayout</dt>
* <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>
*/
public class FieldSet extends LayoutContainer {
private El body;
private ToolButton collapseBtn;
private Element heading;
private String text;
private boolean collapsible;
private boolean collapsed;
private boolean checkboxToggle;
private String checkboxName;
private InputElement checkbox;
/**
* Creates a new fieldset.
*/
public FieldSet() {
baseStyle = "x-fieldset";
enableLayout = true;
}
/**
* Collapses the fieldset.
*/
public void collapse() {
if (rendered) {
if (collapsible && !collapsed) {
if (fireEvent(Events.BeforeCollapse)) {
onCollapse();
}
}
} else {
collapsed = true;
}
}
/**
* Expands the fieldset.
*/
public void expand() {
if (rendered) {
if (collapsible && collapsed) {
if (fireEvent(Events.BeforeExpand)) {
onExpand();
}
}
} else {
collapsed = false;
}
}
/**
* Returns the checkbox name.
*
* @return the checkbox name
*/
public String getCheckboxName() {
return checkboxName;
}
@Override
public El getLayoutTarget() {
return body;
}
@Override
public boolean insert(Component item, int index) {
return super.insert(item, index);
}
/**
* Returns true if checkbox toggle is enabled.
*
* @return the checkbox toggle state
*/
public boolean isCheckboxToggle() {
return checkboxToggle;
}
/**
* Returns true if the fieldset is collapsible.
*
* @return true if callapsible
*/
public boolean isCollapsible() {
return collapsible;
}
/**
* Returns <code>true</code> if the panel is expanded.
*
* @return the expand state
*/
public boolean isExpanded() {
return !collapsed;
}
@Override
public void onComponentEvent(ComponentEvent ce) {
super.onComponentEvent(ce);
if (ce.getEventTypeInt() == Event.ONCLICK) {
onClick(ce);
}
}
/**
* The name to assign to the fieldset's checkbox if
* {@link #setCheckboxToggle(boolean)} = true.
*
* @param checkboxName the name
*/
public void setCheckboxName(String checkboxName) {
this.checkboxName = checkboxName;
}
/**
* True to render a checkbox into the fieldset frame just in front of the
* legend (defaults to false, pre-render). The fieldset will be expanded or
* collapsed when the checkbox is toggled.
*
* @param checkboxToggle true for checkbox toggle
*/
public void setCheckboxToggle(boolean checkboxToggle) {
this.checkboxToggle = checkboxToggle;
this.collapsible = true;
}
/**
* Sets whether the fieldset is collapsible (defaults to false, pre-render).
*
* @param collapsible true for collapse
*/
public void setCollapsible(boolean collapsible) {
this.collapsible = collapsible;
}
/**
* Sets the panel's expand state.
*
* @param expand <code>true<code> true to expand
*/
public void setExpanded(boolean expand) {
if (expand) {
expand();
} else {
collapse();
}
}
/**
* Sets the panel heading.
*
* @param text the heading text
*/
public void setHeading(String text) {
this.text = text;
if (rendered) {
heading.setInnerHTML(text);
}
}
@Override
protected ComponentEvent createComponentEvent(Event event) {
return new FieldSetEvent(this, event);
}
@Override
protected void doAttachChildren() {
super.doAttachChildren();
ComponentHelper.doAttach(collapseBtn);
}
@Override
protected void doDetachChildren() {
super.doDetachChildren();
ComponentHelper.doDetach(collapseBtn);
}
protected void onClick(ComponentEvent ce) {
if (checkboxToggle && ce.getTarget() == (Element) checkbox.cast()) {
setExpanded(!isExpanded());
}
}
protected void onCollapse() {
collapsed = true;
if (checkboxToggle && checkbox != null) {
checkbox.setChecked(false);
}
body.setVisible(false);
addStyleName("x-panel-collapsed");
FieldSetEvent fe = new FieldSetEvent(this);
fireEvent(Events.Collapse, fe);
fireEvent(Events.Resize, fe);
}
protected void onExpand() {
collapsed = false;
if (checkboxToggle && checkbox != null) {
checkbox.setChecked(true);
}
body.setVisible(true);
removeStyleName("x-panel-collapsed");
layout();
FieldSetEvent fe = new FieldSetEvent(this);
fireEvent(Events.Expand, fe);
fireEvent(Events.Resize, fe);
}
@Override
protected void onRender(Element parent, int pos) {
setElement(DOM.createFieldSet(), parent, pos);
Element legend = DOM.createLegend();
legend.setClassName("x-fieldset-header");
if (checkboxToggle) {
checkbox = DOM.createInputCheck().cast();
El.fly(checkbox).addEventsSunk(Event.ONCLICK);
if (checkboxName != null) {
checkbox.setAttribute("name", checkboxName);
}
legend.appendChild(checkbox);
checkbox.setChecked(!collapsed);
}
if (!checkboxToggle && collapsible) {
collapseBtn = new ToolButton("x-tool-toggle");
collapseBtn.addListener(Events.Select, new Listener<ComponentEvent>() {
public void handleEvent(ComponentEvent be) {
setExpanded(!isExpanded());
}
});
collapseBtn.render(legend);
}
heading = DOM.createSpan();
heading.setClassName("x-fieldset-header-text");
legend.appendChild(heading);
getElement().appendChild(legend);
body = el().appendChild(DOM.createDiv());
if (text != null) {
setHeading(text);
}
if (collapsed) {
onCollapse();
}
}
@Override
protected void onResize(int width, int height) {
super.onResize(width, height);
if (isAutoWidth()) {
getLayoutTarget().setWidth("auto");
} else if (width != -1) {
getLayoutTarget().setWidth(width - el().getFrameWidth("lr"), true);
}
if (isAutoHeight()) {
getLayoutTarget().setHeight("auto");
} else if (height != -1) {
getLayoutTarget().setHeight(height - el().getFrameWidth("tb"), true);
}
}
}