Package com.google.gwt.user.cellview.client

Source Code of com.google.gwt.user.cellview.client.CellTree$CleanResources

/*
* Copyright 2010 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.user.cellview.client;

import com.google.gwt.animation.client.Animation;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.dom.client.Style.Position;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.resources.client.ImageResource.ImageOptions;
import com.google.gwt.resources.client.ImageResource.RepeatStyle;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HasAnimation;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.view.client.TreeViewModel;

import java.util.ArrayList;

/**
* A view of a tree.
*/
public class CellTree extends Composite implements HasAnimation {

  /**
   * A node animation.
   */
  public abstract static class NodeAnimation extends Animation {

    /**
     * The default animation delay in milliseconds.
     */
    private static final int DEFAULT_ANIMATION_DURATION = 450;

    /**
     * The duration of the animation.
     */
    private int duration = DEFAULT_ANIMATION_DURATION;

    NodeAnimation() {
    }

    public int getDuration() {
      return duration;
    }

    public void setDuration(int duration) {
      this.duration = duration;
    }

    /**
     * Animate a tree node into its new state.
     *
     * @param node the node to animate
     * @param isAnimationEnabled true to animate
     */
    abstract void animate(CellTreeNodeView<?> node, boolean isAnimationEnabled);
  }

  /**
   * A ClientBundle that provides images for this widget.
   */
  public static interface Resources extends ClientBundle {

    /**
     * An image indicating a closed branch.
     */
    ImageResource cellTreeClosedItem();

    /**
     * An image indicating that a node is loading.
     */
    ImageResource cellTreeLoading();

    /**
     * An image indicating an open branch.
     */
    ImageResource cellTreeOpenItem();

    /**
     * The background used for selected items.
     */
    @ImageOptions(repeatStyle = RepeatStyle.Horizontal)
    ImageResource cellTreeSelectedBackground();

    /**
     * The styles used in this widget.
     */
    @Source("CellTree.css")
    Style cellTreeStyle();
  }

  /**
   * A {@link NodeAnimation} that reveals the contents of child nodes.
   */
  public static class RevealAnimation extends NodeAnimation {

    /**
     * Create a new {@link RevealAnimation}.
     *
     * @return the new animation
     */
    public static RevealAnimation create() {
      return new RevealAnimation();
    }

    /**
     * The container that holds the content, includind the children.
     */
    Element contentContainer;

    /**
     * The target height when opening, the start height when closing.
     */
    int height;

    /**
     * True if the node is opening, false if closing.
     */
    boolean opening;

    /**
     * The container that holds the child container.
     */
    private Element animFrame;

    /**
     * The container that holds the children.
     */
    private Element childContainer;

    /**
     * Not instantiable.
     */
    private RevealAnimation() {
    }

    @Override
    protected void onComplete() {
      cleanup();
    }

    @Override
    protected void onStart() {
      if (opening) {
        animFrame.getStyle().setHeight(1.0, Unit.PX);
        animFrame.getStyle().clearDisplay();
        height = contentContainer.getScrollHeight();
      } else {
        height = contentContainer.getOffsetHeight();
      }
    }

    @Override
    protected void onUpdate(double progress) {
      if (opening) {
        double curHeight = progress * height;
        animFrame.getStyle().setHeight(curHeight, Unit.PX);
      } else {
        double curHeight = (1.0 - progress) * height;
        animFrame.getStyle().setHeight(curHeight, Unit.PX);
      }
    }

    /**
     * Animate a {@link CellTreeNodeView} into its new state.
     *
     * @param node the {@link CellTreeNodeView} to animate
     * @param isAnimationEnabled true to animate
     */
    @Override
    void animate(CellTreeNodeView<?> node, boolean isAnimationEnabled) {
      // Cancel any pending animations.
      cancel();

      // Initialize the fields.
      this.opening = node.isOpen();
      animFrame = node.ensureAnimationFrame();
      contentContainer = node.ensureContentContainer();
      childContainer = node.ensureChildContainer();

      if (isAnimationEnabled) {
        // Animated.
        int duration = getDuration();
        int childCount = childContainer.getChildCount();
        if (childCount < 4) {
          // Reduce the duration if there are less than four items or it will
          // look really slow.
          duration = (int) ((childCount / 4.0) * duration);
        }
        run(duration);
      } else {
        // Non animated.
        cleanup();
      }
    }

    /**
     * Put the node back into a clean state and clear fields.
     */
    private void cleanup() {
      if (opening) {
        animFrame.getStyle().clearDisplay();
      } else {
        animFrame.getStyle().setDisplay(Display.NONE);
        childContainer.setInnerHTML("");
      }
      animFrame.getStyle().clearHeight();
      this.contentContainer = null;
      this.childContainer = null;
      this.animFrame = null;
    }
  }

  /**
   * A {@link NodeAnimation} that slides children into view.
   */
  public static class SlideAnimation extends RevealAnimation {
    /**
     * Create a new {@link RevealAnimation}.
     *
     * @return the new animation
     */
    public static SlideAnimation create() {
      return new SlideAnimation();
    }

    /**
     * Not instantiable.
     */
    private SlideAnimation() {
    }

    @Override
    protected void onComplete() {
      contentContainer.getStyle().clearPosition();
      contentContainer.getStyle().clearTop();
      contentContainer.getStyle().clearWidth();
      super.onComplete();
    }

    @Override
    protected void onStart() {
      super.onStart();
      if (opening) {
        contentContainer.getStyle().setTop(-height, Unit.PX);
      } else {
        contentContainer.getStyle().setTop(0, Unit.PX);
      }
      contentContainer.getStyle().setPosition(Position.RELATIVE);
    }

    @Override
    protected void onUpdate(double progress) {
      super.onUpdate(progress);
      if (opening) {
        double curTop = (1.0 - progress) * -height;
        contentContainer.getStyle().setTop(curTop, Unit.PX);
      } else {
        double curTop = progress * -height;
        contentContainer.getStyle().setTop(curTop, Unit.PX);
      }
    }
  }

  /**
   * Styles used by this widget.
   */
  public static interface Style extends CssResource {

    /**
     * Applied to the empty message.
     */
    String emptyMessage();

    /**
     * Applied to tree items.
     */
    String item();

    /**
     * Applied to open/close icon.
     */
    String itemImage();

    /**
     * Applied to the wrapper around the image and value.
     */
    String itemImageValue();

    /**
     * Applied to the value in an item.
     */
    String itemValue();

    /**
     * Applied to open tree items.
     */
    String openItem();

    /**
     * Applied to selected tree items.
     */
    String selectedItem();

    /**
     * Applied to the show more button.
     */
    String showMoreButton();

    /**
     * Applied to top level items.
     */
    String topItem();

    /**
     * Applied to open/close icon at the top level.
     */
    String topItemImage();

    /**
     * Applied to the wrapper around the image and value of top level items.
     */
    String topItemImageValue();
  }

  /**
   * A cleaner version of the table that uses less graphics.
   */
  public static interface CleanStyle extends Style {
    String topItem();

    String topItemImageValue();
  }

  /**
   * A cleaner version of the table that uses less graphics.
   */
  public static interface CleanResources extends Resources {

    @Source("cellTreeClosedArrow.png")
    ImageResource cellTreeClosedItem();

    @Source("cellTreeLoadingClean.gif")
    ImageResource cellTreeLoading();

    @Source("cellTreeOpenArrow.png")
    ImageResource cellTreeOpenItem();

    @Source("CellTreeClean.css")
    CleanStyle cellTreeStyle();
  }

  /**
   * The default number of children to show under a tree node.
   */
  private static final int DEFAULT_LIST_SIZE = 25;

  private static Resources DEFAULT_RESOURCES;

  private static Resources getDefaultResources() {
    if (DEFAULT_RESOURCES == null) {
      DEFAULT_RESOURCES = GWT.create(Resources.class);
    }
    return DEFAULT_RESOURCES;
  }

  /**
   * The animation.
   */
  private NodeAnimation animation;

  /**
   * The HTML used to generate the closed image.
   */
  private final String closedImageHtml;

  /**
   * The HTML used to generate the closed image for the top items.
   */
  private final String closedImageTopHtml;

  /**
   * The default number of children to display under each node.
   */
  private int defaultNodeSize = DEFAULT_LIST_SIZE;

  /**
   * The maximum width of the open and closed images.
   */
  private final int imageWidth;

  /**
   * Indicates whether or not animations are enabled.
   */
  private boolean isAnimationEnabled;

  /**
   * The HTML used to generate the loading image.
   */
  private final String loadingImageHtml;

  /**
   * The HTML used to generate the open image.
   */
  private final String openImageHtml;

  /**
   * The HTML used to generate the open image for the top items.
   */
  private final String openImageTopHtml;

  /**
   * The hidden root node in the tree.
   */
  private final CellTreeNodeView<?> rootNode;

  /**
   * The styles used by this widget.
   */
  private final Style style;

  /**
   * The {@link TreeViewModel} that backs the tree.
   */
  private final TreeViewModel viewModel;

  /**
   * Construct a new {@link CellTree}.
   *
   * @param <T> the type of data in the root node
   * @param viewModel the {@link TreeViewModel} that backs the tree
   * @param rootValue the hidden root value of the tree
   */
  public <T> CellTree(TreeViewModel viewModel, T rootValue) {
    this(viewModel, rootValue, getDefaultResources());
  }

  /**
   * Construct a new {@link CellTree}.
   *
   * @param <T> the type of data in the root node
   * @param viewModel the {@link TreeViewModel} that backs the tree
   * @param rootValue the hidden root value of the tree
   * @param resources the resources used to render the tree
   */
  public <T> CellTree(TreeViewModel viewModel, T rootValue, Resources resources) {
    this.viewModel = viewModel;
    this.style = resources.cellTreeStyle();
    this.style.ensureInjected();
    initWidget(new SimplePanel());
    setStyleName("gwt-StandardTreeView");

    // Initialize the open and close images strings.
    ImageResource treeOpen = resources.cellTreeOpenItem();
    ImageResource treeClosed = resources.cellTreeClosedItem();
    ImageResource treeLoading = resources.cellTreeLoading();
    openImageHtml = getImageHtml(treeOpen, false);
    closedImageHtml = getImageHtml(treeClosed, false);
    openImageTopHtml = getImageHtml(treeOpen, true);
    closedImageTopHtml = getImageHtml(treeClosed, true);
    loadingImageHtml = getImageHtml(treeLoading, false);
    imageWidth = Math.max(Math.max(treeOpen.getWidth(), treeClosed.getWidth()),
        treeLoading.getWidth());

    // We use one animation for the entire tree.
    setAnimation(SlideAnimation.create());

    // Add event handlers.
    sinkEvents(Event.ONCLICK | Event.ONCHANGE | Event.MOUSEEVENTS);

    // Associate a view with the item.
    CellTreeNodeView<T> root = new CellTreeNodeView<T>(this, null, null,
        getElement(), rootValue);
    rootNode = root;
    root.setOpen(true);
  }

  /**
   * Get the animation used to open and close nodes in this tree if animations
   * are enabled.
   *
   * @return the animation
   * @see #isAnimationEnabled()
   */
  public NodeAnimation getAnimation() {
    return animation;
  }

  /**
   * Get the default maximum number of children to display under each tree node.
   *
   * @return the default node size
   */
  public int getDefaultNodeSize() {
    return defaultNodeSize;
  }

  public TreeViewModel getTreeViewModel() {
    return viewModel;
  }

  public boolean isAnimationEnabled() {
    return isAnimationEnabled;
  }

  @Override
  public void onBrowserEvent(Event event) {
    super.onBrowserEvent(event);

    Element target = event.getEventTarget().cast();

    ArrayList<Element> chain = new ArrayList<Element>();
    collectElementChain(chain, getElement(), target);

    CellTreeNodeView<?> nodeView = findItemByChain(chain, 0, rootNode);
    if (nodeView != null && nodeView != rootNode) {
      if ("click".equals(event.getType())) {
        // Open the node when the open image is clicked.
        Element showMoreElem = nodeView.getShowMoreElement();
        if (nodeView.getImageElement().isOrHasChild(target)) {
          nodeView.setOpen(!nodeView.isOpen());
          return;
        } else if (showMoreElem != null && showMoreElem.isOrHasChild(target)) {
          nodeView.showMore();
          return;
        }
      }

      // Forward the event to the cell.
      if (nodeView.getCellParent().isOrHasChild(target)) {
        boolean consumesEvent = nodeView.fireEventToCell(event);
        if (!consumesEvent && "click".equals(event.getType())) {
          nodeView.select();
        }
      }
    }
  }

  /**
   * Set the animation used to open and close nodes in this tree. You must call
   * {@link #setAnimationEnabled(boolean)} to enable or disable animation.
   *
   * @param animation a {@link NodeAnimation}
   * @see #setAnimationEnabled(boolean)
   */
  public void setAnimation(NodeAnimation animation) {
    assert animation != null : "animation cannot be null";
    this.animation = animation;
  }

  public void setAnimationEnabled(boolean enable) {
    this.isAnimationEnabled = enable;
    if (!enable && animation != null) {
      animation.cancel();
    }
  }

  /**
   * Set the default number of children to display beneath each child node. If
   * more nodes are available, a button will appear at the end of the list
   * allowing the user to show more items. Changing this value will not affect
   * tree nodes that are already open.
   *
   * @param defaultNodeSize the max
   */
  public void setDefaultNodeSize(int defaultNodeSize) {
    this.defaultNodeSize = defaultNodeSize;
  }

  /**
   * Get the HTML to render the closed image.
   *
   * @param isTop true if the top element, false if not
   * @return the HTML string
   */
  String getClosedImageHtml(boolean isTop) {
    return isTop ? closedImageTopHtml : closedImageHtml;
  }

  /**
   * Get the width required for the images.
   *
   * @return the maximum width required for images.
   */
  int getImageWidth() {
    return imageWidth;
  }

  /**
   * @return the HTML to render the loading image.
   */
  String getLoadingImageHtml() {
    return loadingImageHtml;
  }

  /**
   * Get the HTML to render the open image.
   *
   * @param isTop true if the top element, false if not
   * @return the HTML string
   */
  String getOpenImageHtml(boolean isTop) {
    return isTop ? openImageTopHtml : openImageHtml;
  }

  /**
   * @return the Style used by the tree
   */
  Style getStyle() {
    return style;
  }

  /**
   * Animate the current state of a {@link CellTreeNodeView} in this tree.
   *
   * @param node the node to animate
   */
  void maybeAnimateTreeNode(CellTreeNodeView<?> node) {
    if (animation != null) {
      animation.animate(node, node.consumeAnimate() && isAnimationEnabled()
          && !node.isRootNode());
    }
  }

  /**
   * Collects parents going up the element tree, terminated at the tree root.
   */
  private void collectElementChain(ArrayList<Element> chain, Element hRoot,
      Element hElem) {
    if ((hElem == null) || (hElem == hRoot)) {
      return;
    }

    collectElementChain(chain, hRoot, hElem.getParentElement());
    chain.add(hElem);
  }

  private CellTreeNodeView<?> findItemByChain(ArrayList<Element> chain,
      int idx, CellTreeNodeView<?> parent) {
    if (idx == chain.size()) {
      return parent;
    }

    Element hCurElem = chain.get(idx);
    for (int i = 0, n = parent.getChildCount(); i < n; ++i) {
      CellTreeNodeView<?> child = parent.getChildNode(i);
      if (child.getElement() == hCurElem) {
        CellTreeNodeView<?> retItem = findItemByChain(chain, idx + 1, child);
        if (retItem == null) {
          return child;
        }
        return retItem;
      }
    }

    return findItemByChain(chain, idx + 1, parent);
  }

  /**
   * Get the HTML representation of an image.
   *
   * @param res the {@link ImageResource} to render as HTML
   * @param isTop true if the image is for a top level element.
   * @return the rendered HTML
   */
  private String getImageHtml(ImageResource res, boolean isTop) {
    StringBuilder sb = new StringBuilder();
    sb.append("<div class='").append(style.itemImage());
    if (isTop) {
      sb.append(" ").append(style.topItemImage());
    }
    sb.append("' ");

    // Add the position and dimensions.
    sb.append("style=\"position:absolute;left:0px;top:0px;");
    sb.append("height:").append(res.getHeight()).append("px;");
    sb.append("width:").append(res.getWidth()).append("px;");

    // Add the background, vertically centered.
    sb.append("background:url('").append(res.getURL()).append("') ");
    sb.append("no-repeat scroll center center transparent;");

    // Close the div and return.
    sb.append("\"></div>");
    return sb.toString();
  }
}
TOP

Related Classes of com.google.gwt.user.cellview.client.CellTree$CleanResources

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.