Package com.google.gwt.widgetideas.client

Source Code of com.google.gwt.widgetideas.client.FastTreeItem

/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.widgetideas.client;

import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.HasFocus;
import com.google.gwt.user.client.ui.HasHTML;
import com.google.gwt.user.client.ui.UIObject;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.widgetideas.client.overrides.DOMHelper;

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

/**
* An item that can be contained within a
* {@link com.google.gwt.widgetideas.client.FastTree}.
* <p>
* <h3>Example</h3>
* {@example com.google.gwt.examples.TreeExample}
*/

public class FastTreeItem extends UIObject implements HasHTML, HasFastTreeItems {
  private static final String STYLENAME_SELECTED = "selected";

  // TODO(ECC) change states to enums and move style names to FastTree where
  // they below.
  private static final int TREE_NODE_LEAF = 1;
  private static final int TREE_NODE_INTERIOR_NEVER_OPENED = 2;
  private static final int TREE_NODE_INTERIOR_OPEN = 3;
  private static final int TREE_NODE_INTERIOR_CLOSED = 4;
  private static final String STYLENAME_CHILDREN = "children";
  private static final String STYLENAME_LEAF_DEFAULT = "gwt-FastTreeItem gwt-FastTreeItem-leaf";
  private static final String STYLENAME_OPEN = "open";
  private static final String STYLENAME_CLOSED = "closed";
  private static final String STYLENAME_LEAF = "leaf";
 
  private static final String STYLENAME_CONTENT = "treeItemContent";
  /**
   * The base tree item element that will be cloned.
   */
  private static Element TREE_LEAF;

  /**
   * Static constructor to set up clonable elements.
   */
  static {

    // Create the base element that will be cloned
    TREE_LEAF = DOM.createDiv();
    // leaf contents.
    setStyleName(TREE_LEAF, STYLENAME_LEAF_DEFAULT);
    Element content = DOM.createDiv();
    setStyleName(content, STYLENAME_CONTENT);
    DOM.appendChild(TREE_LEAF, content);
  }

  private int state = TREE_NODE_LEAF;
  private ArrayList<FastTreeItem> children;
  private Element contentElem, childElems;
  private FastTreeItem parent;
  private FastTree tree;
  private Widget widget;

  /**
   * Creates an empty tree item.
   */
  public FastTreeItem() {
    Element elem = createLeafElement();
    setElement(elem);   
  }

  /**
   * Constructs a tree item with the given HTML.
   *
   * @param html the item's HTML
   */
  public FastTreeItem(String html) {
    this();
    DOM.setInnerHTML(getElementToAttach(), html);
  }

  /**
   * Constructs a tree item with the given <code>Widget</code>.
   *
   * @param widget the item's widget
   */
  public FastTreeItem(Widget widget) {
    this();
    addWidget(widget);
  }

  /**
   * This constructor is only for use by {@link DecoratedFastTreeItem}.
   * @param element element
   */
  FastTreeItem(Element element) {
    setElement(element);
  }

  public void addItem(FastTreeItem item) {
    // Detach item from existing parent.
    if ((item.getParentItem() != null) || (item.getTree() != null)) {
      item.remove();
    }
    if (isLeafNode()) {
      becomeInteriorNode();
    }
    if (children == null) {
      // Never had children.
      children = new ArrayList<FastTreeItem>();
    }
    // Logical attach.
    item.setParentItem(this);
    children.add(item);

    // Physical attach.
    if (state != TREE_NODE_INTERIOR_NEVER_OPENED) {
      DOM.appendChild(childElems, item.getElement());
    }

    // Adopt.
    if (tree != null) {
      item.setTree(tree);
    }
  }

  public FastTreeItem addItem(String itemText) {
    FastTreeItem ret = new FastTreeItem(itemText);
    addItem(ret);
    return ret;
  }

  public FastTreeItem addItem(Widget widget) {
    FastTreeItem ret = new FastTreeItem(widget);
    addItem(ret);
    return ret;
  }

  /**
   * Become an interior node.
   */
  public void becomeInteriorNode() { 
    if (!isInteriorNode()) {     
      state = TREE_NODE_INTERIOR_NEVER_OPENED;

      Element control = DOM.createDiv();
      setStyleName(control, STYLENAME_CLOSED);
      DOM.appendChild(control, contentElem);
      convertElementToInteriorNode(control);
    }
  }

  public FastTreeItem getChild(int index) {
    if ((index < 0) || (index >= getChildCount())) {
      throw new IndexOutOfBoundsException("No child at index " + index);
    }
    return children.get(index);
  }

  public int getChildCount() {
    if (children == null) {
      return 0;
    }
    return children.size();
  }

  public int getChildIndex(FastTreeItem child) {
    if (children == null) {
      return -1;
    }
    return children.indexOf(child);
  }

  /**
   * Returns the width of the control open/close image. Must be overridden if
   * the TreeItem is using a control image that is <i>not</i> 16 pixels wide.
   *
   * @return the width of the control image
   */
  public int getControlImageWidth() {
    return 16;
  }

  public String getHTML() {
    return DOM.getInnerHTML(getElementToAttach());
  }

  /**
   * Gets this item's parent.
   *
   * @return the parent item
   */
  public FastTreeItem getParentItem() {
    return parent;
  }

  public String getText() {
    return DOM.getInnerText(getElementToAttach());
  }

  /**
   * Gets the tree that contains this item.
   *
   * @return the containing tree
   */
  public final FastTree getTree() {
    return tree;
  }

  /**
   * Gets the <code>Widget</code> associated with this tree item.
   */
  public Widget getWidget() {
    return widget;
  }

  /**
   * Has this {@link FastTreeItem} ever been opened?
   *
   * @return whether the {@link FastTreeItem} has ever been opened.
   */
  public boolean hasBeenOpened() {
    return state == TREE_NODE_INTERIOR_OPEN;
  }

  /**
   * Does this {@link FastTreeItem} represent an interior node?
   */
  public boolean isInteriorNode() {
    return state >= TREE_NODE_INTERIOR_NEVER_OPENED;
  }

  /**
   * Is this {@link FastTreeItem} a leaf node?
   */
  public boolean isLeafNode() {
    return state <= TREE_NODE_LEAF;
  }

  /**
   * Is the {@link FastTreeItem} open? Returns false if the {@link FastTreeItem}
   * is closed or a leaf node.
   */
  public boolean isOpen() {
    return state == TREE_NODE_INTERIOR_OPEN;
  }

  /**
   * Determines whether this item is currently selected.
   *
   * @return <code>true</code> if it is selected
   */
  public boolean isSelected() {
    if (tree == null) {
      return false;
    } else {
      return tree.getSelectedItem() == this;
    }
  }

  /**
   * Returns whether the tree is currently showing this {@link FastTreeItem}.
   */
  public boolean isShowing() {
    if (tree == null || isVisible() == false) {
      return false;
    } else if (parent == null) {
      return true;
    } else if (!parent.isOpen()) {
      return false;
    } else {
      return parent.isShowing();
    }
  }

  /**
   * Removes this item from its tree.
   */
  public void remove() {
    if (parent != null) {
      // If this item has a parent, remove self from it.
      parent.removeItem(this);
    } else if (tree != null) {
      // If the item has no parent, but is in the Tree, it must be a top-level
      // element.
      tree.removeItem(this);
    }
  }

  /**
   * Removes an item from the tree. Note, if you want to switch the node back to
   * be a leaf node, must call becomeLeaf()
   */
  public void removeItem(FastTreeItem item) {
    // Validate.
    if (children == null || !children.contains(item)) {
      return;
    }

    // Orphan.
    item.clearTree();

    // Physical detach.
    if (state != TREE_NODE_INTERIOR_NEVER_OPENED) {
      DOM.removeChild(childElems, item.getElement());
    }

    // Logical detach.
    item.setParentItem(null);
    children.remove(item);
  }

  /**
   * Removes all of this item's children.
   */
  public void removeItems() {
    while (getChildCount() > 0) {
      removeItem(getChild(0));
    }
  }

  public void setHTML(String html) {
    clearWidget();
    DOM.setInnerHTML(getElementToAttach(), html);
  }

  /**
   * Sets whether this item's children are displayed.
   *
   * @param open whether the item is open
   */
  public final void setState(boolean open) {
    setState(open, true);
  }

  /**
   * Sets whether this item's children are displayed.
   *
   * @param open whether the item is open
   * @param fireEvents <code>true</code> to allow open/close events to be
   *          fired
   */
  public void setState(boolean open, boolean fireEvents) {
    if (open == isOpen()) {
      return;
    }
    // Cannot open leaf nodes.
    if (isLeafNode()) {
      return;
    }
    if (open) {
      beforeOpen();
      if (state == TREE_NODE_INTERIOR_NEVER_OPENED) {
        ensureChildren();
        childElems = DOM.createDiv();
        UIObject.setStyleName(childElems, STYLENAME_CHILDREN);
        convertElementToHaveChildren(childElems);

        if (children != null) {
          for (FastTreeItem item : children) {
            DOM.appendChild(childElems, item.getElement());
          }
        }
      }

      state = TREE_NODE_INTERIOR_OPEN;
    } else {
      beforeClose();
      state = TREE_NODE_INTERIOR_CLOSED;
    }
    updateState();
  }

  public void setText(String text) {
    clearWidget();
    DOM.setInnerText(getElementToAttach(), text);
  }

  public void setWidget(Widget widget) {
    // Physical detach old from self.
    // Clear out any existing content before adding a widget.

    DOM.setInnerHTML(getElementToAttach(), "");
    clearWidget();
    addWidget(widget);
  }

  /**
   * Called before the tree item is closed.
   */
  protected void beforeClose() {
  }

  /**
   * Called before the tree item is opened.
   */
  protected void beforeOpen() {
  }

  /**
   * Called when tree item is being unselected. Returning <code>false</code>
   * cancels the unselection.
   *
   */
  protected boolean beforeSelectionLost() {
    return true;
  }

  /**
   * Fired when a tree item receives a request to open for the first time.
   * Should be overridden in child clases.
   */
  protected void ensureChildren() {
  }

  /**
   * Returns the widget, if any, that should be focused on if this TreeItem is
   * selected.
   *
   * @return widget to be focused.
   */
  protected HasFocus getFocusableWidget() {
    Widget w = getWidget();
    if (w instanceof HasFocus) {
      return (HasFocus) w;
    } else {
      return null;
    }
  }

  /**
   * Called when a tree item is selected.
   *
   */
  protected void onSelected() {
  }

  void clearTree() {
    if (tree != null) {
      if (widget != null) {
        tree.treeOrphan(widget);
      }
      if (tree.getSelectedItem() == this) {
        tree.setSelectedItem(null);
      }
      tree = null;
      for (int i = 0, n = getChildCount(); i < n; ++i) {
        children.get(i).clearTree();
      }
    }
  }

  void convertElementToHaveChildren(Element children) {
    DOM.appendChild(getElement(), children);
  }

  void convertElementToInteriorNode(Element control) {
    setStyleName(getElement(), "gwt-FastTreeItem-leaf", false);
    DOM.appendChild(getElement(), control);
  }

  Element createLeafElement() {
    Element elem = DOMHelper.clone(TREE_LEAF, true);
    contentElem = DOMHelper.rawFirstChild(elem);
    return elem;
  }

  void dumpTreeItems(List<FastTreeItem> accum) {
    if (isInteriorNode() && getChildCount() > 0) {
      for (int i = 0; i < children.size(); i++) {
        FastTreeItem item = children.get(i);
        accum.add(item);
        item.dumpTreeItems(accum);
      }
    }
  }

  ArrayList<FastTreeItem> getChildren() {
    return children;
  }

  Element getContentElem() {
    return contentElem;
  }

  Element getControlElement() {
    return DOM.getParent(contentElem);
  }

  Element getElementToAttach() {
    return contentElem;
  }

  void setParentItem(FastTreeItem parent) {
    this.parent = parent;
  }

  /**
   * Selects or deselects this item.
   *
   * @param selected <code>true</code> to select the item, <code>false</code>
   *          to deselect it
   */
  void setSelection(boolean selected, boolean fireEvents) {
    setStyleName(getControlElement(), STYLENAME_SELECTED, selected);
    if (selected && fireEvents) {
      onSelected();
    }
  }

  void setTree(FastTree newTree) {
    if (tree == newTree) {
      return;
    }

    // Early out.
    if (tree != null) {
      throw new IllegalStateException(
          "Each Tree Item must be removed from its current tree before being added to another.");
    }
    tree = newTree;

    if (widget != null) {
      // Add my widget to the new tree.
      tree.adopt(widget, this);
    }

    for (int i = 0, n = getChildCount(); i < n; ++i) {
      children.get(i).setTree(newTree);
    }
  }

  void updateState() {
    // No work to be done.
    if (isLeafNode()) {
      return;
    }
    if (isOpen()) {
      showOpenImage();
      UIObject.setVisible(childElems, true);
    } else {
      showClosedImage();
      UIObject.setVisible(childElems, false);
    }
  }

  /**
   * Adds a widget to an already empty {@link FastTreeItem}.
   */
  private void addWidget(Widget newWidget) {
    // Detach new child from old parent.
    if (newWidget != null) {
      newWidget.removeFromParent();
    }

    // Logical detach old/attach new.
    widget = newWidget;

    if (newWidget != null) {
      DOM.appendChild(getElementToAttach(), widget.getElement());
      bidiSupport();
      // Attach child to tree.
      if (tree != null) {
        tree.adopt(widget, this);
      }
    }
  }

  private void bidiSupport() {
  }

  private void clearWidget() {
    // Detach old child from tree.
    if (widget != null && tree != null) {
      tree.treeOrphan(widget);
      widget = null;
    }
  }

  private void showClosedImage() {
    setStyleName(getControlElement(), STYLENAME_OPEN, false);
    setStyleName(getControlElement(), STYLENAME_CLOSED, true);
  }

  private void showOpenImage() {
    setStyleName(getControlElement(), STYLENAME_CLOSED, false);
    setStyleName(getControlElement(), STYLENAME_OPEN, true);
  }

}
TOP

Related Classes of com.google.gwt.widgetideas.client.FastTreeItem

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.