All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.extjs.gxt.ui.client.widget.Container Maven / Gradle / Ivy

There is a newer version: 2.3.1-gwt22
Show newest version
/*
 * Sencha GXT 2.3.1 - Sencha for GWT
 * Copyright(c) 2007-2013, Sencha, Inc.
 * [email protected]
 * 
 * http://www.sencha.com/products/gxt/license/
 */
 package com.extjs.gxt.ui.client.widget;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

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.ContainerEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.LayoutEvent;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.widget.layout.FlowLayout;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.Widget;

/**
 * Class for any {@link BoxComponent} that can contain other components.
 * Containers handle the basic behavior of containing components, namely
 * managing, attaching, and detaching the child widgets.
 * 
 * 

* When children are added to a container they are not physically added to the * DOM of the container. Subclasses are responsible for connecting the child * components. * *

* Container does not define a root element. setElement must be called by any * subclass to ensure the container has an element. * *

*
Events:
* *
BeforeAdd : ContainerEvent(container, item, index)
*
Fires before a item is added or inserted. Listeners can cancel the * action by calling {@link BaseEvent#setCancelled(boolean)}.
*
    *
  • container : this
  • *
  • item : the component being added
  • *
  • index : the index at which the component will be added
  • *
*
* *
BeforeRemove : ContainerEvent(container, item)
*
Fires before a item is removed. Listeners can cancel the action by * calling {@link BaseEvent#setCancelled(boolean)}.
*
    *
  • container : this
  • *
  • item : the component being removed
  • *
*
* *
Add : ContainerEvent(container, item, index)
*
Fires after a item has been added or inserted.
*
    *
  • container : this
  • *
  • item : the item that was added
  • *
  • index : the index at which the item will be added
  • *
*
* *
Remove : ContainerEvent(container, item)
*
Fires after a item has been removed.
*
    *
  • container : this
  • *
  • item : the item being removed
  • *
*
*
* *
*
Inherited Events:
*
BoxComponent Move
*
BoxComponent Resize
*
Component Enable
*
Component Disable
*
Component BeforeHide
*
Component Hide
*
Component BeforeShow
*
Component Show
*
Component Attach
*
Component Detach
*
Component BeforeRender
*
Component Render
*
Component BrowserEvent
*
Component BeforeStateRestore
*
Component StateRestore
*
Component BeforeStateSave
*
Component SaveState
*
* * @param the child component type */ public abstract class Container extends BoxComponent { /** * True to attach the container's children (defaults to true). */ protected boolean attachChildren = true; /** * False to disable the container's layout, stopping it from executing * (defaults to false). */ protected boolean enableLayout; /** * True to execute the container's layout when children are inserted and * removed (defaults to false). */ protected boolean layoutOnChange; protected boolean layoutExecuted; protected boolean layoutNeeded = true; protected boolean layoutOnAttach = true; Listener layoutListener; private List items; private Layout layout; /** * Creates a new container. */ public Container() { items = new ArrayList(); } @Override public void disable() { super.disable(); for (Component c : items) { c.disable(); } } @Override public void enable() { super.enable(); for (Component c : items) { c.enable(); } } /** * Returns the component whose element, or child element, matches the given * element. * * @param elem the element * @return the matching component or null if no match */ public T findItem(Element elem) { for (T c : items) { if (DOM.isOrHasChild(c.getElement(), elem)) { return c; } } return null; } /** * Returns the item at the given index or null if index out of bounds. * * @param index the index * @return the item */ public T getItem(int index) { return index < items.size() ? items.get(index) : null; } /** * Returns the item with the specified item id. * * @param itemId the item id * @return the item or null if no match */ public T getItemByItemId(String itemId) { for (T item : getItems()) { if (item.getItemId().equals(itemId)) { return item; } } return null; } /** * Returns the number of children. * * @return the component count */ public int getItemCount() { return items.size(); } /** * Returns the child items. * * @return the children */ public List getItems() { return items; } /** * Returns the container's layout target. Only applies to container's with * layouts. * * @return the layout target */ public El getLayoutTarget() { return el(); } /** * Returns the widget at the given index. If the child is a WidgetComponent, * the wrapped widget is returned. * * @param index the index * @return the widget */ public Widget getWidget(int index) { Component c = getItem(index); if (c != null && c instanceof WidgetComponent) { return ((WidgetComponent) c).getWidget(); } return c; } /** * Returns the index of the item. * * @param item the item * @return the index */ public int indexOf(T item) { return items.indexOf(item); } /** * Returns an iterator over the container's children. * * @return an iterator */ public Iterator iterator() { return items.iterator(); } /** * Removes all the container's items. * * @return true if all items where removed */ public boolean removeAll() { return removeAll(false); } /** * Scrolls the item into view. * * @param item the item */ public void scrollIntoView(T item) { if (rendered && item.isRendered()) { item.el().scrollIntoView(el().dom, false); } } /** * Adds a item to the container. Fires the BeforeAdd event before * inserting, then fires the Add event after the widget has been * inserted. * * @param item the item to be added */ protected boolean add(T item) { return insert(item, getItemCount()); } protected int adjustIndex(T child, int beforeIndex) { int idx = indexOf(child); if (idx != -1) { if (idx < beforeIndex) { beforeIndex--; } } return beforeIndex; } /** * Sets the child's parent to this container. In order to support lazy * rendering this method uses JSNI to simply set the child parent without * effecting the attached state of the child. * * @param child the child widget */ protected void adopt(T child) { child.setParent(this); } @SuppressWarnings({"rawtypes", "unchecked"}) protected ContainerEvent createContainerEvent(T item) { return new ContainerEvent(this, item); } @Override protected void doAttachChildren() { super.doAttachChildren(); attachChildren(); } @Override protected void doDetachChildren() { super.doDetachChildren(); if (attachChildren) { for (T item : items) { if (item.isRendered()) { ComponentHelper.doDetach(item); } } } } protected boolean doLayout() { return doLayout(false); } protected boolean doLayout(boolean force) { if (!enableLayout || (!force && !fireEvent(Events.BeforeLayout, createContainerEvent(null)))) { return false; } if (layout == null) { setLayout(new FlowLayout()); } for (Component c : items) { if (c instanceof ContentPanel) { ((ContentPanel) c).layoutBars(); } } // execute the layout if (force || layoutNeeded) { layout.layout(); } for (Component c : items) { if (c instanceof Composite) { c = ((Composite) c).getComponent(); } if (c instanceof LayoutContainer) { ((LayoutContainer) c).layout(force); } else if (c instanceof Container) { Container con = (Container) c; if (con.layout != null) { con.layout(force); } } else { c.recalculate(); } } onAfterLayout(); fireEvent(Events.AfterLayout, createContainerEvent(null)); return true; } protected Layout getLayout() { return layout; } /** * Adds a item into the container. Fires the BeforeAdd event before * inserting, then fires the Add event after the widget has been * inserted. * * @param item the item to insert * @param index the insert location */ protected boolean insert(T item, int index) { ContainerEvent containerEvent = createContainerEvent(item); containerEvent.setIndex(index); if (fireEvent(Events.BeforeAdd, containerEvent)) { ComponentEvent componentEvent = item.createComponentEvent(null); if (item.fireEvent(Events.BeforeAdopt, componentEvent)) { index = adjustIndex(item, index); item.removeFromParent(); if (item.isRendered()) { // make sure to detach it from the dom first item.el().remove(); } items.add(index, item); onInsert(item, index); adopt(item); item.fireEvent(Events.Adopt, componentEvent); fireEvent(Events.Add, containerEvent); layoutNeeded = true; if (isRendered() && layoutOnChange) { layout(); } return true; } } return false; } protected boolean isLayoutNeeded() { return layoutNeeded; } /** * Executes the container's layout. If a layout has not been set a * FlowLayout will be used. * * @return true if layout was executed. */ protected boolean layout() { return layout(false); } /** * * Executes the container's layout. If a layout has not been set a * FlowLayout will be used. * * @param force true to force the layout call, also if caching things it is * not needed * @return true if layout was executed. */ protected boolean layout(boolean force) { if (!rendered) { layoutOnAttach = true; return false; } return doLayout(force); } protected void notifyHide() { super.notifyHide(); for (Component c : items) { if (!c.hidden && c.isRendered()) { c.notifyHide(); } } } protected void notifyShow() { super.notifyShow(); for (Component c : items) { if (!c.hidden && c.isRendered()) { c.notifyShow(); } } } protected void onAfterLayout() { } @Override protected void onAttach() { super.onAttach(); if (!layoutExecuted && layoutOnAttach) { boolean parentIsContainer = getParent() != null && getParent() instanceof Container; if (parentIsContainer) { Container parent = (Container) getParent(); if (parent.getLayout() == null || getLayout() == null || !getLayout().monitorResize || !getLayout().isRunning()) { layout(); } } else { layout(); } } } protected void onBeforeLayoutExcecuted(Layout layout) { } protected void onInsert(T item, int index) { if (isAutoHeight() || isAutoWidth()) { sync(true); } } protected void onLayoutExcecuted(Layout layout) { layoutExecuted = true; layoutNeeded = false; attachChildren(); sync(true); } protected void onRemove(T item) { if (isAutoHeight() || isAutoWidth()) { sync(true); } } protected final void orphan(T child) { assert (child.getParent() == this); if (child.isAttached()) { ComponentHelper.doDetach(child); assert !child.isAttached() : "Failure of " + getClass() + " to call super.onDetach()"; } child.setParent(null); } /** * Removes the item from the container. Fires the BeforeRemove event * before removing, then fires the Remove event after the widget has * been removed. * * @param item the item to remove * @return true if the item was removed */ protected boolean remove(T item) { return remove(item, false); } @SuppressWarnings({"unchecked", "rawtypes"}) protected boolean remove(T component, boolean force) { ContainerEvent containerEvent = createContainerEvent(component); containerEvent.setItem(component); containerEvent.setIndex(indexOf(component)); if (fireEvent(Events.BeforeRemove, containerEvent) || force) { ComponentEvent componentEvent = component.createComponentEvent(null); if (component.fireEvent(Events.BeforeOrphan, componentEvent) || force) { onRemove(component); if (attachChildren) { assert component.getParent() == this :"component is not a child of this container"; orphan(component); } if (rendered) { Element elem = component.getElement(); Element parent = DOM.getParent(elem); if (parent != null) { DOM.removeChild(parent, elem); } } items.remove(component); component.fireEvent(Events.Orphan, componentEvent); fireEvent(Events.Remove, containerEvent); layoutNeeded = true; if (rendered && layoutOnChange) { layout(); } return true; } } return false; } protected boolean removeAll(boolean force) { int count = getItemCount(); for (int i = 0; i < count; i++) { remove(getItem(0), force); } return getItemCount() == 0; } /** * Sets the container's layout. * * @param layout the new layout */ protected void setLayout(Layout layout) { if (layoutListener == null) { layoutListener = new Listener() { public void handleEvent(LayoutEvent be) { if (be.getType() == Events.BeforeLayout) { onBeforeLayoutExcecuted(be.getLayout()); } else if (be.getType() == Events.AfterLayout) { onLayoutExcecuted(be.getLayout()); } } }; } if (this.layout != null) { this.layout.removeListener(Events.BeforeLayout, layoutListener); this.layout.removeListener(Events.AfterLayout, layoutListener); this.layout.setContainer(null); } this.layout = layout; this.layout.addListener(Events.BeforeLayout, layoutListener); this.layout.addListener(Events.AfterLayout, layoutListener); layoutNeeded = true; layout.setContainer(this); } protected void setLayoutNeeded(boolean layoutNeeded) { this.layoutNeeded = layoutNeeded; } protected void setLayoutOnChange(boolean change) { this.layoutOnChange = change; } /** * Helper Method for the subclasses that wish to support automatic wrapping of * Widget instances in WidgetComponents * *

* If the widget is a component, no wrapping is performed * * @param widget the widget to be wrapped * @return the new component */ protected Component wrapWidget(Widget widget) { if (widget instanceof Component) { return (Component) widget; } else { return new WidgetComponent(widget); } } private void attachChildren() { if (attachChildren && isAttached()) { for (T item : items) { if (item.isRendered()) { ComponentHelper.doAttach(item); } } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy