Tree class
A standard hierarchical tree widget. The tree contains a hierarchy of {@link com.google.gwt.user.client.ui.TreeItem TreeItems} that the user can open, close, and select. <p> <img class='gallery' src='doc-files/Tree.png'/> </p> <h3>CSS Style Rules</h3> <dl> <dt>.gwt-Tree</dt> <dd>the tree itself</dd> <dt>.gwt-Tree .gwt-TreeItem</dt> <dd>a tree item</dd> <dt>.gwt-Tree .gwt-TreeItem-selected</dt> <dd>a selected tree item</dd> </dl> <p> <h3>Example</h3> {@example com.google.gwt.examples.TreeExample} </p>
class Tree extends Widget implements HasTreeItemsForIsWidget, HasWidgetsForIsWidget, Focusable, HasAnimation, HasAllKeyHandlers, HasAllFocusHandlers, HasSelectionHandlers<TreeItem>, HasOpenHandlers<TreeItem>, HasCloseHandlers<TreeItem>, HasAllMouseHandlers { static const int _OTHER_KEY_DOWN = 63233; static const int _OTHER_KEY_LEFT = 63234; static const int _OTHER_KEY_RIGHT = 63235; static const int _OTHER_KEY_UP = 63232; static bool shouldTreeDelegateFocusToElement(dart_html.Element elem) { String name = ""; //elem.nodeName; return ((name == "SELECT") || (name == "INPUT") || (name == "TEXTAREA") || (name == "OPTION") || (name == "BUTTON") || (name == "LABEL")); } static bool isArrowKey(int code) { switch (code) { case _OTHER_KEY_DOWN: case _OTHER_KEY_RIGHT: case _OTHER_KEY_UP: case _OTHER_KEY_LEFT: case KeyCodes.KEY_DOWN: case KeyCodes.KEY_RIGHT: case KeyCodes.KEY_UP: case KeyCodes.KEY_LEFT: return true; default: return false; } } /** * Normalized key codes. Also switches KEY_RIGHT and KEY_LEFT in RTL * languages. */ static int _standardizeKeycode(int code) { switch (code) { case _OTHER_KEY_DOWN: code = KeyCodes.KEY_DOWN; break; case _OTHER_KEY_RIGHT: code = KeyCodes.KEY_RIGHT; break; case _OTHER_KEY_UP: code = KeyCodes.KEY_UP; break; case _OTHER_KEY_LEFT: code = KeyCodes.KEY_LEFT; break; } if (LocaleInfo.getCurrentLocale().isRTL()) { if (code == KeyCodes.KEY_RIGHT) { code = KeyCodes.KEY_LEFT; } else if (code == KeyCodes.KEY_LEFT) { code = KeyCodes.KEY_RIGHT; } } return code; } /** * Map of TreeItem.widget -> TreeItem. */ Map<Widget, TreeItem> _childWidgets = new Map<Widget, TreeItem>(); TreeItem _curSelection; dart_html.Element _focusable; _ImageAdapter _images; String _indentValue = ""; bool _isAnimationEnabled = false; bool _lastWasKeyDown = false; TreeItem _root; bool _useLeafImages; /** * Constructs a tree that uses the specified ClientBundle for images. If this * tree does not use leaf images, the width of the Resources's leaf image will * control the leaf indent. * * @param resources a bundle that provides tree specific images * @param useLeafImages use leaf images from bundle */ Tree([_TreeResource resources = null, bool useLeafImages = false]) { if (resources == null) { _init(new _ImageAdapter(), useLeafImages); } else { _init(new _ImageAdapter(resources), useLeafImages); } } /** * Adds the widget as a root tree item. * * @see com.google.gwt.user.client.ui.HasWidgets#add(com.google.gwt.user.client.ui.Widget) * @param widget widget to add. */ void add(Widget widget) { addWidgetItem(widget); } /** * Overloaded version for IsWidget. * * @see #add(Widget) */ void addIsWidget(IsWidget w) { this.add(Widget.asWidgetOrNull(w)); } HandlerRegistration addBlurHandler(BlurHandler handler) { return addDomHandler(handler, BlurEvent.TYPE); } HandlerRegistration addCloseHandler(CloseHandler<TreeItem> handler) { return addHandler(handler, CloseEvent.TYPE); } HandlerRegistration addFocusHandler(FocusHandler handler) { return addDomHandler(handler, FocusEvent.TYPE); } /** * Adds a simple tree item containing the specified html. * * @param itemHtml the html of the item to be added * @return the item that was added */ TreeItem addSafeHtmlItem(SafeHtml itemHtml) { return _root.addSafeHtmlItem(itemHtml); } /** * Adds an item to the root level of this tree. * * @param item the item to be added */ void addItem(TreeItem item) { _root.addItem(item); } /** * Adds an item to the root level of this tree. * * @param isItem the wrapper of item to be added */ void addIsTreeItem(IsTreeItem isItem) { _root.addIsTreeItem(isItem); } /** * Adds a new tree item containing the specified widget. * * @param widget the widget to be added * @return the new item */ TreeItem addWidgetItem(Widget widget) { return _root.addWidgetItem(widget); } /** * Overloaded version for IsWidget. * * @see #addItem(Widget) */ TreeItem addIsWidgetItem(IsWidget w) { return this.addIsWidgetItem(Widget.asWidgetOrNull(w)); } HandlerRegistration addKeyDownHandler(KeyDownHandler handler) { return addDomHandler(handler, KeyDownEvent.TYPE); } HandlerRegistration addKeyPressHandler(KeyPressHandler handler) { return addDomHandler(handler, KeyPressEvent.TYPE); } HandlerRegistration addKeyUpHandler(KeyUpHandler handler) { return addDomHandler(handler, KeyUpEvent.TYPE); } HandlerRegistration addMouseDownHandler(MouseDownHandler handler) { return addHandler(handler, MouseDownEvent.TYPE); } HandlerRegistration addMouseMoveHandler(MouseMoveHandler handler) { return addDomHandler(handler, MouseMoveEvent.TYPE); } HandlerRegistration addMouseOutHandler(MouseOutHandler handler) { return addDomHandler(handler, MouseOutEvent.TYPE); } HandlerRegistration addMouseOverHandler(MouseOverHandler handler) { return addDomHandler(handler, MouseOverEvent.TYPE); } HandlerRegistration addMouseUpHandler(MouseUpHandler handler) { return addDomHandler(handler, MouseUpEvent.TYPE); } HandlerRegistration addMouseWheelHandler(MouseWheelHandler handler) { return addDomHandler(handler, MouseWheelEvent.TYPE); } HandlerRegistration addOpenHandler(OpenHandler<TreeItem> handler) { return addHandler(handler, OpenEvent.TYPE); } HandlerRegistration addSelectionHandler( SelectionHandler<TreeItem> handler) { return addHandler(handler, SelectionEvent.TYPE); } /** * Adds a simple tree item containing the specified text. * * @param itemText the text of the item to be added * @return the item that was added */ TreeItem addTextItem(String itemText) { return _root.addTextItem(itemText); } /** * Clears all tree items from the current tree. */ void clear() { int size = _root.getChildCount(); for (int i = size - 1; i >= 0; i--) { _root.getChild(i).remove(); } } /** * Ensures that the currently-selected item is visible, opening its parents * and scrolling the tree as necessary. */ void ensureSelectedItemVisible() { if (_curSelection == null) { return; } TreeItem parent = _curSelection.getParentItem(); while (parent != null) { parent.setState(true); parent = parent.getParentItem(); } } /** * Gets the top-level tree item at the specified index. * * @param index the index to be retrieved * @return the item at that index */ TreeItem getItem(int index) { return _root.getChild(index); } /** * Gets the number of items contained at the root of this tree. * * @return this tree's item count */ int getItemCount() { return _root.getChildCount(); } /** * Gets the currently selected item. * * @return the selected item */ TreeItem getSelectedItem() { return _curSelection; } int get tabIndex { return FocusPanel.impl.getTabIndex(_focusable); } /** * Inserts a child tree item at the specified index containing the specified * html. * * @param beforeIndex the index where the item will be inserted * @param itemHtml the html of the item to be added * @return the item that was added * @throws IndexOutOfBoundsException if the index is out of range */ TreeItem insertSafeHtmlItem(int beforeIndex, SafeHtml itemHtml) { return _root.insertSafeHtmlItem(beforeIndex, itemHtml); } /** * Inserts an item into the root level of this tree. * * @param beforeIndex the index where the item will be inserted * @param item the item to be added * @throws IndexOutOfBoundsException if the index is out of range */ void insertItem(int beforeIndex, TreeItem item) { _root.insertItem(beforeIndex, item); } /** * Inserts a child tree item at the specified index containing the specified * widget. * * @param beforeIndex the index where the item will be inserted * @param widget the widget to be added * @return the item that was added * @throws IndexOutOfBoundsException if the index is out of range */ TreeItem insertWidgetItem(int beforeIndex, Widget widget) { return _root.insertWidgetItem(beforeIndex, widget); } /** * Inserts a child tree item at the specified index containing the specified * text. * * @param beforeIndex the index where the item will be inserted * @param itemText the text of the item to be added * @return the item that was added * @throws IndexOutOfBoundsException if the index is out of range */ TreeItem insertTextItem(int beforeIndex, String itemText) { return _root.insertTextItem(beforeIndex, itemText); } bool isAnimationEnabled() { return _isAnimationEnabled; } Iterator<Widget> iterator() { List<Widget> widgets = new List<Widget>.from(_childWidgets.keys); return WidgetIterators.createWidgetIterator(this, widgets); } // @SuppressWarnings("fallthrough") void onBrowserEvent(dart_html.Event event) { int eventType = Dom.eventGetType(event); switch (eventType) { case IEvent.ONKEYDOWN: // If nothing's selected, select the first item. if (_curSelection == null) { if (_root.getChildCount() > 0) { _onSelection(_root.getChild(0), true, true); } super.onBrowserEvent(event); return; } break; // Intentional fallthrough. case IEvent.ONKEYPRESS: case IEvent.ONKEYUP: dart_html.KeyboardEvent kEvent = event as dart_html.KeyboardEvent; // Issue 1890: Do not block history navigation via alt+left/right if (kEvent.altKey || kEvent.metaKey) { super.onBrowserEvent(event); return; } break; } switch (eventType) { case IEvent.ONCLICK: dart_html.Element e = event.target as dart_html.Element; if (shouldTreeDelegateFocusToElement(e)) { // The click event should have given focus to this element already. // Avoid moving focus back up to the tree (so that focusable widgets // attached to TreeItems can receive keyboard events). } else if ((_curSelection != null) && Dom.isOrHasChild(_curSelection.getContentElem(), e)) { focus = true; } break; case IEvent.ONMOUSEDOWN: // Currently, the way we're using image bundles causes extraneous events // to be sunk on individual items' open/close images. This leads to an // extra event reaching the Tree, which we will ignore here. // Also, ignore middle and right clicks here. dart_html.MouseEvent mEvent = event as dart_html.MouseEvent; if (mEvent.currentTarget == getElement() && mEvent.button == IEvent.BUTTON_LEFT) { _elementClicked(event.target as dart_html.Element); } break; case IEvent.ONKEYDOWN: _keyboardNavigation(event); _lastWasKeyDown = true; break; case IEvent.ONKEYPRESS: if (!_lastWasKeyDown) { _keyboardNavigation(event); } _lastWasKeyDown = false; break; case IEvent.ONKEYUP: dart_html.KeyboardEvent kEvent = event as dart_html.KeyboardEvent; if (kEvent.keyCode == KeyCodes.KEY_TAB) { List<dart_html.Element> chain = new List<dart_html.Element>(); _collectElementChain(chain, getElement(), event.target); TreeItem item = _findItemByChain(chain, 0, _root); if (item != getSelectedItem()) { setSelectedItem(item, true); } } _lastWasKeyDown = false; break; } switch (eventType) { case IEvent.ONKEYDOWN: case IEvent.ONKEYUP: dart_html.KeyboardEvent kEvent = event as dart_html.KeyboardEvent; if (isArrowKey(kEvent.keyCode)) { // event.cancelBubble = true; event.preventDefault(); return; } break; } // We must call super for all handlers. super.onBrowserEvent(event); } bool remove(Widget w) { // Validate. TreeItem item = _childWidgets[w]; if (item == null) { return false; } // Delegate to TreeItem.setWidget, which performs correct removal. item.setWidget(null); return true; } /** * Overloaded version for IsWidget. * * @see #remove(Widget) */ bool removeIsWidget(IsWidget w) { return this.remove(w.asWidget()); } /** * Removes an item from the root level of this tree. * * @param item the item to be removed */ void removeItem(TreeItem item) { _root.removeItem(item); } /** * Removes an item from the _root level of this tree. * * @param isItem the wrapper of item to be removed */ void removeIsTreeItem(IsTreeItem isItem) { if (isItem != null) { TreeItem item = isItem.asTreeItem(); removeItem(item); } } /** * Removes all items from the root level of this tree. */ void removeItems() { while (getItemCount() > 0) { removeItem(getItem(0)); } } void set accessKey(int key) { FocusPanel.impl.setAccessKey(_focusable, key); } void setAnimationEnabled(bool enable) { _isAnimationEnabled = enable; } void set focus(bool val) { if (val) { FocusPanel.impl.focus(_focusable); } else { FocusPanel.impl.blur(_focusable); } } /** * Selects a specified item. * * @param item the item to be selected, or <code>null</code> to deselect all * items * @param fireEvents <code>true</code> to allow selection events to be fired */ void setSelectedItem(TreeItem item, [bool fireEvents = true]) { if (item == null) { if (_curSelection == null) { return; } _curSelection.setSelected(false); _curSelection = null; return; } _onSelection(item, fireEvents, true); } void set tabIndex(int index) { FocusPanel.impl.setTabIndex(_focusable, index); } /** * Iterator of tree items. * * @return the iterator */ Iterator<TreeItem> treeItemIterator() { List<TreeItem> accum = new List<TreeItem>(); _root.addTreeItems(accum); return accum.iterator; } void doAttachChildren() { try { AttachDetachException.tryCommand(this.iterator(), AttachDetachException.attachCommand); } finally { Dom.setEventListener(_focusable, this); } } void doDetachChildren() { try { AttachDetachException.tryCommand(this.iterator(), AttachDetachException.detachCommand); } finally { Dom.setEventListener(_focusable, null); } } /** * Indicates if keyboard navigation is enabled for the Tree and for a given * TreeItem. Subclasses of Tree can override this function to selectively * enable or disable keyboard navigation. * * @param currentItem the currently selected TreeItem * @return <code>true</code> if the Tree will response to arrow keys by * changing the currently selected item */ bool isKeyboardNavigationEnabled(TreeItem currentItem) { return true; } void onLoad() { _root.updateStateRecursive(); } void adopt(Widget widget, TreeItem treeItem) { assert (!_childWidgets.containsKey(widget)); _childWidgets[widget] = treeItem; widget.setParent(this); } void fireStateChanged(TreeItem item, bool open) { if (open) { OpenEvent.fire(this, item); } else { CloseEvent.fire(this, item); } } /* * This method exists solely to support unit tests. */ Map<Widget, TreeItem> getChildWidgets() { return _childWidgets; } _ImageAdapter getImages() { return _images; } void maybeUpdateSelection(TreeItem itemThatChangedState, bool isItemOpening) { /** * If we just closed the item, let's check to see if this item is the parent * of the currently selected item. If so, we should make this item the * currently selected selected item. */ if (!isItemOpening) { TreeItem tempItem = _curSelection; while (tempItem != null) { if (tempItem == itemThatChangedState) { setSelectedItem(itemThatChangedState); return; } tempItem = tempItem.getParentItem(); } } } void orphan(Widget widget) { // Validation should already be done. assert (widget.getParent() == this); // Orphan. try { widget.setParent(null); } finally { // Logical detach. _childWidgets.remove(widget); } } /** * Called only from {@link TreeItem}: Shows the closed image on that tree * item. * * @param treeItem the tree item */ void showClosedImage(TreeItem treeItem) { _showImage(treeItem, _images.treeClosed()); } /** * Called only from {@link TreeItem}: Shows the leaf image on a tree item. * * @param treeItem the tree item */ void showLeafImage(TreeItem treeItem) { if (_useLeafImages || treeItem.isFullNode()) { _showImage(treeItem, _images.treeLeaf()); } else if (LocaleInfo.getCurrentLocale().isRTL()) { treeItem.getElement().style.paddingRight = _indentValue; } else { treeItem.getElement().style.paddingLeft = _indentValue; } } /** * Called only from {@link TreeItem}: Shows the open image on a tree item. * * @param treeItem the tree item */ void showOpenImage(TreeItem treeItem) { _showImage(treeItem, _images.treeOpen()); } /** * Collects parents going up the element tree, terminated at the tree root. */ void _collectElementChain(List<dart_html.Element> chain, dart_html.Element hRoot, dart_html.Element hElem) { if ((hElem == null) || (hElem == hRoot)) { return; } _collectElementChain(chain, hRoot, hElem.parent); chain.add(hElem); } bool _elementClicked(dart_html.Element hElem) { List<dart_html.Element> chain = new List<dart_html.Element>(); _collectElementChain(chain, getElement(), hElem); TreeItem item = _findItemByChain(chain, 0, _root); if (item != null && item != _root) { if (item.getChildCount() > 0 && Dom.isOrHasChild(item.getImageElement(), hElem)) { item.setState(!item.getState(), true); return true; } else if (Dom.isOrHasChild(item.getElement(), hElem)) { _onSelection(item, true, !shouldTreeDelegateFocusToElement(hElem)); return true; } } return false; } TreeItem _findDeepestOpenChild(TreeItem item) { if (!item.getState()) { return item; } return _findDeepestOpenChild(item.getChild(item.getChildCount() - 1)); } TreeItem _findItemByChain(List<dart_html.Element> chain, int idx, TreeItem root) { if (idx == chain.length) { return root; } dart_html.Element hCurElem = chain[idx]; for (int i = 0, n = root.getChildCount(); i < n; ++i) { TreeItem child = root.getChild(i); if (child.getElement() == hCurElem) { TreeItem retItem = _findItemByChain(chain, idx + 1, root.getChild(i)); if (retItem == null) { return child; } return retItem; } } return _findItemByChain(chain, idx + 1, root); } /** * Get the top parent above this {@link TreeItem} that is in closed state. In * other words, get the parent that is guaranteed to be visible. * * @param item * @return the closed parent, or null if all parents are opened */ TreeItem _getTopClosedParent(TreeItem item) { TreeItem topClosedParent = null; TreeItem parent = item.getParentItem(); while (parent != null && parent != _root) { if (!parent.getState()) { topClosedParent = parent; } parent = parent.getParentItem(); } return topClosedParent; } void _init(_ImageAdapter images, bool useLeafImages) { _setImages(images, useLeafImages); setElement(new dart_html.DivElement()); getElement().style.position = "relative"; // Fix rendering problem with relatively-positioned elements and their // children by // forcing the element that is positioned relatively to 'have layout' getElement().style.zoom = "1"; _focusable = FocusPanel.impl.createFocusable(); _focusable.style.fontSize = "0"; _focusable.style.position = "absolute"; // Hide focus outline in Mozilla/Webkit/Opera _focusable.style.outline = "0px"; // Hide focus outline in IE 6/7 Dom.setElementAttribute(_focusable, "hideFocus", "true"); Dom.setIntStyleAttribute(_focusable, "zIndex", -1); getElement().append(_focusable); sinkEvents(IEvent.ONMOUSEDOWN | IEvent.ONCLICK | IEvent.KEYEVENTS); Dom.sinkEvents(_focusable, IEvent.FOCUSEVENTS); // The 'root' item is invisible and serves only as a container // for all top-level items. _root = new TreeItem(isRoot:true); _root.setTree(this); clearAndSetStyleName("dwt-Tree"); // Add a11y role "tree" // Roles.getTreeRole().set(_focusable); } void _keyboardNavigation(dart_html.Event event) { // Handle keyboard events if keyboard navigation is enabled if (isKeyboardNavigationEnabled(_curSelection)) { dart_html.KeyboardEvent kEvent = event as dart_html.KeyboardEvent; int code = kEvent.keyCode; switch (_standardizeKeycode(code)) { case KeyCodes.KEY_UP: _moveSelectionUp(_curSelection); break; case KeyCodes.KEY_DOWN: _moveSelectionDown(_curSelection, true); break; case KeyCodes.KEY_LEFT: _maybeCollapseTreeItem(); break; case KeyCodes.KEY_RIGHT: _maybeExpandTreeItem(); break; default: return; } } } void _maybeCollapseTreeItem() { TreeItem topClosedParent = _getTopClosedParent(_curSelection); if (topClosedParent != null) { // Select the first visible parent if _curSelection is hidden setSelectedItem(topClosedParent); } else if (_curSelection.getState()) { _curSelection.setState(false); } else { TreeItem parent = _curSelection.getParentItem(); if (parent != null) { setSelectedItem(parent); } } } void _maybeExpandTreeItem() { TreeItem topClosedParent = _getTopClosedParent(_curSelection); if (topClosedParent != null) { // Select the first visible parent if _curSelection is hidden setSelectedItem(topClosedParent); } else if (!_curSelection.getState()) { _curSelection.setState(true); } else if (_curSelection.getChildCount() > 0) { setSelectedItem(_curSelection.getChild(0)); } } /** * Move the tree focus to the specified selected item. */ void _moveFocus() { Focusable focusableWidget = _curSelection.getFocusable(); if (focusableWidget != null) { focusableWidget.focus = true; Dom.scrollIntoView((focusableWidget as Widget).getElement()); } else { // Get the location and size of the given item's content element relative // to the tree. dart_html.Element selectedElem = _curSelection.getContentElem(); int containerLeft = getAbsoluteLeft(); int containerTop = getAbsoluteTop(); int left = Dom.getAbsoluteLeft(selectedElem) - containerLeft; int top = Dom.getAbsoluteTop(selectedElem) - containerTop; int width = Dom.getElementPropertyInt(selectedElem, "offsetWidth"); int height = Dom.getElementPropertyInt(selectedElem, "offsetHeight"); // If the item is not visible, quite here if (width == 0 || height == 0) { Dom.setIntStyleAttribute(_focusable, "left", 0); Dom.setIntStyleAttribute(_focusable, "top", 0); return; } // Set the _focusable element's position and size to exactly underlap the // item's content element. Dom.setStyleAttribute(_focusable, "left", "${left}px"); Dom.setStyleAttribute(_focusable, "top", "${top}px"); Dom.setStyleAttribute(_focusable, "width", "${width}px"); Dom.setStyleAttribute(_focusable, "height", "${height}px"); // Scroll it into view. Dom.scrollIntoView(_focusable); // Update ARIA attributes to reflect the information from the // newly-selected item. _updateAriaAttributes(); // Ensure Focus is set, as focus may have been previously delegated by // tree. focus = true; } } /** * Moves to the next item, going into children as if dig is enabled. */ void _moveSelectionDown(TreeItem sel, bool dig) { if (sel == _root) { return; } // Find a parent that is visible TreeItem topClosedParent = _getTopClosedParent(sel); if (topClosedParent != null) { _moveSelectionDown(topClosedParent, false); return; } TreeItem parent = sel.getParentItem(); if (parent == null) { parent = _root; } int idx = parent.getChildIndex(sel); if (!dig || !sel.getState()) { if (idx < parent.getChildCount() - 1) { _onSelection(parent.getChild(idx + 1), true, true); } else { _moveSelectionDown(parent, false); } } else if (sel.getChildCount() > 0) { _onSelection(sel.getChild(0), true, true); } } /** * Moves the selected item up one. */ void _moveSelectionUp(TreeItem sel) { // Find a parent that is visible TreeItem topClosedParent = _getTopClosedParent(sel); if (topClosedParent != null) { _onSelection(topClosedParent, true, true); return; } TreeItem parent = sel.getParentItem(); if (parent == null) { parent = _root; } int idx = parent.getChildIndex(sel); if (idx > 0) { TreeItem sibling = parent.getChild(idx - 1); _onSelection(_findDeepestOpenChild(sibling), true, true); } else { _onSelection(parent, true, true); } } void _onSelection(TreeItem item, bool fireEvents, bool moveFocus) { // 'root' isn't a real item, so don't let it be selected // (some cases in the keyboard handler will try to do this) if (item == _root) { return; } if (_curSelection != null) { _curSelection.setSelected(false); } _curSelection = item; if (_curSelection != null) { if (moveFocus) { _moveFocus(); } // Select the item and fire the selection event. _curSelection.setSelected(true); if (fireEvents) { SelectionEvent.fire(this, _curSelection); } } } void _setImages(_ImageAdapter images, bool useLeafImages) { this._images = images; this._useLeafImages = useLeafImages; if (!useLeafImages) { Image image = images.treeLeaf().createImage(); image.getElement().style.visibility = "hidden"; RootPanel.get().add(image); int size = image.getWidth() + TreeItem.IMAGE_PAD; image.removeFromParent(); _indentValue = "${size}px"; } } void _showImage(TreeItem treeItem, AbstractImagePrototype proto) { dart_html.Element holder = treeItem.getImageHolderElement(); dart_html.ImageElement child = Dom.getFirstChild(holder) as dart_html.ImageElement; if (child == null) { // If no image element has been created yet, create one from the // prototype. holder.append(proto.createElement()); } else { // Otherwise, simply apply the prototype to the existing element. proto.applyToImageElement(child); } } void _updateAriaAttributes() { dart_html.Element curSelectionContentElem = _curSelection.getContentElem(); // Set the 'aria-level' state. To do this, we need to compute the level of // the currently selected item. // We initialize itemLevel to -1 because the level value is zero-based. // Note that the root node is not a part of the TreeItem hierachy, and we // do not consider the root node to have a designated level. The level of // the root's children is level 0, its children's children is level 1, etc. int curSelectionLevel = -1; TreeItem tempItem = _curSelection; while (tempItem != null) { tempItem = tempItem.getParentItem(); ++curSelectionLevel; } // Roles.getTreeitemRole().setAriaLevelProperty(curSelectionContentElem, curSelectionLevel + 1); // Set the 'aria-setsize' and 'aria-posinset' states. To do this, we need to // compute the the number of siblings that the currently selected item has, // and the item's position among its siblings. TreeItem curSelectionParent = _curSelection.getParentItem(); if (curSelectionParent == null) { curSelectionParent = _root; } // Roles.getTreeitemRole().setAriaSetsizeProperty(curSelectionContentElem, // curSelectionParent.getChildCount()); int curSelectionIndex = curSelectionParent.getChildIndex(_curSelection); // Roles.getTreeitemRole().setAriaPosinsetProperty(curSelectionContentElem, // curSelectionIndex + 1); // Set the 'aria-expanded' state. This depends on the state of the currently // selected item. // If the item has no children, we remove the 'aria-expanded' state. // if (_curSelection.getChildCount() == 0) { // Roles.getTreeitemRole().removeAriaExpandedState(curSelectionContentElem); // // } else { // Roles.getTreeitemRole().setAriaExpandedState(curSelectionContentElem, // ExpandedValue.of(_curSelection.getState())); // } // Make sure that 'aria-selected' is true. // Roles.getTreeitemRole().setAriaSelectedState(curSelectionContentElem, // SelectedValue.of(true)); // Update the 'aria-activedescendant' state for the focusable element to // match the id of the currently selected item // Roles.getTreeRole().setAriaActivedescendantProperty(_focusable, // IdReference.of(Dom.getElementAttribute(curSelectionContentElem, "id"))); } }
Extends
Implements
HasAllMouseHandlers, HasCloseHandlers<TreeItem>, HasOpenHandlers<TreeItem>, HasSelectionHandlers<TreeItem>, HasAllFocusHandlers, HasAllKeyHandlers, HasAnimation, Focusable, HasWidgetsForIsWidget, HasTreeItemsForIsWidget
Static Methods
bool shouldTreeDelegateFocusToElement(Element elem) #
static bool shouldTreeDelegateFocusToElement(dart_html.Element elem) { String name = ""; //elem.nodeName; return ((name == "SELECT") || (name == "INPUT") || (name == "TEXTAREA") || (name == "OPTION") || (name == "BUTTON") || (name == "LABEL")); }
bool isArrowKey(int code) #
static bool isArrowKey(int code) { switch (code) { case _OTHER_KEY_DOWN: case _OTHER_KEY_RIGHT: case _OTHER_KEY_UP: case _OTHER_KEY_LEFT: case KeyCodes.KEY_DOWN: case KeyCodes.KEY_RIGHT: case KeyCodes.KEY_UP: case KeyCodes.KEY_LEFT: return true; default: return false; } }
Constructors
new Tree([_TreeResource resources = null, bool useLeafImages = false]) #
Constructs a tree that uses the specified ClientBundle for images. If this tree does not use leaf images, the width of the Resources's leaf image will control the leaf indent.
@param resources a bundle that provides tree specific images @param useLeafImages use leaf images from bundle
Tree([_TreeResource resources = null, bool useLeafImages = false]) { if (resources == null) { _init(new _ImageAdapter(), useLeafImages); } else { _init(new _ImageAdapter(resources), useLeafImages); } }
Properties
void set accessKey(int key) #
Sets the widget's 'access key'. This key is used (in conjunction with a browser-specific modifier key) to automatically focus the widget.
@param key the widget's access key
void set accessKey(int key) { FocusPanel.impl.setAccessKey(_focusable, key); }
int eventsToSink #
A set og events that should be sunk when the widget is attached to the DOM. (We delay the sinking of events to improve startup performance.) When the widget is attached, this is set is empty
Package protected to allow Composite to see it.
int eventsToSink = 0
void set focus(bool val) #
Explicitly focus/unfocus this widget. Only one widget can have focus at a time, and the widget that does will receive all keyboard events.
@param focused whether this widget should take focus or release it
void set focus(bool val) { if (val) { FocusPanel.impl.focus(_focusable); } else { FocusPanel.impl.blur(_focusable); } }
int get tabIndex #
Gets the widget's position in the tab index.
@return the widget's tab index
int get tabIndex { return FocusPanel.impl.getTabIndex(_focusable); }
void set tabIndex(int index) #
Sets the widget's position in the tab index. If more than one widget has the same tab index, each such widget will receive focus in an arbitrary order. Setting the tab index to <code>-1</code> will cause this widget to be removed from the tab order.
@param index the widget's tab index
void set tabIndex(int index) { FocusPanel.impl.setTabIndex(_focusable, index); }
String get title #
Gets the title associated with this object. The title is the 'tool-tip' displayed to users when they hover over the object.
@return the object's title
String get title => getElement().title;
void set title(String value) #
Sets the element's title.
void set title(String value) { getElement().title = value; }
bool get visible #
Determines whether or not this object is visible. Note that this does not necessarily take into account whether or not the receiver's parent is visible, or even if it is attached to the Document. The default implementation of this trait in UIObject is based on the value of a dom element's style object's display attribute.
@return <code>true</code> if the object is visible
bool get visible => isVisible(getElement());
Methods
void add(Widget widget) #
Adds the widget as a root tree item.
@see com.google.gwt.user.client.ui.HasWidgets#add(com.google.gwt.user.client.ui.Widget) @param widget widget to add.
void add(Widget widget) { addWidgetItem(widget); }
HandlerRegistration addAttachHandler(AttachEventHandler handler) #
Adds an AttachEvent handler.
@param handler the handler @return the handler registration
HandlerRegistration addAttachHandler(AttachEventHandler handler) { return addHandler(handler, AttachEvent.TYPE); }
HandlerRegistration addBitlessDomHandler(EventHandler handler, DomEventType type) #
For <a href= "http://code.google.com/p/google-web-toolkit/wiki/UnderstandingMemoryLeaks"
browsers which do not leak</a>, adds a native event handler to the widget.
Note that, unlike the {@link #addDomHandler(EventHandler, com.google.gwt.event.dom.client.DomEvent.Type)} implementation, there is no need to attach the widget to the DOM in order to cause the event handlers to be attached.
@param <H> the type of handler to add @param type the event key @param handler the handler @return {@link HandlerRegistration} used to remove the handler
HandlerRegistration addBitlessDomHandler(EventHandler handler, DomEventType type) { assert (handler != null);; // : "handler must not be null"; assert (type != null); // : "type must not be null"; sinkBitlessEvent(type.eventName); return ensureHandlers().addHandler(type, handler); }
HandlerRegistration addBlurHandler(BlurHandler handler) #
Adds a {@link BlurEvent} handler.
@param handler the blur handler @return {@link HandlerRegistration} used to remove this handler
HandlerRegistration addBlurHandler(BlurHandler handler) { return addDomHandler(handler, BlurEvent.TYPE); }
HandlerRegistration addCloseHandler(CloseHandler<TreeItem> handler) #
Adds a {@link CloseEvent} handler.
@param handler the handler @return the registration for the event
HandlerRegistration addCloseHandler(CloseHandler<TreeItem> handler) { return addHandler(handler, CloseEvent.TYPE); }
HandlerRegistration addDomHandler(EventHandler handler, DomEventType type) #
Adds a native event handler to the widget and sinks the corresponding native event. If you do not want to sink the native event, use the generic addHandler method instead.
@param <H> the type of handler to add @param type the event key @param handler the handler @return {@link HandlerRegistration} used to remove the handler
HandlerRegistration addDomHandler(EventHandler handler, DomEventType type) { assert (handler != null); // : "handler must not be null"; assert (type != null); // : "type must not be null"; int typeInt = IEvent.getTypeInt(type.eventName); if (typeInt == -1) { sinkBitlessEvent(type.eventName); } else { sinkEvents(typeInt); } return ensureHandlers().addHandler(type, handler); }
HandlerRegistration addFocusHandler(FocusHandler handler) #
Adds a {@link FocusEvent} handler.
@param handler the focus handler @return {@link HandlerRegistration} used to remove this handler
HandlerRegistration addFocusHandler(FocusHandler handler) { return addDomHandler(handler, FocusEvent.TYPE); }
HandlerRegistration addHandler(EventHandler handler, EventType<EventHandler> type) #
Adds this handler to the widget.
@param <H> the type of handler to add @param type the event type @param handler the handler @return {@link HandlerRegistration} used to remove the handler
HandlerRegistration addHandler(EventHandler handler, EventType<EventHandler> type) { return ensureHandlers().addHandler(type, handler); }
void addIsTreeItem(IsTreeItem isItem) #
Adds an item to the root level of this tree.
@param isItem the wrapper of item to be added
void addIsTreeItem(IsTreeItem isItem) { _root.addIsTreeItem(isItem); }
void addIsWidget(IsWidget w) #
Overloaded version for IsWidget.
@see #add(Widget)
void addIsWidget(IsWidget w) { this.add(Widget.asWidgetOrNull(w)); }
TreeItem addIsWidgetItem(IsWidget w) #
Overloaded version for IsWidget.
@see #addItem(Widget)
TreeItem addIsWidgetItem(IsWidget w) { return this.addIsWidgetItem(Widget.asWidgetOrNull(w)); }
void addItem(TreeItem item) #
Adds an item to the root level of this tree.
@param item the item to be added
void addItem(TreeItem item) { _root.addItem(item); }
HandlerRegistration addKeyDownHandler(KeyDownHandler handler) #
Adds a {@link KeyDownEvent} handler.
@param handler the key down handler @return {@link HandlerRegistration} used to remove this handler
HandlerRegistration addKeyDownHandler(KeyDownHandler handler) { return addDomHandler(handler, KeyDownEvent.TYPE); }
HandlerRegistration addKeyPressHandler(KeyPressHandler handler) #
Adds a {@link KeyPressEvent} handler.
@param handler the key press handler @return {@link HandlerRegistration} used to remove this handler
HandlerRegistration addKeyPressHandler(KeyPressHandler handler) { return addDomHandler(handler, KeyPressEvent.TYPE); }
HandlerRegistration addKeyUpHandler(KeyUpHandler handler) #
Adds a {@link KeyUpEvent} handler.
@param handler the key up handler @return {@link HandlerRegistration} used to remove this handler
HandlerRegistration addKeyUpHandler(KeyUpHandler handler) { return addDomHandler(handler, KeyUpEvent.TYPE); }
HandlerRegistration addMouseDownHandler(MouseDownHandler handler) #
Adds a {@link MouseDownEvent} handler.
@param handler the mouse down handler @return {@link HandlerRegistration} used to remove this handler
HandlerRegistration addMouseDownHandler(MouseDownHandler handler) { return addHandler(handler, MouseDownEvent.TYPE); }
HandlerRegistration addMouseMoveHandler(MouseMoveHandler handler) #
Adds a {@link MouseMoveEvent} handler.
@param handler the mouse move handler @return {@link HandlerRegistration} used to remove this handler
HandlerRegistration addMouseMoveHandler(MouseMoveHandler handler) { return addDomHandler(handler, MouseMoveEvent.TYPE); }
HandlerRegistration addMouseOutHandler(MouseOutHandler handler) #
Adds a {@link MouseOutEvent} handler.
@param handler the mouse out handler @return {@link HandlerRegistration} used to remove this handler
HandlerRegistration addMouseOutHandler(MouseOutHandler handler) { return addDomHandler(handler, MouseOutEvent.TYPE); }
HandlerRegistration addMouseOverHandler(MouseOverHandler handler) #
Adds a {@link MouseOverEvent} handler.
@param handler the mouse over handler @return {@link HandlerRegistration} used to remove this handler
HandlerRegistration addMouseOverHandler(MouseOverHandler handler) { return addDomHandler(handler, MouseOverEvent.TYPE); }
HandlerRegistration addMouseUpHandler(MouseUpHandler handler) #
Adds a {@link MouseUpEvent} handler.
@param handler the mouse up handler @return {@link HandlerRegistration} used to remove this handler
HandlerRegistration addMouseUpHandler(MouseUpHandler handler) { return addDomHandler(handler, MouseUpEvent.TYPE); }
HandlerRegistration addMouseWheelHandler(MouseWheelHandler handler) #
Adds a {@link MouseWheelEvent} handler.
@param handler the mouse wheel handler @return {@link HandlerRegistration} used to remove this handler
HandlerRegistration addMouseWheelHandler(MouseWheelHandler handler) { return addDomHandler(handler, MouseWheelEvent.TYPE); }
HandlerRegistration addOpenHandler(OpenHandler<TreeItem> handler) #
Adds an {@link OpenEvent} handler.
@param handler the handler @return the registration for the event
HandlerRegistration addOpenHandler(OpenHandler<TreeItem> handler) { return addHandler(handler, OpenEvent.TYPE); }
TreeItem addSafeHtmlItem(SafeHtml itemHtml) #
Adds a simple tree item containing the specified html.
@param itemHtml the html of the item to be added @return the item that was added
TreeItem addSafeHtmlItem(SafeHtml itemHtml) { return _root.addSafeHtmlItem(itemHtml); }
HandlerRegistration addSelectionHandler(SelectionHandler<TreeItem> handler) #
Adds a {@link SelectionEvent} handler.
@param handler the handler @return the registration for the event
HandlerRegistration addSelectionHandler( SelectionHandler<TreeItem> handler) { return addHandler(handler, SelectionEvent.TYPE); }
void addStyleDependentName(String styleSuffix) #
Adds a dependent style name by specifying the style name's suffix. The actual form of the style name that is added is:
getStylePrimaryName() + '-' + styleSuffix
@param styleSuffix the suffix of the dependent style to be added. @see #setStylePrimaryName(String) @see #removeStyleDependentName(String) @see #setStyleDependentName(String, boolean) @see #addStyleName(String)
void addStyleDependentName(String styleSuffix) { setStyleDependentName(styleSuffix, true); }
void addStyleName(String style) #
Adds a secondary or dependent style name to this object. A secondary style name is an additional style name that is, in HTML/CSS terms, included as a space-separated token in the value of the CSS <code>class</code> attribute for this object's root element.
The most important use for this method is to add a special kind of
secondary style name called a dependent style name. To add a
dependent style name, use {@link #addStyleDependentName(String)}, which
will prefix the 'style' argument with the result of
{@link #k()} (followed by a '-'). For example, suppose
the primary style name is gwt-TextBox
. If the following method
is called as obj.setReadOnly(true)
:
public void setReadOnly(boolean readOnly) { isReadOnlyMode = readOnly;// Create a dependent style name. String readOnlyStyle = "readonly";
if (readOnly) {
addStyleDependentName(readOnlyStyle);
} else {
removeStyleDependentName(readOnlyStyle);
} }</pre>
then both of the CSS style rules below will be applied:
// This rule is based on the primary style name and is always active. .gwt-TextBox { font-size: 12pt; }
// This rule is based on a dependent style name that is only active // when the widget has called addStyleName(getStylePrimaryName() + // "-readonly"). .gwt-TextBox-readonly { background-color: lightgrey; border: none; }</pre>
The code can also be simplified with {@link #setStyleDependentName(String, boolean)}:
public void setReadOnly(boolean readOnly) { isReadOnlyMode = readOnly; setStyleDependentName("readonly", readOnly); }Dependent style names are powerful because they are automatically updated whenever the primary style name changes. Continuing with the example above, if the primary style name changed due to the following call:
setStylePrimaryName("my-TextThingy");then the object would be re-associated with following style rules, removing those that were shown above.
.my-TextThingy { font-size: 20pt; }.my-TextThingy-readonly { background-color: red; border: 2px solid yellow; }</pre>
Secondary style names that are not dependent style names are not automatically updated when the primary style name changes.
@param style the secondary style name to be added @see UIObject @see #removeStyleName(String)
void addStyleName(String style) { setStyleName(style, true); }
TreeItem addTextItem(String itemText) #
Adds a simple tree item containing the specified text.
@param itemText the text of the item to be added @return the item that was added
TreeItem addTextItem(String itemText) { return _root.addTextItem(itemText); }
TreeItem addWidgetItem(Widget widget) #
Adds a new tree item containing the specified widget.
@param widget the widget to be added @return the new item
TreeItem addWidgetItem(Widget widget) { return _root.addWidgetItem(widget); }
void adopt(Widget widget, TreeItem treeItem) #
void adopt(Widget widget, TreeItem treeItem) { assert (!_childWidgets.containsKey(widget)); _childWidgets[widget] = treeItem; widget.setParent(this); }
Widget asWidget() #
Returns the Widget aspect of the receiver.
Widget asWidget() { return this; }
void clear() #
Clears all tree items from the current tree.
void clear() { int size = _root.getChildCount(); for (int i = size - 1; i >= 0; i--) { _root.getChild(i).remove(); } }
void clearAndSetStyleName(String style) #
Clears all of the object's style names and sets it to the given style. You should normally use {@link #setStylePrimaryName(String)} unless you wish to explicitly remove all existing styles.
@param style the new style name @see #setStylePrimaryName(String)
void clearAndSetStyleName(String style) { setElementStyleName(getStyleElement(), style); }
EventBus createEventBus() #
Creates the SimpleEventBus used by this Widget. You can override this method to create a custom EventBus.
@return the EventBus you want to use.
EventBus createEventBus() { return new SimpleEventBus(); }
void delegateEvent(Widget target, DwtEvent event) #
Fires an event on a child widget. Used to delegate the handling of an event from one widget to another.
@param event the event @param target fire the event on the given target
void delegateEvent(Widget target, DwtEvent event) { target.fireEvent(event); }
void doAttachChildren() #
If a widget contains one or more child widgets that are not in the logical widget hierarchy (the child is physically connected only on the DOM level), it must override this method and call {@link #onAttach()} for each of its child widgets.
@see #onAttach()
void doAttachChildren() { try { AttachDetachException.tryCommand(this.iterator(), AttachDetachException.attachCommand); } finally { Dom.setEventListener(_focusable, this); } }
void doDetachChildren() #
If a widget contains one or more child widgets that are not in the logical widget hierarchy (the child is physically connected only on the DOM level), it must override this method and call {@link #onDetach()} for each of its child widgets.
@see #onDetach()
void doDetachChildren() { try { AttachDetachException.tryCommand(this.iterator(), AttachDetachException.detachCommand); } finally { Dom.setEventListener(_focusable, null); } }
EventBus ensureHandlers() #
Ensures the existence of the event bus.
@return the EventBus.
EventBus ensureHandlers() { return _eventBus == null ? _eventBus = createEventBus() : _eventBus; }
void ensureSelectedItemVisible() #
Ensures that the currently-selected item is visible, opening its parents and scrolling the tree as necessary.
void ensureSelectedItemVisible() { if (_curSelection == null) { return; } TreeItem parent = _curSelection.getParentItem(); while (parent != null) { parent.setState(true); parent = parent.getParentItem(); } }
double extractLengthValue(String s) #
Intended to be used to pull the value out of a CSS length. If the value is "auto" or "inherit", 0 will be returned.
@param s The CSS length string to extract @return The leading numeric portion of <code>s</code>, or 0 if "auto" or
"inherit" are passed in.
double extractLengthValue(String s) { if (s == "auto" || s == "inherit" || s == "") { return 0.0; } else { // numberRegex divides the string into a leading numeric portion // followed by an arbitrary portion. if(numberRegex.hasMatch(s)) { // Extract the leading numeric portion of string s = numberRegex.firstMatch(s)[0]; } return double.parse(s); } }
void fireEvent(DwtEvent event) #
Fires the given event to the handlers listening to the event's type.
Any exceptions thrown by handlers will be bundled into a UmbrellaException and then re-thrown after all handlers have completed. An exception thrown by a handler will not prevent other handlers from executing.
@param event the event
void fireEvent(DwtEvent event) { // if (_eventBus != null) { // _eventBus.fireEvent(event); // } if (_eventBus != null) { // If it not live we should revive it. if (!event.isLive()) { event.revive(); } Object oldSource = event.getSource(); event.overrideSource(getElement()); try { // May throw an UmbrellaException. _eventBus.fireEventFromSource(event, getElement()); } on UmbrellaException catch (e) { throw new UmbrellaException(e.causes); } finally { if (oldSource == null) { // This was my event, so I should kill it now that I'm done. event.kill(); } else { // Restoring the source for the next handler to use. event.overrideSource(oldSource); } } } }
void fireStateChanged(TreeItem item, bool open) #
void fireStateChanged(TreeItem item, bool open) { if (open) { OpenEvent.fire(this, item); } else { CloseEvent.fire(this, item); } }
int getAbsoluteLeft() #
Gets the object's absolute left position in pixels, as measured from the browser window's client area.
@return the object's absolute left position
int getAbsoluteLeft() { return Dom.getAbsoluteLeft(getElement()); }
int getAbsoluteTop() #
Gets the object's absolute top position in pixels, as measured from the browser window's client area.
@return the object's absolute top position
int getAbsoluteTop() { return Dom.getAbsoluteTop(getElement()); }
Map<Widget, TreeItem> getChildWidgets() #
Map<Widget, TreeItem> getChildWidgets() { return _childWidgets; }
Element getElement() #
Gets this object's browser element.
dart_html.Element getElement() { assert (_element != null); // : MISSING_ELEMENT_ERROR; return _element; }
EventBus getEventBus() #
Return EventBus.
EventBus getEventBus() { return _eventBus; }
_ImageAdapter getImages() #
_ImageAdapter getImages() { return _images; }
TreeItem getItem(int index) #
Gets the top-level tree item at the specified index.
@param index the index to be retrieved @return the item at that index
TreeItem getItem(int index) { return _root.getChild(index); }
int getItemCount() #
Gets the number of items contained at the root of this tree.
@return this tree's item count
int getItemCount() { return _root.getChildCount(); }
Object getLayoutData() #
Gets the panel-defined layout data associated with this widget.
@return the widget's layout data @see #setLayoutData
Object getLayoutData() { return _layoutData; }
int getOffsetHeight() #
Gets the object's offset height in pixels. This is the total height of the object, including decorations such as border and padding, but not margin.
@return the object's offset height
int getOffsetHeight() { return getElement().offset.height; // Dom.getElementPropertyInt(getElement(), "offsetHeight"); }
int getOffsetWidth() #
Gets the object's offset width in pixels. This is the total width of the object, including decorations such as border and padding, but not margin.
@return the object's offset width
int getOffsetWidth() { return getElement().offset.width; // Dom.getElementPropertyInt(getElement(), "offsetWidth"); }
Widget getParent() #
Gets this widget's parent panel.
@return the widget's parent panel
Widget getParent() { return _parent; }
TreeItem getSelectedItem() #
Gets the currently selected item.
@return the selected item
TreeItem getSelectedItem() { return _curSelection; }
Element getStyleElement() #
Template method that returns the element to which style names will be applied. By default it returns the root element, but this method may be overridden to apply styles to a child element.
@return the element to which style names will be applied
dart_html.Element getStyleElement() { return getElement(); }
String getStyleName() #
Gets all of the object's style names, as a space-separated list. If you wish to retrieve only the primary style name, call {@link #getStylePrimaryName()}.
@return the objects's space-separated style names @see #getStylePrimaryName()
String getStyleName() { return getElementStyleName(getStyleElement()); }
String getStylePrimaryName() #
Gets the primary style name associated with the object.
@return the object's primary style name @see #setStyleName(String) @see #addStyleName(String) @see #removeStyleName(String)
String getStylePrimaryName() { return getElementStylePrimaryName(getStyleElement()); }
void insertItem(int beforeIndex, TreeItem item) #
Inserts an item into the root level of this tree.
@param beforeIndex the index where the item will be inserted @param item the item to be added @throws IndexOutOfBoundsException if the index is out of range
void insertItem(int beforeIndex, TreeItem item) { _root.insertItem(beforeIndex, item); }
TreeItem insertSafeHtmlItem(int beforeIndex, SafeHtml itemHtml) #
Inserts a child tree item at the specified index containing the specified html.
@param beforeIndex the index where the item will be inserted @param itemHtml the html of the item to be added @return the item that was added @throws IndexOutOfBoundsException if the index is out of range
TreeItem insertSafeHtmlItem(int beforeIndex, SafeHtml itemHtml) { return _root.insertSafeHtmlItem(beforeIndex, itemHtml); }
TreeItem insertTextItem(int beforeIndex, String itemText) #
Inserts a child tree item at the specified index containing the specified text.
@param beforeIndex the index where the item will be inserted @param itemText the text of the item to be added @return the item that was added @throws IndexOutOfBoundsException if the index is out of range
TreeItem insertTextItem(int beforeIndex, String itemText) { return _root.insertTextItem(beforeIndex, itemText); }
TreeItem insertWidgetItem(int beforeIndex, Widget widget) #
Inserts a child tree item at the specified index containing the specified widget.
@param beforeIndex the index where the item will be inserted @param widget the widget to be added @return the item that was added @throws IndexOutOfBoundsException if the index is out of range
TreeItem insertWidgetItem(int beforeIndex, Widget widget) { return _root.insertWidgetItem(beforeIndex, widget); }
bool isAnimationEnabled() #
Returns true if animations are enabled, false if not.
bool isAnimationEnabled() { return _isAnimationEnabled; }
bool isAttached() #
Returns whether or not the receiver is attached to the {@link com.google.gwt.dom.client.Document Document}'s {@link com.google.gwt.dom.client.BodyElement BodyElement}.
@return true if attached, false otherwise
bool isAttached() { return _attached; }
bool isKeyboardNavigationEnabled(TreeItem currentItem) #
Indicates if keyboard navigation is enabled for the Tree and for a given TreeItem. Subclasses of Tree can override this function to selectively enable or disable keyboard navigation.
@param currentItem the currently selected TreeItem @return <code>true</code> if the Tree will response to arrow keys by
changing the currently selected item
bool isKeyboardNavigationEnabled(TreeItem currentItem) { return true; }
bool isOrWasAttached() #
Has this widget ever been attached?
@return true if this widget ever been attached to the DOM, false otherwise
bool isOrWasAttached() { return eventsToSink == -1; }
Iterator<Widget> iterator() #
Returns an Iterator that iterates over this Iterable object.
Iterator<Widget> iterator() { List<Widget> widgets = new List<Widget>.from(_childWidgets.keys); return WidgetIterators.createWidgetIterator(this, widgets); }
void maybeUpdateSelection(TreeItem itemThatChangedState, bool isItemOpening) #
void maybeUpdateSelection(TreeItem itemThatChangedState, bool isItemOpening) { /** * If we just closed the item, let's check to see if this item is the parent * of the currently selected item. If so, we should make this item the * currently selected selected item. */ if (!isItemOpening) { TreeItem tempItem = _curSelection; while (tempItem != null) { if (tempItem == itemThatChangedState) { setSelectedItem(itemThatChangedState); return; } tempItem = tempItem.getParentItem(); } } }
void onAttach() #
This method is called when a widget is attached to the browser's document. To receive notification after a Widget has been added to the document, override the {@link #onLoad} method or use {@link #addAttachHandler}.
It is strongly recommended that you override {@link #onLoad()} or {@link #doAttachChildren()} instead of this method to avoid inconsistencies between logical and physical attachment states.
Subclasses that override this method must call
super.onAttach()
to ensure that the Widget has been attached
to its underlying Element.
@throws IllegalStateException if this widget is already attached @see #onLoad() @see #doAttachChildren()
void onAttach() { if (isAttached()) { throw new Exception("Should only call onAttach when the widget is detached from the browser's document"); } _attached = true; // Event hookup code Dom.setEventListener(getElement(), this); int bitsToAdd = eventsToSink; eventsToSink = -1; if (bitsToAdd > 0) { sinkEvents(bitsToAdd); } doAttachChildren(); // onLoad() gets called only *after* all of the children are attached and // the attached flag is set. This allows widgets to be notified when they // are fully attached, and panels when all of their children are attached. onLoad(); AttachEvent.fire(this, true); }
void onBrowserEvent(Event event) #
Fired whenever a browser event is received.
@param event the event received
TODO
void onBrowserEvent(dart_html.Event event) { int eventType = Dom.eventGetType(event); switch (eventType) { case IEvent.ONKEYDOWN: // If nothing's selected, select the first item. if (_curSelection == null) { if (_root.getChildCount() > 0) { _onSelection(_root.getChild(0), true, true); } super.onBrowserEvent(event); return; } break; // Intentional fallthrough. case IEvent.ONKEYPRESS: case IEvent.ONKEYUP: dart_html.KeyboardEvent kEvent = event as dart_html.KeyboardEvent; // Issue 1890: Do not block history navigation via alt+left/right if (kEvent.altKey || kEvent.metaKey) { super.onBrowserEvent(event); return; } break; } switch (eventType) { case IEvent.ONCLICK: dart_html.Element e = event.target as dart_html.Element; if (shouldTreeDelegateFocusToElement(e)) { // The click event should have given focus to this element already. // Avoid moving focus back up to the tree (so that focusable widgets // attached to TreeItems can receive keyboard events). } else if ((_curSelection != null) && Dom.isOrHasChild(_curSelection.getContentElem(), e)) { focus = true; } break; case IEvent.ONMOUSEDOWN: // Currently, the way we're using image bundles causes extraneous events // to be sunk on individual items' open/close images. This leads to an // extra event reaching the Tree, which we will ignore here. // Also, ignore middle and right clicks here. dart_html.MouseEvent mEvent = event as dart_html.MouseEvent; if (mEvent.currentTarget == getElement() && mEvent.button == IEvent.BUTTON_LEFT) { _elementClicked(event.target as dart_html.Element); } break; case IEvent.ONKEYDOWN: _keyboardNavigation(event); _lastWasKeyDown = true; break; case IEvent.ONKEYPRESS: if (!_lastWasKeyDown) { _keyboardNavigation(event); } _lastWasKeyDown = false; break; case IEvent.ONKEYUP: dart_html.KeyboardEvent kEvent = event as dart_html.KeyboardEvent; if (kEvent.keyCode == KeyCodes.KEY_TAB) { List<dart_html.Element> chain = new List<dart_html.Element>(); _collectElementChain(chain, getElement(), event.target); TreeItem item = _findItemByChain(chain, 0, _root); if (item != getSelectedItem()) { setSelectedItem(item, true); } } _lastWasKeyDown = false; break; } switch (eventType) { case IEvent.ONKEYDOWN: case IEvent.ONKEYUP: dart_html.KeyboardEvent kEvent = event as dart_html.KeyboardEvent; if (isArrowKey(kEvent.keyCode)) { // event.cancelBubble = true; event.preventDefault(); return; } break; } // We must call super for all handlers. super.onBrowserEvent(event); }
void onDetach() #
This method is called when a widget is detached from the browser's document. To receive notification before a Widget is removed from the document, override the {@link #onUnload} method or use {@link #addAttachHandler}.
It is strongly recommended that you override {@link #onUnload()} or {@link #doDetachChildren()} instead of this method to avoid inconsistencies between logical and physical attachment states.
Subclasses that override this method must call
super.onDetach()
to ensure that the Widget has been detached
from the underlying Element. Failure to do so will result in application
memory leaks due to circular references between DOM Elements and JavaScript
objects.
@throws IllegalStateException if this widget is already detached @see #onUnload() @see #doDetachChildren()
void onDetach() { if (!isAttached()) { throw new Exception("Should only call onDetach when the widget is attached to the browser's document"); } try { // onUnload() gets called *before* everything else (the opposite of // onLoad()). onUnload(); AttachEvent.fire(this, false); } finally { // Put this in a finally, just in case onUnload throws an exception. try { doDetachChildren(); } finally { // Put this in a finally, in case doDetachChildren throws an exception. Dom.setEventListener(getElement(), null); _attached = false; } } }
void onLoad() #
This method is called immediately after a widget becomes attached to the browser's document.
void onLoad() { _root.updateStateRecursive(); }
void onUnload() #
This method is called immediately before a widget will be detached from the browser's document.
void onUnload() { }
void orphan(Widget widget) #
void orphan(Widget widget) { // Validation should already be done. assert (widget.getParent() == this); // Orphan. try { widget.setParent(null); } finally { // Logical detach. _childWidgets.remove(widget); } }
bool remove(Widget w) #
Removes a child widget.
@param w the widget to be removed @return <code>true</code> if the widget was present
bool remove(Widget w) { // Validate. TreeItem item = _childWidgets[w]; if (item == null) { return false; } // Delegate to TreeItem.setWidget, which performs correct removal. item.setWidget(null); return true; }
void removeFromParent() #
Removes this widget from its parent widget, if one exists.
If it has no parent, this method does nothing. If it is a "root" widget (meaning it's been added to the detach list via {@link RootPanel#detachOnWindowClose(Widget)}), it will be removed from the detached immediately. This makes it possible for Composites and Panels to adopt root widgets.
@throws IllegalStateException if this widget's parent does not support
removal (e.g. {@link Composite})
void removeFromParent() { if (_parent == null) { // If the widget had no parent, check to see if it was in the detach list // and remove it if necessary. if (RootPanel.isInDetachList(this)) { RootPanel.detachNow(this); } } else if (_parent is HasWidgets) { (_parent as HasWidgets).remove(this); } else if (_parent != null) { throw new Exception("This widget's parent does not implement HasWidgets"); } }
void removeIsTreeItem(IsTreeItem isItem) #
Removes an item from the _root level of this tree.
@param isItem the wrapper of item to be removed
void removeIsTreeItem(IsTreeItem isItem) { if (isItem != null) { TreeItem item = isItem.asTreeItem(); removeItem(item); } }
bool removeIsWidget(IsWidget w) #
Overloaded version for IsWidget.
@see #remove(Widget)
bool removeIsWidget(IsWidget w) { return this.remove(w.asWidget()); }
void removeItem(TreeItem item) #
Removes an item from the root level of this tree.
@param item the item to be removed
void removeItem(TreeItem item) { _root.removeItem(item); }
void removeItems() #
Removes all items from the root level of this tree.
void removeItems() { while (getItemCount() > 0) { removeItem(getItem(0)); } }
void removeStyleDependentName(String styleSuffix) #
Removes a dependent style name by specifying the style name's suffix.
@param styleSuffix the suffix of the dependent style to be removed @see #setStylePrimaryName(Element, String) @see #addStyleDependentName(String) @see #setStyleDependentName(String, boolean)
void removeStyleDependentName(String styleSuffix) { setStyleDependentName(styleSuffix, false); }
void removeStyleName(String style) #
Removes a style name. This method is typically used to remove secondary style names, but it can be used to remove primary stylenames as well. That use is not recommended.
@param style the secondary style name to be removed @see #addStyleName(String) @see #setStyleName(String, boolean)
void removeStyleName(String style) { setStyleName(style, false); }
void replaceElement(Element elem) #
Replaces this object's browser element.
This method exists only to support a specific use-case in Image, and should not be used by other classes.
@param elem the object's new element
void replaceElement(dart_html.Element elem) { if (isAttached()) { // Remove old event listener to avoid leaking. onDetach will not do this // for us, because it is only called when the widget itself is detached // from the document. Dom.setEventListener(getElement(), null); } super.replaceElement(elem); if (isAttached()) { // Hook the event listener back up on the new element. onAttach will not // do this for us, because it is only called when the widget itself is // attached to the document. Dom.setEventListener(getElement(), this); } }
void setAnimationEnabled(bool enable) #
Enable or disable animations.
@param enable true to enable, false to disable
void setAnimationEnabled(bool enable) { _isAnimationEnabled = enable; }
void setElement(Element elem) #
Sets this object's browser element. UIObject subclasses must call this method before attempting to call any other methods, and it may only be called once.
@param elem the object's element
void setElement(dart_html.Element elem) { assert (_element == null); this._element = elem; }
void setHeight(String height) #
Sets the object's height. This height does not include decorations such as border, margin, and padding.
@param height the object's new height, in CSS units (e.g. "10px", "1em")
void setHeight(String height) { // This exists to deal with an inconsistency in IE's implementation where // it won't accept negative numbers in length measurements assert (extractLengthValue(height.trim().toLowerCase()) >= 0); // : "CSS heights should not be negative"; Dom.setStyleAttribute(getElement(), "height", height); }
void setLayoutData(Object value) #
Sets the panel-defined layout data associated with this widget. Only the panel that currently contains a widget should ever set this value. It serves as a place to store layout bookkeeping data associated with a widget.
@param layoutData the widget's layout data
void setLayoutData(Object value) { this._layoutData = value; }
void setParent(Widget parent) #
Sets this widget's parent. This method should only be called by {@link Panel} and {@link Composite}.
@param parent the widget's new parent @throws IllegalStateException if <code>parent</code> is non-null and the
widget already has a parent
void setParent(Widget parent) { Widget oldParent = this._parent; if (parent == null) { try { if (oldParent != null && oldParent.isAttached()) { onDetach(); assert (!isAttached()); // : "Failure of " + this.getClass().getName() + " to call super.onDetach()"; } } finally { // Put this in a finally in case onDetach throws an exception. this._parent = null; } } else { if (oldParent != null) { throw new Exception("Cannot set a new parent without first clearing the old parent"); } this._parent = parent; if (parent.isAttached()) { onAttach(); assert (isAttached()); // : "Failure of " + this.getClass().getName() + " to call super.onAttach()"; } } }
void setPixelSize(int width, int height) #
Sets the object's size, in pixels, not including decorations such as border, margin, and padding.
@param width the object's new width, in pixels @param height the object's new height, in pixels
void setPixelSize(int width, int height) { if (width >= 0) { setWidth(width.toString() + "px"); } if (height >= 0) { setHeight(height.toString() + "px"); } }
void setSelectedItem(TreeItem item, [bool fireEvents = true]) #
Selects a specified item.
@param item the item to be selected, or <code>null</code> to deselect all
items
@param fireEvents <code>true</code> to allow selection events to be fired
void setSelectedItem(TreeItem item, [bool fireEvents = true]) { if (item == null) { if (_curSelection == null) { return; } _curSelection.setSelected(false); _curSelection = null; return; } _onSelection(item, fireEvents, true); }
void setSize(String width, String height) #
Sets the object's size. This size does not include decorations such as border, margin, and padding.
@param width the object's new width, in CSS units (e.g. "10px", "1em") @param height the object's new height, in CSS units (e.g. "10px", "1em")
void setSize(String width, String height) { setWidth(width); setHeight(height); }
void setStyleDependentName(String styleSuffix, bool add) #
Adds or removes a dependent style name by specifying the style name's suffix. The actual form of the style name that is added is:
getStylePrimaryName() + '-' + styleSuffix
@param styleSuffix the suffix of the dependent style to be added or removed @param add <code>true</code> to add the given style, <code>false</code> to
remove it
@see #setStylePrimaryName(Element, String) @see #addStyleDependentName(String) @see #setStyleName(String, boolean) @see #removeStyleDependentName(String)
void setStyleDependentName(String styleSuffix, bool add) { setStyleName(getStylePrimaryName() + '-' + styleSuffix, add); }
void setStyleName(String style, bool add) #
Adds or removes a style name. This method is typically used to remove secondary style names, but it can be used to remove primary stylenames as well. That use is not recommended.
@param style the style name to be added or removed @param add <code>true</code> to add the given style, <code>false</code> to
remove it
@see #addStyleName(String) @see #removeStyleName(String)
void setStyleName(String style, bool add) { manageElementStyleName(getStyleElement(), style, add); }
void setStylePrimaryName(String style) #
Sets the object's primary style name and updates all dependent style names.
@param style the new primary style name @see #addStyleName(String) @see #removeStyleName(String)
void setStylePrimaryName(String style) { setElementStylePrimaryName(getStyleElement(), style); }
void setWidth(String width) #
Sets the object's width. This width does not include decorations such as border, margin, and padding.
@param width the object's new width, in CSS units (e.g. "10px", "1em")
void setWidth(String width) { // This exists to deal with an inconsistency in IE's implementation where // it won't accept negative numbers in length measurements assert (extractLengthValue(width.trim().toLowerCase()) >= 0); // : "CSS widths should not be negative"; Dom.setStyleAttribute(getElement(), "width", width); }
void showClosedImage(TreeItem treeItem) #
Called only from {@link TreeItem}: Shows the closed image on that tree item.
@param treeItem the tree item
void showClosedImage(TreeItem treeItem) { _showImage(treeItem, _images.treeClosed()); }
void showLeafImage(TreeItem treeItem) #
Called only from {@link TreeItem}: Shows the leaf image on a tree item.
@param treeItem the tree item
void showLeafImage(TreeItem treeItem) { if (_useLeafImages || treeItem.isFullNode()) { _showImage(treeItem, _images.treeLeaf()); } else if (LocaleInfo.getCurrentLocale().isRTL()) { treeItem.getElement().style.paddingRight = _indentValue; } else { treeItem.getElement().style.paddingLeft = _indentValue; } }
void showOpenImage(TreeItem treeItem) #
Called only from {@link TreeItem}: Shows the open image on a tree item.
@param treeItem the tree item
void showOpenImage(TreeItem treeItem) { _showImage(treeItem, _images.treeOpen()); }
void sinkBitlessEvent(String eventTypeName) #
Sinks a named event. Note that only {@link Widget widgets} may actually receive events, but can receive events from all objects contained within them.
@param eventTypeName name of the event to sink on this element @see com.google.gwt.user.client.Event
void sinkBitlessEvent(String eventTypeName) { Dom.sinkBitlessEvent(getElement(), eventTypeName); }
void sinkEvents(int eventBitsToAdd) #
Overridden to defer the call to super.sinkEvents until the first time this widget is attached to the dom, as a performance enhancement. Subclasses wishing to customize sinkEvents can preserve this deferred sink behavior by putting their implementation behind a check of <code>isOrWasAttached()</code>:
{@literal @}Override public void sinkEvents(int eventBitsToAdd) { if (isOrWasAttached()) { /{@literal *} customized sink code goes here {@literal *}/ } else { super.sinkEvents(eventBitsToAdd); } }
void sinkEvents(int eventBitsToAdd) { if (isOrWasAttached()) { super.sinkEvents(eventsToSink); } else { eventsToSink |= eventBitsToAdd; } }
String toString() #
This method is overridden so that any object can be viewed in the debugger as an HTML snippet.
@return a string representation of the object
String toString() { if (_element == null) { return "(null handle)"; } return getElement().toString(); }
Iterator<TreeItem> treeItemIterator() #
Iterator of tree items.
@return the iterator
Iterator<TreeItem> treeItemIterator() { List<TreeItem> accum = new List<TreeItem>(); _root.addTreeItems(accum); return accum.iterator; }
void unsinkEvents(int eventBitsToRemove) #
Removes a set of events from this object's event list.
@param eventBitsToRemove a bitfield representing the set of events to be
removed from this element's event set
@see #sinkEvents @see com.google.gwt.user.client.Event
void unsinkEvents(int eventBitsToRemove) { Dom.sinkEvents(getElement(), Dom.getEventsSunk(getElement()) & (~eventBitsToRemove)); }