/*
* 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.layout;
import com.extjs.gxt.ui.client.core.El;
import com.extjs.gxt.ui.client.event.ComponentEvent;
import com.extjs.gxt.ui.client.event.Events;
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.ContentPanel;
/**
* This is a layout that contains multiple content panels in an expandable
* accordion style such that only one panel can be open at any given time.
*
* <p />
* Child Widgets are:
* <ul>
* <li><b>Sized</b> : Yes - default expands to fill parent container.</li>
* <li><b>Positioned</b> : No - widgets are located at 0,0.</li>
* </ul>
* <p>
* <b>Note:</b> All children added to the container must be
* <code>ContentPanel</code> instances.
* </p>
*/
public class AccordionLayout extends FitLayout {
private boolean activeOnTop;
private boolean autoWidth;
private boolean fill = true;
private boolean hideCollapseTool;
private Listener<ComponentEvent> listener, elistener;
private boolean sequence;
private boolean titleCollapse = true;
public AccordionLayout() {
listener = new Listener<ComponentEvent>() {
public void handleEvent(ComponentEvent ce) {
onBeforeExpand(ce);
}
};
elistener = new Listener<ComponentEvent>() {
public void handleEvent(ComponentEvent ce) {
onExpand(ce);
}
};
}
/**
* Returns true if the active item if first.
*
* @return the active on top state
*/
public boolean getActiveOnTop() {
return activeOnTop;
}
/**
* Returns true if auto width is enabled.
*
* @return the auto width state
*/
public boolean getAutoWidth() {
return autoWidth;
}
/**
* Returns true if fill is enabled.
*
* @return the fill state
*/
public boolean getFill() {
return fill;
}
/**
* Returns true if the collapse tool is hidden.
*
* @return the hide collapse tool state
*/
public boolean getHideCollapseTool() {
return hideCollapseTool;
}
/**
* Returns true if title collapse is enabled.
*
* @return the title collapse state
*/
public boolean getTitleCollapse() {
return titleCollapse;
}
public boolean isSequence() {
return sequence;
}
/**
* Sets the active item.
*
* @param item the active item
*/
public void setActiveItem(Component item) {
if (container == null || !container.isRendered()) {
activeItem = item;
return;
}
((ContentPanel) activeItem).expand();
}
/**
* True to swap the position of each panel as it is expanded so that it
* becomes the first item in the container, false to keep the panels in the
* rendered order. (defaults to false).
*
* @param activeOnTop true to keep the active item on top
*/
public void setActiveOnTop(boolean activeOnTop) {
this.activeOnTop = activeOnTop;
}
/**
* True to set each contained item's width to 'auto', false to use the item's
* current width (defaults to false).
*
* @param autoWidth true for auto width
*/
public void setAutoWidth(boolean autoWidth) {
this.autoWidth = autoWidth;
}
/**
* True to adjust the active item's height to fill the available space in the
* container, false to use the item's current height (defaults to true).
*
* @param fill true to fill
*/
public void setFill(boolean fill) {
this.fill = fill;
}
/**
* True to hide the contained panels' collapse/expand toggle buttons, false to
* display them (defaults to false). When set to true, {@link #titleCollapse}
* should be true also.
*
* @param hideCollapseTool true to hide
*/
public void setHideCollapseTool(boolean hideCollapseTool) {
this.hideCollapseTool = hideCollapseTool;
}
public void setSequence(boolean sequence) {
this.sequence = sequence;
}
/**
* True to allow expand/collapse of each contained panel by clicking anywhere
* on the title bar, false to allow expand/collapse only when the toggle tool
* button is clicked (defaults to true). When set to false,
* {@link #hideCollapseTool} should be false also.
*
* @param titleCollapse true for title collapse
*/
public void setTitleCollapse(boolean titleCollapse) {
this.titleCollapse = titleCollapse;
}
protected void onBeforeExpand(ComponentEvent ce) {
final ContentPanel ai = (ContentPanel) activeItem;
if (activeItem != null) {
if (sequence) {
final ContentPanel p = ce.getComponent();
activeItem = null;
if (!ai.isCollapsed()) {
Listener<ComponentEvent> l = new Listener<ComponentEvent>() {
public void handleEvent(ComponentEvent be) {
ai.removeListener(Events.Collapse, this);
p.expand();
}
};
ai.addListener(Events.Collapse, l);
ai.collapse();
ce.setCancelled(true);
return;
}
} else {
ai.collapse();
}
}
activeItem = ce.getComponent();
if (activeOnTop) {
target.insertChild(activeItem.getElement(), 0);
}
}
protected void onExpand(ComponentEvent ce) {
layout();
}
@Override
protected void renderComponent(Component component, int index, El target) {
ContentPanel cp = (ContentPanel) component;
if (!cp.isRendered()) {
cp.setCollapsible(true);
if (titleCollapse) {
cp.setTitleCollapse(true);
}
if (hideCollapseTool) {
cp.setHideCollapseTool(true);
}
}
if (autoWidth) {
cp.setAutoWidth(autoWidth);
}
super.renderComponent(component, index, target);
if (activeItem == null || activeItem == component) {
activeItem = component;
} else {
cp.collapse();
}
El.fly(cp.getElement("header")).addStyleName("x-accordion-hd");
cp.addListener(Events.BeforeExpand, listener);
cp.addListener(Events.Expand, elistener);
}
@Override
protected void setItemSize(Component item, Size size) {
if (fill && item != null) {
int count = container.getItemCount();
int hh = 0;
for (int i = 0, len = count; i < len; i++) {
ContentPanel cp = (ContentPanel) container.getItem(i);
if (cp != item) {
hh += (cp.getOffsetHeight() - El.fly(cp.getElement("bwrap")).getHeight());
if (!autoWidth) {
cp.setWidth(size.width);
}
}
}
size.height -= hh;
ContentPanel cp = (ContentPanel) item;
if (cp.isExpanded()) {
setSize(item, size.width, size.height);
}
}
}
}