    /**
     * Adds custom behavior for left/right keyboard navigation for use with a tree.
     * Depends on the view having an expand and collapse method which accepts a
     * record. This selection model is created by default for {@link Ext.tree.Panel}.
     */
    Ext.define('Ext.selection.TreeModel', {
        extend: 'Ext.selection.RowModel',
        alias: 'selection.treemodel',

        /**
         * @cfg {Boolean} pruneRemoved @hide
         */

        constructor: function(config) {
            this.callParent(arguments);

            // If pruneRemoved is required, we must listen to the *TreeStore* to know when nodes
            // are added and removed
            if (this.pruneRemoved) {
                this.pruneRemoved = false;
                this.pruneRemovedNodes = true;
            }
        },

        // binds the store to the selModel.
        bindStore: function(store, initial) {
            var me = this;
            me.callParent(arguments);

            // TreePanel should have injected a reference to the TreeStore so that we can
            // listen for node removal.
            if (me.pruneRemovedNodes) {
                me.view.mon(me.treeStore, {
                    remove: me.onNodeRemove,
                    scope: me
                });
            }
        },

        onNodeRemove: function(parent, node, isMove) {
            // deselection of deleted records done in base Model class
            if (!isMove) {
                this.deselectDeletedRecords([node]);
            }
        },

        onKeyRight: function(e, t) {
            this.navExpand(e, t);
        },

        navExpand: function(e, t) {
            var focused = this.getLastFocused(),
                view    = this.view;

            if (focused) {
                // tree node is already expanded, go down instead
                // this handles both the case where we navigate to firstChild and if
                // there are no children to the nextSibling
                if (focused.isExpanded()) {
                    this.onKeyDown(e, t);
                // if its not a leaf node, expand it
                } else if (focused.isExpandable()) {
                    // If we are the normal side of a locking pair, only the tree view can do expanding
                    if (!view.isTreeView) {
                        view = view.lockingPartner;
                    }

                    view.expand(focused);
                }
            }
        },

        onKeyLeft: function(e, t) {
            this.navCollapse(e, t);
        },

        navCollapse: function(e, t) {
            var me = this,
                focused = this.getLastFocused(),
                view    = this.view,
                parentNode;

            if (focused) {
                parentNode = focused.parentNode;
                // if focused node is already expanded, collapse it
                if (focused.isExpanded()) {
                    // If we are the normal side of a locking pair, only the tree view can do collapsing
                    if (!view.isTreeView) {
                        view = view.lockingPartner;
                    }

                    view.collapse(focused);
                // has a parentNode and its not root
                // TODO: this needs to cover the case where the root isVisible
                } else if (parentNode && !parentNode.isRoot()) {
                    // Select a range of records when doing multiple selection.
                    if (e.shiftKey) {
                        me.selectRange(parentNode, focused, e.ctrlKey, 'up');
                        me.setLastFocused(parentNode);
                    // just move focus, not selection
                    } else if (e.ctrlKey) {
                        me.setLastFocused(parentNode);
                    // select it
                    } else {
                        me.select(parentNode);
                    }
                }
            }
        },

        onKeySpace: function(e, t) {
            if (e.record.data.checked != null) {
                this.toggleCheck(e);
            } else {
                this.callParent(arguments);
            }
        },

        onKeyEnter: function(e, t) {
            if (e.record.data.checked != null) {
                this.toggleCheck(e);
            } else {
                this.callParent(arguments);
            }
        },

        toggleCheck: function(e) {
            var view = this.view,
                selected = this.getLastSelected();

            e.stopEvent();
            if (selected) {
                // If we are the normal side of a locking pair, only the tree view can do on heckChange
                if (!view.isTreeView) {
                    view = view.lockingPartner;
                }

                view.onCheckChange(selected);
            }
        }
    });