/*
* 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 com.extjs.gxt.ui.client.GXT;
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.util.Size;
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 InputElement checkbox;
private String checkboxName;
private boolean checkboxToggle;
private ToolButton collapseBtn;
private boolean collapsed;
private boolean collapsible;
private Element heading;
private El legend;
private String text;
/**
* Creates a new fieldset.
*/
public FieldSet() {
baseStyle = "x-fieldset";
enableLayout = true;
getFocusSupport().setIgnore(false);
}
/**
* 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;
}
/**
* Returns the panel heading.
*
* @return the heading
*/
public String getHeading() {
return text;
}
@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);
}
@Override
protected void notifyHide() {
if (!collapsed) {
super.notifyHide();
}
}
@Override
protected void notifyShow() {
if (!collapsed) {
super.notifyShow();
}
}
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");
for (Component c : getItems()) {
if (!isComponentHidden(c) && c.isRendered()) {
doNotify(c, false);
}
}
updateIconTitles();
FieldSetEvent fe = new FieldSetEvent(this);
fireEvent(Events.Collapse, fe);
}
@Override
protected void onDisable() {
super.onDisable();
if (collapseBtn != null) {
collapseBtn.disable();
} else if (checkbox != null) {
checkbox.setDisabled(true);
}
}
@Override
protected void onEnable() {
super.onEnable();
if (collapseBtn != null) {
collapseBtn.enable();
} else if (checkbox != null) {
checkbox.setDisabled(false);
}
}
protected void onExpand() {
collapsed = false;
if (checkboxToggle && checkbox != null) {
checkbox.setChecked(true);
}
body.setVisible(true);
removeStyleName("x-panel-collapsed");
for (Component c : getItems()) {
if (!isComponentHidden(c) && c.isRendered()) {
doNotify(c, true);
}
}
updateIconTitles();
FieldSetEvent fe = new FieldSetEvent(this);
fireEvent(Events.Expand, fe);
}
@Override
protected void onFocus(ComponentEvent ce) {
super.onFocus(ce);
if (GXT.isFocusManagerEnabled()) {
if (checkboxToggle && checkbox != null) {
checkbox.focus();
} else if(collapseBtn != null) {
collapseBtn.focus();
}
}
}
@Override
protected void onRender(Element parent, int pos) {
setElement(DOM.createFieldSet(), parent, pos);
legend = new El(DOM.createLegend());
legend.addStyleName("x-fieldset-header");
if (checkboxToggle && collapsible) {
checkbox = DOM.createInputCheck().cast();
sinkEvents(Event.ONCLICK);
if (checkboxName != null) {
checkbox.setAttribute("name", checkboxName);
}
legend.appendChild((Element) checkbox.cast());
checkbox.setDefaultChecked(!collapsed);
checkbox.setChecked(!collapsed);
if (GXT.isAriaEnabled()) {
checkbox.setTitle("Expand " + text);
}
} else 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.dom);
collapseBtn.getAriaSupport().setRole("checkbox");
if (GXT.isAriaEnabled()) {
collapseBtn.setTitle("Expand " + text);
}
ComponentHelper.setParent(this, collapseBtn);
}
heading = DOM.createSpan();
heading.setClassName("x-fieldset-header-text");
legend.appendChild(heading);
getElement().appendChild(legend.dom);
body = el().appendChild(DOM.createDiv());
if (text != null) {
setHeading(text);
}
if (collapsed) {
onCollapse();
}
updateIconTitles();
if (GXT.isFocusManagerEnabled() && !getFocusSupport().isIgnore()) {
el().setTabIndex(0);
el().setElementAttribute("hideFocus", "true");
sinkEvents(Event.FOCUSEVENTS);
}
}
@Override
protected void onResize(int width, int height) {
super.onResize(width, height);
Size frameSize = el().getFrameSize();
if (isAutoWidth()) {
getLayoutTarget().setWidth("auto");
} else if (width != -1) {
getLayoutTarget().setWidth(width - frameSize.width, true);
}
if (isAutoHeight()) {
getLayoutTarget().setHeight("auto");
} else if (height != -1) {
getLayoutTarget().setHeight(
height - frameSize.height - legend.getHeight() - (GXT.isIE ? legend.getMargins("b") : 0), true);
}
}
protected void updateIconTitles() {
if (GXT.isAriaEnabled()) {
String txt = "Expand " + text;
if (checkbox != null) {
checkbox.setTitle(txt);
}
if (collapseBtn != null) {
collapseBtn.setTitle(txt);
collapseBtn.getAriaSupport().setState("aria-checked", !collapsed ? "true" : "false");
}
}
}
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()();
}
}-*/;
private native boolean isComponentHidden(Component c) /*-{
return c.@com.extjs.gxt.ui.client.widget.Component::hidden;
}-*/;
}