/*
* 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.layout;
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.event.ButtonEvent;
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.event.MenuEvent;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.widget.Component;
import com.extjs.gxt.ui.client.widget.ComponentHelper;
import com.extjs.gxt.ui.client.widget.Container;
import com.extjs.gxt.ui.client.widget.Layout;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.button.ButtonGroup;
import com.extjs.gxt.ui.client.widget.button.SplitButton;
import com.extjs.gxt.ui.client.widget.menu.HeaderMenuItem;
import com.extjs.gxt.ui.client.widget.menu.Menu;
import com.extjs.gxt.ui.client.widget.menu.MenuItem;
import com.extjs.gxt.ui.client.widget.menu.SeparatorMenuItem;
import com.extjs.gxt.ui.client.widget.toolbar.FillToolItem;
import com.extjs.gxt.ui.client.widget.toolbar.SeparatorToolItem;
import com.extjs.gxt.ui.client.widget.toolbar.ToolBar;
import com.google.gwt.dom.client.Node;
import com.google.gwt.dom.client.NodeList;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
public class ToolBarLayout extends Layout {
protected Button more;
protected Menu moreMenu;
private Listener<ComponentEvent> containerListener;
private El extrasTr;
private List<Component> hiddens;
private boolean lastOverflow = false;
private int lastWidth = 0;
private El leftTr;
private String noItemsMenuText = "<div class=\"x-toolbar-no-items\">(None)</div>";
private El rightTr;
private int spacing = 0;
private int triggerWidth = 18;
public ToolBarLayout() {
monitorResize = true;
hiddens = new ArrayList<Component>();
targetStyleName = "x-toolbar-layout-ct";
}
/**
* Returns the button used when the toolbar has overflow.
*
* @return the button
*/
public Button getMoreButton() {
return more;
}
/**
* Returns the no menu item text.
*
* @return the no menu item text
*/
public String getNoItemsMenuText() {
return noItemsMenuText;
}
/**
* Returns the item spacing.
*
* @return the spacing
*/
public int getSpacing() {
return spacing;
}
@Override
public void setContainer(Container<?> ct) {
if (containerListener == null) {
containerListener = new Listener<ComponentEvent>() {
public void handleEvent(ComponentEvent be) {
if (be.getType() == Events.Attach && lastOverflow) {
ComponentHelper.doAttach(more);
} else if (be.getType() == Events.Detach && lastOverflow) {
ComponentHelper.doDetach(more);
}
}
};
}
if (this.container != null) {
this.container.removeListener(Events.Attach, containerListener);
this.container.removeListener(Events.Detach, containerListener);
}
super.setContainer(ct);
if (this.container != null) {
this.container.addListener(Events.Attach, containerListener);
this.container.addListener(Events.Detach, containerListener);
}
}
/**
* Sets the no menu items text (defaults to '<div
* class=\"x-toolbar-no-items\">(None)</div>').
*
* @param noItemsMenuText the no menu items text
*/
public void setNoItemsMenuText(String noItemsMenuText) {
this.noItemsMenuText = noItemsMenuText;
}
/**
* Sets the amount of spacing between items (defaults to 0).
*
* @param spacing the spacing
*/
public void setSpacing(int spacing) {
this.spacing = spacing;
}
protected void addComponentToMenu(Menu menu, Component c) {
if (c instanceof SeparatorToolItem) {
menu.add(new SeparatorMenuItem());
} else if (c instanceof SplitButton) {
final SplitButton sb = (SplitButton) c;
MenuItem item = new MenuItem(sb.getText(), sb.getIcon());
item.setEnabled(c.isEnabled());
item.setItemId(c.getItemId());
if (sb.getData("gxt-menutext") != null) {
item.setText(sb.getData("gxt-menutext").toString());
}
if (sb.getMenu() != null) {
item.setSubMenu(sb.getMenu());
}
item.addSelectionListener(new SelectionListener<MenuEvent>() {
@Override
public void componentSelected(MenuEvent ce) {
ButtonEvent e = new ButtonEvent(sb);
e.setEvent(ce.getEvent());
sb.fireEvent(Events.Select, e);
}
});
menu.add(item);
} else if (c instanceof Button) {
final Button b = (Button) c;
MenuItem item = new MenuItem(b.getText(), b.getIcon());
item.setItemId(c.getItemId());
if (b.getData("gxt-menutext") != null) {
item.setText(b.getData("gxt-menutext").toString());
}
if (b.getMenu() != null) {
item.setHideOnClick(false);
item.setSubMenu(b.getMenu());
}
item.setEnabled(c.isEnabled());
item.addSelectionListener(new SelectionListener<MenuEvent>() {
@Override
public void componentSelected(MenuEvent ce) {
ButtonEvent e = new ButtonEvent(b);
e.setEvent(ce.getEvent());
b.fireEvent(Events.Select, e);
}
});
menu.add(item);
} else if (c instanceof ButtonGroup) {
ButtonGroup g = (ButtonGroup) c;
g.setItemId(c.getItemId());
menu.add(new SeparatorMenuItem());
String heading = g.getHeading();
if (heading != null && heading.length() > 0 && !heading.equals(" ")) {
menu.add(new HeaderMenuItem(g.getHeading()));
}
for (Component c2 : g.getItems()) {
addComponentToMenu(menu, c2);
}
menu.add(new SeparatorMenuItem());
}
if (menu.getItemCount() > 0) {
if (menu.getItem(0) instanceof SeparatorMenuItem) {
menu.remove(menu.getItem(0));
}
if (menu.getItemCount() > 0) {
if (menu.getItem(menu.getItemCount() - 1) instanceof SeparatorMenuItem) {
menu.remove(menu.getItem(menu.getItemCount() - 1));
}
}
}
}
protected void cleanup(El row) {
NodeList<Node> cn = row.dom.getChildNodes();
for (int i = cn.getLength() - 1; i >= 0; i--) {
Element td = (Element) cn.getItem(i);
if (!td.hasChildNodes()) {
row.dom.removeChild(td);
}
}
}
protected void clearMenu() {
moreMenu.removeAll();
}
protected void fitToSize(El t) {
if (!((ToolBar) container).isEnableOverflow()) {
return;
}
if (target.getWidth() < 1) {
return;
}
int w = t.getWidth(true);
int lw = lastWidth;
lastWidth = w;
int iw = t.firstChild().getWidth(true);
int clipWidth = w - triggerWidth;
if (iw > w || (hiddens != null && hiddens.size() > 0 && w >= lw)) {
int loopWidth = 0;
for (Component c : container.getItems()) {
if (!(c instanceof FillToolItem)) {
loopWidth += getComponentWidth(c);
if (loopWidth >= clipWidth) {
if (!isHidden(c)) {
c.setData("gxt-overflow", "true");
hideComponent(c);
}
} else {
if (isHidden(c)) {
c.setData("gxt-overflow", null);
unhideComponent(c);
}
}
}
}
}
if (hiddens != null && hiddens.size() > 0) {
initMore();
if (!lastOverflow) {
lastOverflow = true;
}
} else if (more != null) {
ComponentHelper.doDetach(more);
more.el().removeFromParent();
if (lastOverflow) {
lastOverflow = false;
}
}
}
protected int getComponentWidth(Component c) {
return (Integer) (c.getData("xtbWidth") != null ? c.getData("xtbWidth") : c.el().getParent().getWidth());
}
protected void hideComponent(Component c) {
c.setData("xtbWidth", c.el().getParent().getWidth());
c.setData("xtbIsVisible", c.isVisible(false));
hiddens.add(c);
c.hide();
}
protected void initMore() {
if (more == null) {
moreMenu = new Menu();
moreMenu.addListener(Events.BeforeShow, new Listener<MenuEvent>() {
public void handleEvent(MenuEvent be) {
clearMenu();
for (Component c : container.getItems()) {
if (isHidden(c)) {
addComponentToMenu(be.getContainer(), c);
}
}
// put something so the menu isn't empty
// if no compatible items found
if (be.getContainer().getItemCount() == 0) {
be.getContainer().add(new HeaderMenuItem(noItemsMenuText));
}
}
});
more = new Button();
more.addStyleName("x-toolbar-more");
more.setIcon(GXT.IMAGES.toolbar_more());
more.setMenu(moreMenu);
ComponentHelper.setParent(container, more);
if (GXT.isAriaEnabled()) {
more.setTitle("More items...");
}
}
Element td = insertCell(more, extrasTr, 100);
if (more.isRendered()) {
td.appendChild(more.el().dom);
} else {
more.render(td);
}
if (container.isAttached()) {
ComponentHelper.doAttach(more);
}
}
protected Element insertCell(Component c, El side, int pos) {
Element td = DOM.createTD();
td.setClassName("x-toolbar-cell");
td.setAttribute("role", "presentation");
Element point;
if (pos >= side.dom.getChildNodes().getLength()) {
point = null;
} else {
point = side.getChild(pos) != null ? side.getChild(pos).dom : null;
}
side.insertBefore(td, point);
return td;
}
protected boolean isHidden(Component c) {
return hiddens != null && hiddens.contains(c);
}
@Override
protected void onComponentHide(Component component) {
super.onComponentHide(component);
if (component.isRendered()) {
component.el().getParent().addStyleName(component.getHideMode().value());
}
}
@Override
protected void onComponentShow(Component component) {
super.onComponentShow(component);
if (component.isRendered()) {
component.el().getParent().removeStyleName(component.getHideMode().value());
}
}
protected void onLayout(Container<?> container, El target) {
if (leftTr == null) {
target.insertHtml(
"beforeEnd",
"<table cellspacing=\"0\" class=\"x-toolbar-ct\" role=\"presentation\"><tbody><tr><td class=\"x-toolbar-left\" align=\"left\"><table cellspacing=\"0\" role=\"presentation\"><tbody><tr class=\"x-toolbar-left-row\"></tr></tbody></table></td><td class=\"x-toolbar-right\" align=\"right\"><table cellspacing=\"0\" class=\"x-toolbar-right-ct\" role=\"presentation\"><tbody><tr><td><table cellspacing=\"0\" role=\"presentation\"><tbody><tr class=\"x-toolbar-right-row\" role=\"presentation\"></tr></tbody></table></td><td><table cellspacing=\"0\" role=\"presentation\"><tbody><tr class=\"x-toolbar-extras-row\"></tr></tbody></table></td></tr></tbody></table></td></tr></tbody></table>");
leftTr = target.child("tr.x-toolbar-left-row");
rightTr = target.child("tr.x-toolbar-right-row");
extrasTr = target.child("tr.x-toolbar-extras-row");
leftTr.dom.setAttribute("role", "presentation");
rightTr.dom.setAttribute("role", "presentation");
extrasTr.dom.setAttribute("role", "presentation");
}
El side = leftTr;
int pos = 0;
for (int i = 0, len = container.getItemCount(); i < len; i++, pos++) {
Component c = container.getItem(i);
if (c instanceof FillToolItem) {
side = rightTr;
pos = -1;
} else if (!c.isRendered()) {
c.render(insertCell(c, side, pos));
if (i < len - 1) {
c.el().setStyleAttribute("marginRight", spacing + "px");
} else {
c.el().setStyleAttribute("marginRight", "0px");
}
} else {
if (!isHidden(c) && !isValidParent(c.el().dom, side.getChildElement(pos))) {
Element td = insertCell(c, side, pos);
td.appendChild(c.el().dom);
if (i < len - 1) {
c.el().setStyleAttribute("marginRight", spacing + "px");
} else {
c.el().setStyleAttribute("marginRight", "0px");
}
}
}
}
// strip extra empty cells
cleanup(leftTr);
cleanup(rightTr);
cleanup(extrasTr);
fitToSize(target);
}
protected void unhideComponent(Component c) {
if (hiddens.remove(c)) {
Boolean b = c.getData("xtbIsVisible");
if (b) {
c.show();
}
c.setData("xtbWidth", null);
c.setData("xtbIsVisible", null);
}
}
}