Package com.sencha.gxt.dnd.core.client

Source Code of com.sencha.gxt.dnd.core.client.TreeGridDropTarget$TreeGridDropTargetResources

/**
* Sencha GXT 3.1.0-beta - Sencha for GWT
* Copyright(c) 2007-2014, Sencha, Inc.
* licensing@sencha.com
*
* http://www.sencha.com/products/gxt/license/
*/
package com.sencha.gxt.dnd.core.client;

import java.util.List;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.Timer;
import com.sencha.gxt.core.client.dom.AutoScrollSupport;
import com.sencha.gxt.core.client.dom.ScrollSupport;
import com.sencha.gxt.core.client.dom.XElement;
import com.sencha.gxt.core.client.util.Rectangle;
import com.sencha.gxt.data.shared.TreeStore;
import com.sencha.gxt.data.shared.event.StoreRemoveEvent;
import com.sencha.gxt.data.shared.event.StoreRemoveEvent.StoreRemoveHandler;
import com.sencha.gxt.dnd.core.client.DND.Feedback;
import com.sencha.gxt.dnd.core.client.DND.Operation;
import com.sencha.gxt.widget.core.client.tree.Tree.TreeNode;
import com.sencha.gxt.widget.core.client.treegrid.TreeGrid;

/**
* Enables a {@link TreeGrid} to act as the target of a drag and drop operation.
* <p/>
* Use {@link #setFeedback(com.sencha.gxt.dnd.core.client.DND.Feedback)} to specify whether to allow inserting
* items between items, appending items to the end, or both (defaults to
* {@link Feedback#BOTH}).
* <p/>
* Use {@link #setOperation(com.sencha.gxt.dnd.core.client.DND.Operation)} to specify whether to move items or copy
* them (defaults to {@link Operation#MOVE}).
*
* @param <M> the model type
*/
public class TreeGridDropTarget<M> extends DropTarget {

  /**
   * The tree drop target resources.
   */
  public interface TreeGridDropTargetResources extends ClientBundle {
    /**
     * Returns an icon to indicate an insert at the current item.
     *
     * @return an icon to indicate an insert at the current item
     */
    ImageResource dropInsert();

    /**
     * Returns an icon to indicate an insert above the current item.
     *
     * @return an icon to indicate an insert above the current item
     */
    ImageResource dropInsertAbove();

    /**
     * Returns an icon to indicate an insert below the current item.
     *
     * @return an icon to indicate an insert below the current item
     */
    ImageResource dropInsertBelow();
  }

  protected TreeNode<M> activeItem, appendItem;
  protected int status;
  protected TreeGridDropTargetResources resources = GWT.create(TreeGridDropTargetResources.class);

  private boolean allowDropOnLeaf = false;
  private boolean autoExpand = true, autoScroll = true;
  private int autoExpandDelay = 800;
  private boolean addChildren;
  private AutoScrollSupport scrollSupport;

  /**
   * Creates a drop target for the specified tree grid.
   *
   * @param tree the tree grid to enable as a drop target
   */
  public TreeGridDropTarget(TreeGrid<M> tree) {
    super(tree);
    bind(tree);
  }

  @SuppressWarnings("unchecked")
  @Override
  public TreeGrid<M> getWidget() {
    return (TreeGrid<M>) super.getWidget();
  }

  /**
   * Returns true if children are being added when inserting into the TreeStore.
   *
   * @return the add children state
   */
  public boolean isAddChildren() {
    return addChildren;
  }

  /**
   * Returns whether drops are allowed on leaf nodes.
   *
   * @return true of drops on leafs are allowed
   */
  public boolean isAllowDropOnLeaf() {
    return allowDropOnLeaf;
  }

  /**
   * Returns true if auto expand is enabled (defaults to true).
   *
   * @return the auto expand state
   */
  public boolean isAutoExpand() {
    return autoExpand;
  }

  /**
   * Returns true if auto scroll is enabled (defaults to true).
   *
   * @return true if auto scroll enabled
   */
  public boolean isAutoScroll() {
    return autoScroll;
  }

  /**
   * True to add children when inserting models into the TreeStore (defaults to
   * false).
   *
   * @param addChildren true to add children
   */
  public void setAddChildren(boolean addChildren) {
    this.addChildren = addChildren;
  }

  /**
   * True to allow drops on leaf nodes (defaults to false).
   *
   * @param allowDropOnLeaf true to enable drops on leaf nodes
   */
  public void setAllowDropOnLeaf(boolean allowDropOnLeaf) {
    this.allowDropOnLeaf = allowDropOnLeaf;
  }

  /**
   * True to automatically expand the active tree item when the user hovers over
   * a collapsed item (defaults to true). Use {@link #setAutoExpandDelay(int)}
   * to set the delay.
   *
   * @param autoExpand true to auto expand
   */
  public void setAutoExpand(boolean autoExpand) {
    this.autoExpand = autoExpand;
  }

  /**
   * Sets the delay used to auto expand items (defaults to 800).
   *
   * @param autoExpandDelay the delay in milliseconds
   */
  public void setAutoExpandDelay(int autoExpandDelay) {
    this.autoExpandDelay = autoExpandDelay;
  }

  /**
   * True to automatically scroll the tree when the user hovers over the top and
   * bottom of the tree grid (defaults to true).
   *
   * @see ScrollSupport
   *
   * @param autoScroll true to enable auto scroll
   */
  public void setAutoScroll(boolean autoScroll) {
    this.autoScroll = autoScroll;
  }

  protected void appendModel(M p, List<?> items, int index) {
    if (items.size() == 0) return;
    if (items.get(0) instanceof TreeStore.TreeNode) {
      @SuppressWarnings("unchecked")
      List<TreeStore.TreeNode<M>> nodes = (List<TreeStore.TreeNode<M>>) items;
      if (p == null) {
        getWidget().getTreeStore().addSubTree(index, nodes);
      } else {
        getWidget().getTreeStore().addSubTree(p, index, nodes);
      }
    } else {
      @SuppressWarnings("unchecked")
      List<M> models = (List<M>) items;
      if (p == null) {
        getWidget().getTreeStore().insert(index, models);
      } else {
        getWidget().getTreeStore().insert(p, index, models);
      }
    }
  }

  protected void bind(TreeGrid<M> tree) {
    // tree.addListener(Events.Unregister, new Listener<TreeGridEvent>() {
    // public void handleEvent(TreeGridEvent be) {
    // if (activeItem == be.getTreeNode()) {
    // activeItem = null;
    // }
    // }
    // });
    tree.getTreeStore().addStoreRemoveHandler(new StoreRemoveHandler<M>() {
      @Override
      public void onRemove(StoreRemoveEvent<M> event) {
        if (activeItem != null && activeItem.getModel() == event.getItem()) {
          activeItem = null;
        }
      }
    });
  }

  protected void clearStyle(TreeNode<M> node) {
    getWidget().getTreeView().onDropChange(getWidget().getView().getRow(node.getModel()), false);
  }

  protected void handleAppend(DndDragMoveEvent event, final TreeNode<M> item) {
    // clear any active append item
    if (activeItem != null && activeItem != item) {
      clearStyle(activeItem);
    }
    status = -1;

    Insert.get().hide();
    event.getStatusProxy().setStatus(true);
    if (activeItem != null) {
      clearStyle(activeItem);
    }

    if (item != null && item != appendItem && autoExpand && !item.isExpanded()) {
      Timer t = new Timer() {
        @Override
        public void run() {
          if (item == appendItem) {
            getWidget().setExpanded(item.getModel(), true);
          }
        }
      };
      t.schedule(autoExpandDelay);
    }
    appendItem = item;
    activeItem = item;
    if (activeItem != null) {
      // TODO this might not get the right element
      Element row = getWidget().getView().findRow(
          event.getDragMoveEvent().getNativeEvent().getEventTarget().<Element> cast());
      getWidget().getTreeView().onDropChange(row, true);
    }
  }

  protected void handleAppendDrop(DndDropEvent event, TreeNode<M> item) {
    // TODO not M, but TreeStore.TreeNode<M>
    List<?> models = (List<?>) event.getData();
    if (models.size() > 0) {
      M p = null;
      if (item != null) {
        p = item.getModel();
        appendModel(p, models, getWidget().getTreeStore().getChildCount(item.getModel()));
      } else {
        appendModel(p, models, getWidget().getTreeStore().getRootItems().size());
      }

    }
  }

  protected void handleInsert(DndDragMoveEvent event, final TreeNode<M> item) {
    int height = getWidget().getView().getRow(item.getModel()).getOffsetHeight();
    int mid = height / 2;
    int top = getWidget().getView().getRow(item.getModel()).getAbsoluteTop();
    mid += top;
    int y = event.getDragMoveEvent().getNativeEvent().getClientY();
    boolean before = y < mid;

    if ((!getWidget().isLeaf(item.getModel()) || allowDropOnLeaf)
        && (feedback == Feedback.BOTH || feedback == Feedback.APPEND)
        && ((before && y > top + 4) || (!before && y < top + height - 4))) {
      handleAppend(event, item);
      return;
    }

    // clear any active append item
    if (activeItem != null && activeItem != item) {
      clearStyle(activeItem);
    }

    appendItem = null;

    status = before ? 0 : 1;

    if (activeItem != null) {
      clearStyle(activeItem);
    }

    activeItem = item;

    if (activeItem != null) {
      TreeStore<M> store = getWidget().getTreeStore();

      int idx = -1;

      M p = store.getParent(activeItem.getModel());
      if (p != null) {
        idx = store.getChildren(p).indexOf(activeItem.getModel());
      } else {
        idx = store.getRootItems().indexOf(activeItem.getModel());
      }

      ImageResource status = resources.dropInsert();
      if (before && idx == 0) {
        status = resources.dropInsertAbove();
      } else if (idx > 1 && !before && p != null && idx == store.getChildCount(p) - 1) {
        status = resources.dropInsertBelow();
      }

      event.getStatusProxy().setStatus(true, status);

      if (before) {
        showInsert(event, (Element) getWidget().getView().getRow(item.getModel()), true);
      } else {
        showInsert(event, (Element) getWidget().getView().getRow(item.getModel()), false);
      }
    }
  }

  protected void handleInsertDrop(DndDropEvent event, TreeNode<M> item, int index) {
    List<?> droppedItems = (List<?>) event.getData();
    if (droppedItems.size() > 0) {
      int idx = getWidget().getTreeStore().indexOf(item.getModel());
      idx = status == 0 ? idx : idx + 1;
      M p = getWidget().getTreeStore().getParent(item.getModel());
      appendModel(p, droppedItems, idx);
    }
  }

  @Override
  protected void onDragCancelled(DndDragCancelEvent event) {
    super.onDragCancelled(event);
    if (autoScroll) {
      scrollSupport.stop();
    }
  }

  @Override
  protected void onDragDrop(DndDropEvent event) {
    super.onDragDrop(event);

    if (activeItem != null && status == -1) {
      clearStyle(activeItem);
      if (event.getData() != null) {
        handleAppendDrop(event, activeItem);
      }
    } else if (activeItem != null && status != -1) {
      if (event.getData() != null) {
        handleInsertDrop(event, activeItem, status);
      }
    } else if (activeItem == null && status == -1) {
      if (event.getData() != null) {
        handleAppendDrop(event, activeItem);
      }
    } else {
      // event.setCancelled(true);
    }
    status = -1;
    activeItem = null;
    appendItem = null;

    if (autoScroll) {
      scrollSupport.stop();
    }
  }

  @Override
  protected void onDragEnter(DndDragEnterEvent event) {
    super.onDragEnter(event);
    event.getStatusProxy().setStatus(false);

    if (autoScroll) {
      if (scrollSupport == null) {
        scrollSupport = new AutoScrollSupport(getWidget().getView().getScroller());
      } else if (scrollSupport.getScrollElement() == null) {
        scrollSupport.setScrollElement(getWidget().getView().getScroller());
      }
      scrollSupport.start();
    }
  }

  @Override
  protected void onDragFail(DndDropEvent event) {
    super.onDragFail(event);
    if (autoScroll) {
      scrollSupport.stop();
    }
  }

  @Override
  protected void onDragLeave(DndDragLeaveEvent event) {
    super.onDragLeave(event);
    if (activeItem != null) {
      clearStyle(activeItem);
      activeItem = null;
    }

    if (autoScroll) {
      scrollSupport.stop();
    }
  }

  @Override
  protected void onDragMove(DndDragMoveEvent event) {
    event.setCancelled(false);
  }

  @Override
  protected void showFeedback(DndDragMoveEvent event) {
    // TODO this might not get the right element
    final TreeNode<M> item = getWidget().findNode(
        event.getDragMoveEvent().getNativeEvent().getEventTarget().<Element> cast());
    if (item == null) {
      if (activeItem != null) {
        clearStyle(activeItem);
      }
    }

    if (item != null && event.getDropTarget().getWidget() == event.getDragSource().getWidget()) {
      @SuppressWarnings("unchecked")
      TreeGrid<M> source = (TreeGrid<M>) event.getDragSource().getWidget();
      List<M> list = source.getSelectionModel().getSelection();
      M overModel = item.getModel();
      for (int i = 0; i < list.size(); i++) {
        M sel = list.get(i);
        if (overModel == sel) {
          Insert.get().hide();
          event.getStatusProxy().setStatus(false);
          return;
        }
        List<M> children = getWidget().getTreeStore().getAllChildren(sel);
        if (children.contains(item.getModel())) {
          Insert.get().hide();
          event.getStatusProxy().setStatus(false);
          return;
        }
      }
    }

    boolean append = feedback == Feedback.APPEND || feedback == Feedback.BOTH;
    boolean insert = feedback == Feedback.INSERT || feedback == Feedback.BOTH;

    if (item == null) {
      handleAppend(event, item);
    } else if (insert) {
      handleInsert(event, item);
    } else if ((!getWidget().isLeaf(item.getModel()) || allowDropOnLeaf) && append) {
      handleAppend(event, item);
    } else {
      if (activeItem != null) {
        clearStyle(activeItem);
      }
      status = -1;
      activeItem = null;
      appendItem = null;
      Insert.get().hide();
      event.getStatusProxy().setStatus(false);
    }
  }

  private void showInsert(DndDragMoveEvent event, Element elem, boolean before) {
    Insert insert = Insert.get();
    insert.show(elem);
    Rectangle rect = elem.<XElement> cast().getBounds();
    int y = before ? rect.getY() - 2 : (rect.getY() + rect.getHeight() - 4);

    // dont call setBounds though component as it expects widget to be attached
    insert.getElement().setBounds(rect.getX(), y, rect.getWidth(), 6);
  }
}
TOP

Related Classes of com.sencha.gxt.dnd.core.client.TreeGridDropTarget$TreeGridDropTargetResources

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.