I needed to restrict a tree to a max depth, but could not find a simple solution for this within the GXT library. I therefore extended TreeDropTarget to get the functionality I needed. This might not be the most elegant solution, but at least it worked. I started using a drag move handler, but the lack of information on if this is an append or insert event stopped me from creating a reliable solution. I think this is functionality that should be in the libary to begin with.

Code:
import java.util.List;


import com.sencha.gxt.data.shared.TreeStore;
import com.sencha.gxt.dnd.core.client.DndDragMoveEvent;
import com.sencha.gxt.dnd.core.client.Insert;
import com.sencha.gxt.dnd.core.client.TreeDropTarget;
import com.sencha.gxt.widget.core.client.tree.Tree;
import com.sencha.gxt.widget.core.client.tree.Tree.TreeNode;


public class MaxDepthTreeDropTarget<M> extends TreeDropTarget<M> {


    private final int maxDepth;


    public MaxDepthTreeDropTarget(final Tree<M, ?> tree, final int maxDepth) {
        super(tree);
        this.maxDepth = maxDepth;
    }


    @Override
    protected final void handleAppend(final DndDragMoveEvent event, final TreeNode<M> item) {
        if (this.hasFolder(event)) {
            if (this.getDepth(item) >= this.maxDepth - 1) {
                this.cancel(event);
                return;
            }
        } else {
            if (this.getDepth(item) >= this.maxDepth) {
                this.cancel(event);
                return;
            }
        }


        super.handleAppend(event, item);
    }


    @Override
    protected final void handleInsert(final DndDragMoveEvent event, final TreeNode<M> item) {
        if (this.hasFolder(event)) {
            if (this.getDepth(item) >= this.maxDepth) {
                this.cancel(event);
                return;
            }
        } else {
            if (this.getDepth(item) > this.maxDepth) {
                this.cancel(event);
                return;
            }
        }


        super.handleInsert(event, item);
    }


    @SuppressWarnings("unchecked")
    private boolean hasFolder(final DndDragMoveEvent event) {
        for (final TreeStore.TreeNode<M> treeNode : (List<TreeStore.TreeNode<M>>) event.getData()) {
            if (!this.getWidget().isLeaf(treeNode.getData())) {
                return true;
            }
        }
        return false;
    }


    private int getDepth(final TreeNode<M> item) {
        return this.getWidget().getStore().getDepth(item.getModel());
    }


    private void cancel(final DndDragMoveEvent event) {
        event.setCancelled(true);
        event.getStatusProxy().setStatus(false);
        Insert.get().hide();
    }
}