    /**
     * @class Ext.selection.CellModel
     * @extends Ext.selection.Model
     * @private
     */
    Ext.define('Ext.selection.CellModel', {
        extend: 'Ext.selection.Model',
        alias: 'selection.cellmodel',
        requires: ['Ext.util.KeyNav'],

        /**
         * @cfg {Boolean} enableKeyNav
         * Turns on/off keyboard navigation within the grid. Defaults to true.
         */
        enableKeyNav: true,

        /**
         * @cfg {Boolean} preventWrap
         * Set this configuration to true to prevent wrapping around of selection as
         * a user navigates to the first or last column. Defaults to false.
         */
        preventWrap: false,

        constructor: function(){
            this.addEvents(
                /**
                 * @event deselect
                 * Fired after a cell is deselected
                 * @param {Ext.selection.CellModel} this
                 * @param {Ext.data.Model} record The record of the deselected cell
                 * @param {Number} row The row index deselected
                 * @param {Number} column The column index deselected
                 */
                'deselect',

                /**
                 * @event select
                 * Fired after a cell is selected
                 * @param {Ext.selection.CellModel} this
                 * @param {Ext.data.Model} record The record of the selected cell
                 * @param {Number} row The row index selected
                 * @param {Number} column The column index selected
                 */
                'select'
            );
            this.callParent(arguments);
        },

        bindComponent: function(view) {
            var me = this;
            me.primaryView = view;
            me.views = me.views || [];
            me.views.push(view);
            me.bind(view.getStore(), true);

            view.on({
                cellmousedown: me.onMouseDown,
                refresh: me.onViewRefresh,
                scope: me
            });

            if (me.enableKeyNav) {
                me.initKeyNav(view);
            }
        },

        initKeyNav: function(view) {
            var me = this;

            if (!view.rendered) {
                view.on('render', Ext.Function.bind(me.initKeyNav, me, [view], 0), me, {single: true});
                return;
            }

            view.el.set({
                tabIndex: -1
            });

            // view.el has tabIndex -1 to allow for
            // keyboard events to be passed to it.
            me.keyNav = Ext.create('Ext.util.KeyNav', view.el, {
                up: me.onKeyUp,
                down: me.onKeyDown,
                right: me.onKeyRight,
                left: me.onKeyLeft,
                tab: me.onKeyTab,
                scope: me
            });
        },

        getHeaderCt: function() {
            return this.primaryView.headerCt;
        },

        onKeyUp: function(e, t) {
            this.move('up', e);
        },

        onKeyDown: function(e, t) {
            this.move('down', e);
        },

        onKeyLeft: function(e, t) {
            this.move('left', e);
        },

        onKeyRight: function(e, t) {
            this.move('right', e);
        },

        move: function(dir, e) {
            var me = this,
                pos = me.primaryView.walkCells(me.getCurrentPosition(), dir, e, me.preventWrap);
            if (pos) {
                me.setCurrentPosition(pos);
            }
            return pos;
        },

        /**
         * Returns the current position in the format {row: row, column: column}
         */
        getCurrentPosition: function() {
            return this.position;
        },

        /**
         * Sets the current position
         * @param {Object} position The position to set.
         */
        setCurrentPosition: function(pos) {
            var me = this;

            if (me.position) {
                me.onCellDeselect(me.position);
            }
            if (pos) {
                me.onCellSelect(pos);
            }
            me.position = pos;
        },

        /**
         * Set the current position based on where the user clicks.
         * @private
         */
        onMouseDown: function(view, cell, cellIndex, record, row, rowIndex, e) {
            this.setCurrentPosition({
                row: rowIndex,
                column: cellIndex
            });
        },

        // notify the view that the cell has been selected to update the ui
        // appropriately and bring the cell into focus
        onCellSelect: function(position) {
            var me = this,
                store = me.view.getStore(),
                record = store.getAt(position.row);

            me.doSelect(record);
            me.primaryView.onCellSelect(position);
            // TODO: Remove temporary cellFocus call here.
            me.primaryView.onCellFocus(position);
            me.fireEvent('select', me, record, position.row, position.column);
        },

        // notify view that the cell has been deselected to update the ui
        // appropriately
        onCellDeselect: function(position) {
            var me = this,
                store = me.view.getStore(),
                record = store.getAt(position.row);

            me.doDeselect(record);
            me.primaryView.onCellDeselect(position);
            me.fireEvent('deselect', me, record, position.row, position.column);
        },

        onKeyTab: function(e, t) {
            var me = this,
                direction = e.shiftKey ? 'left' : 'right',
                editingPlugin = me.view.editingPlugin,
                position = me.move(direction, e);

            if (editingPlugin && position && me.wasEditing) {
                editingPlugin.startEditByPosition(position);
            }
            delete me.wasEditing;
        },

        onEditorTab: function(editingPlugin, e) {
            var me = this,
                direction = e.shiftKey ? 'left' : 'right',
                position  = me.move(direction, e);

            if (position) {
                editingPlugin.startEditByPosition(position);
                me.wasEditing = true;
            }
        },

        refresh: function() {
            var pos = this.getCurrentPosition();
            if (pos) {
                this.onCellSelect(pos);
            }
        },

        onViewRefresh: function() {
            var pos = this.getCurrentPosition();
            if (pos) {
                this.onCellDeselect(pos);
                this.setCurrentPosition(null);
            }
        },

        selectByPosition: function(position) {
            this.setCurrentPosition(position);
        }
    });