text: /**
   * @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);
      }
  });