text: /**
   * RowModel Selection Model implements row based navigation for
   * {@link Ext.grid.Panel grid panels} via user input. RowModel is the default grid selection
   * model and, generally, will not need to be specified.
   *
   * By utilizing the selModel config as an object, you may also set configurations for:
   *
   * + {@link #mode} - Specifies whether user may select multiple rows or single rows
   * + {@link #allowDeselect} - Specifies whether user may deselect records when in SINGLE mode
   * + {@link #ignoreRightMouseSelection} - Specifies whether user may ignore right clicks
   * for selection purposes
   *
   * In the example below, we've enabled MULTI mode. This means that multiple rows can be selected.
   *
   *     @example
   *     var store = Ext.create('Ext.data.Store', {
   *         fields: ['name', 'email', 'phone'],
   *         data: [
   *             { name: 'Lisa', email: 'lisa@simpsons.com', phone: '555-111-1224' },
   *             { name: 'Bart', email: 'bart@simpsons.com', phone: '555-222-1234' },
   *             { name: 'Homer', email: 'homer@simpsons.com', phone: '555-222-1244' },
   *             { name: 'Marge', email: 'marge@simpsons.com', phone: '555-222-1254' }
   *         ]
   *     });
   *
   *     Ext.create('Ext.grid.Panel', {
   *         title: 'Simpsons',
   *         store: store,
   *         width: 400,
   *         renderTo: Ext.getBody(),
   *         selModel: {
   *            selType: 'rowmodel', // rowmodel is the default selection model
   *            mode: 'MULTI' // Allows selection of multiple rows
   *         },
   *         columns: [
   *             { text: 'Name',  dataIndex: 'name'  },
   *             { text: 'Email', dataIndex: 'email', flex: 1 },
   *             { text: 'Phone', dataIndex: 'phone' }
   *         ]
   *     });
   */
  Ext.define('Ext.selection.RowModel', {
      extend: 'Ext.selection.DataViewModel',
      alias: 'selection.rowmodel',
      requires: [
          'Ext.grid.CellContext'
      ],
  
  
      /**
       * @cfg {Boolean} enableKeyNav
       *
       * Turns on/off keyboard navigation within the grid.
       */
      enableKeyNav: true,
  
      /**
       * @event beforedeselect
       * Fired before a record is deselected. If any listener returns false, the
       * deselection is cancelled.
       * @param {Ext.selection.RowModel} this
       * @param {Ext.data.Model} record The deselected record
       * @param {Number} index The row index deselected
       */
  
      /**
       * @event beforeselect
       * Fired before a record is selected. If any listener returns false, the
       * selection is cancelled.
       * @param {Ext.selection.RowModel} this
       * @param {Ext.data.Model} record The selected record
       * @param {Number} index The row index selected
       */
  
      /**
       * @event deselect
       * Fired after a record is deselected
       * @param {Ext.selection.RowModel} this
       * @param {Ext.data.Model} record The deselected record
       * @param {Number} index The row index deselected
       */
  
      /**
       * @event select
       * Fired after a record is selected
       * @param {Ext.selection.RowModel} this
       * @param {Ext.data.Model} record The selected record
       * @param {Number} index The row index selected
       */
  
      isRowModel: true,
  
      /**
       * @inheritdoc
       */
      deselectOnContainerClick: false,
  
      onUpdate: function(record) {
          var me = this,
              view = me.view,
              index;
  
          if (view && me.isSelected(record)) {
              index = view.indexOf(record);
              view.onRowSelect(index);
              if (record === me.lastFocused) {
                  view.onRowFocus(index, true);
              }
          }
      },
  
      // Allow the GridView to update the UI by
      // adding/removing a CSS class from the row.
      onSelectChange: function(record, isSelected, suppressEvent, commitFn) {
          var me      = this,
              views   = me.views || [me.view],
              viewsLn = views.length,
              recordIndex = me.store.indexOf(record),
              eventName = isSelected ? 'select' : 'deselect',
              i, view;
  
          if ((suppressEvent || me.fireEvent('before' + eventName, me, record, recordIndex)) !== false &&
                  commitFn() !== false) {
  
              // Selection models can handle more than one view
              for (i = 0; i < viewsLn; i++) {
                  view = views[i];
                  recordIndex  = view.indexOf(record);
  
                  // The record might not be rendered due to either buffered rendering,
                  // or removal/hiding of all columns (eg empty locked side).
                  if (view.indexOf(record) !== -1) {
                      if (isSelected) {
                          view.onRowSelect(recordIndex, suppressEvent);
                      } else {
                          view.onRowDeselect(recordIndex, suppressEvent);
                      }
                  }
              }
  
              if (!suppressEvent) {
                  me.fireEvent(eventName, me, record, recordIndex);
              }
          }
      },
  
      /**
       * Returns position of the first selected cell in the selection in the format {row: row, column: column}
       * @deprecated 5.0.1 Use the {@link Ext.view.Table#getNavigationModel NavigationModel} instead.
       */
      getCurrentPosition: function() {
          var firstSelection = this.selected.getAt(0);
          if (firstSelection) {
              return new Ext.grid.CellContext(this.view).setPosition(this.store.indexOf(firstSelection), 0);
          }
      },
  
      selectByPosition: function (position, keepExisting) {
          if (!position.isCellContext) {
              position = new Ext.grid.CellContext(this.view).setPosition(position.row, position.column);
          }
          this.select(position.record, keepExisting);
      },
  
      /**
       * Selects the record immediately following the currently selected record.
       * @param {Boolean} [keepExisting] True to retain existing selections
       * @param {Boolean} [suppressEvent] Set to false to not fire a select event
       * @return {Boolean} `true` if there is a next record, else `false`
       */
      selectNext: function(keepExisting, suppressEvent) {
          var me = this,
              store = me.store,
              selection = me.getSelection(),
              record = selection[selection.length - 1],
              index = me.view.indexOf(record) + 1,
              success;
  
          if (index === store.getCount() || index === 0) {
              success = false;
          } else {
              me.doSelect(index, keepExisting, suppressEvent);
              success = true;
          }
          return success;
      },
  
      /**
       * Selects the record that precedes the currently selected record.
       * @param {Boolean} [keepExisting] True to retain existing selections
       * @param {Boolean} [suppressEvent] Set to false to not fire a select event
       * @return {Boolean} `true` if there is a previous record, else `false`
       */
      selectPrevious: function(keepExisting, suppressEvent) {
          var me = this,
              selection = me.getSelection(),
              record = selection[0],
              index = me.view.indexOf(record) - 1,
              success;
  
          if (index < 0) {
              success = false;
          } else {
              me.doSelect(index, keepExisting, suppressEvent);
              success = true;
          }
          return success;
      },
  
      isRowSelected: function(record) {
          return this.isSelected(record);
      },
  
      isCellSelected: function(view, record, columnHeader) {
          return this.isSelected(record);
      },
  
      vetoSelection: function(e) {
          var navModel = this.view.getNavigationModel(),
              key = e.getKey(),
              isLeftRight = key === e.RIGHT || key === e.LEFT;
  
          // Veto row selection upon key-based, in-row left/right navigation.
          // Else pass to superclass to veto.
          return (isLeftRight && navModel.previousRecord === navModel.record) || this.callParent([e]);
      }
  });
  