Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / docs / source / Table2.html
index dcfeeca..ff0b2e2 100644 (file)
@@ -3,8 +3,8 @@
 <head>
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
   <title>The source code</title>
-  <link href="../prettify/prettify.css" type="text/css" rel="stylesheet" />
-  <script type="text/javascript" src="../prettify/prettify.js"></script>
+  <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
+  <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
   <style type="text/css">
     .highlight { display: block; background-color: #ddd; }
   </style>
   </script>
 </head>
 <body onload="prettyPrint(); highlight();">
-  <pre class="prettyprint lang-js"><span id='Ext-layout-container-Table'>/**
-</span> * @class Ext.layout.container.Table
- * @extends Ext.layout.container.Auto
- * &lt;p&gt;This layout allows you to easily render content into an HTML table.  The total number of columns can be
- * specified, and rowspan and colspan can be used to create complex layouts within the table.
- * This class is intended to be extended or created via the &lt;code&gt;layout: {type: 'table'}&lt;/code&gt;
- * {@link Ext.container.Container#layout} config, and should generally not need to be created directly via the new keyword.&lt;/p&gt;
- * &lt;p&gt;Note that when creating a layout via config, the layout-specific config properties must be passed in via
- * the {@link Ext.container.Container#layout} object which will then be applied internally to the layout.  In the
- * case of TableLayout, the only valid layout config properties are {@link #columns} and {@link #tableAttrs}.
- * However, the items added to a TableLayout can supply the following table-specific config properties:&lt;/p&gt;
- * &lt;ul&gt;
- * &lt;li&gt;&lt;b&gt;rowspan&lt;/b&gt; Applied to the table cell containing the item.&lt;/li&gt;
- * &lt;li&gt;&lt;b&gt;colspan&lt;/b&gt; Applied to the table cell containing the item.&lt;/li&gt;
- * &lt;li&gt;&lt;b&gt;cellId&lt;/b&gt; An id applied to the table cell containing the item.&lt;/li&gt;
- * &lt;li&gt;&lt;b&gt;cellCls&lt;/b&gt; A CSS class name added to the table cell containing the item.&lt;/li&gt;
- * &lt;/ul&gt;
- * &lt;p&gt;The basic concept of building up a TableLayout is conceptually very similar to building up a standard
- * HTML table.  You simply add each panel (or &quot;cell&quot;) that you want to include along with any span attributes
- * specified as the special config properties of rowspan and colspan which work exactly like their HTML counterparts.
- * Rather than explicitly creating and nesting rows and columns as you would in HTML, you simply specify the
- * total column count in the layoutConfig and start adding panels in their natural order from left to right,
- * top to bottom.  The layout will automatically figure out, based on the column count, rowspans and colspans,
- * how to position each panel within the table.  Just like with HTML tables, your rowspans and colspans must add
- * up correctly in your overall layout or you'll end up with missing and/or extra cells!  Example usage:&lt;/p&gt;
- * {@img Ext.layout.container.Table/Ext.layout.container.Table.png Ext.layout.container.Table container layout}
- * &lt;pre&gt;&lt;code&gt;
-// This code will generate a layout table that is 3 columns by 2 rows
-// with some spanning included.  The basic layout will be:
-// +--------+-----------------+
-// |   A    |   B             |
-// |        |--------+--------|
-// |        |   C    |   D    |
-// +--------+--------+--------+
-    Ext.create('Ext.panel.Panel', {
-        title: 'Table Layout',
-        width: 300,
-        height: 150,
-        layout: {
-            type: 'table',
-            // The total column count must be specified here
-            columns: 3
-        },
-        defaults: {
-            // applied to each contained panel
-            bodyStyle:'padding:20px'
-        },
-        items: [{
-            html: 'Cell A content',
-            rowspan: 2
-        },{
-            html: 'Cell B content',
-            colspan: 2
-        },{
-            html: 'Cell C content',
-            cellCls: 'highlight'
-        },{
-            html: 'Cell D content'
-        }],
-        renderTo: Ext.getBody()
-    });
-&lt;/code&gt;&lt;/pre&gt;
+  <pre class="prettyprint lang-js"><span id='Ext-panel-Table'>/**
+</span> * @author Nicolas Ferrero
+ *
+ * TablePanel is the basis of both {@link Ext.tree.Panel TreePanel} and {@link Ext.grid.Panel GridPanel}.
+ *
+ * TablePanel aggregates:
+ *
+ *  - a Selection Model
+ *  - a View
+ *  - a Store
+ *  - Scrollers
+ *  - Ext.grid.header.Container
  */
+Ext.define('Ext.panel.Table', {
+    extend: 'Ext.panel.Panel',
 
-Ext.define('Ext.layout.container.Table', {
+    alias: 'widget.tablepanel',
 
-    /* Begin Definitions */
+    uses: [
+        'Ext.selection.RowModel',
+        'Ext.grid.Scroller',
+        'Ext.grid.header.Container',
+        'Ext.grid.Lockable'
+    ],
 
-    alias: ['layout.table'],
-    extend: 'Ext.layout.container.Auto',
-    alternateClassName: 'Ext.layout.TableLayout',
+    extraBaseCls: Ext.baseCSSPrefix + 'grid',
+    extraBodyCls: Ext.baseCSSPrefix + 'grid-body',
 
-    /* End Definitions */
+    layout: 'fit',
+<span id='Ext-panel-Table-property-hasView'>    /**
+</span>     * @property {Boolean} hasView
+     * True to indicate that a view has been injected into the panel.
+     */
+    hasView: false,
 
-<span id='Ext-layout-container-Table-cfg-columns'>    /**
-</span>     * @cfg {Number} columns
-     * The total number of columns to create in the table for this layout.  If not specified, all Components added to
-     * this layout will be rendered into a single row using one column per Component.
+    // each panel should dictate what viewType and selType to use
+<span id='Ext-panel-Table-cfg-viewType'>    /**
+</span>     * @cfg {String} viewType
+     * An xtype of view to use. This is automatically set to 'gridview' by {@link Ext.grid.Panel Grid}
+     * and to 'treeview' by {@link Ext.tree.Panel Tree}.
      */
+    viewType: null,
 
-    // private
-    monitorResize:false,
+<span id='Ext-panel-Table-cfg-viewConfig'>    /**
+</span>     * @cfg {Object} viewConfig
+     * A config object that will be applied to the grid's UI view. Any of the config options available for
+     * {@link Ext.view.Table} can be specified here. This option is ignored if {@link #view} is specified.
+     */
 
-    type: 'table',
+<span id='Ext-panel-Table-cfg-view'>    /**
+</span>     * @cfg {Ext.view.Table} view
+     * The {@link Ext.view.Table} used by the grid. Use {@link #viewConfig} to just supply some config options to
+     * view (instead of creating an entire View instance).
+     */
 
-    // Table layout is a self-sizing layout. When an item of for example, a dock layout, the Panel must expand to accommodate
-    // a table layout. See in particular AbstractDock::onLayout for use of this flag.
-    autoSize: true,
+<span id='Ext-panel-Table-cfg-selType'>    /**
+</span>     * @cfg {String} selType
+     * An xtype of selection model to use. Defaults to 'rowmodel'. This is used to create selection model if just
+     * a config object or nothing at all given in {@link #selModel} config.
+     */
+    selType: 'rowmodel',
 
-    clearEl: true, // Base class will not create it if already truthy. Not needed in tables.
+<span id='Ext-panel-Table-cfg-selModel'>    /**
+</span>     * @cfg {Ext.selection.Model/Object} selModel
+     * A {@link Ext.selection.Model selection model} instance or config object.  In latter case the {@link #selType}
+     * config option determines to which type of selection model this config is applied.
+     */
 
-    targetCls: Ext.baseCSSPrefix + 'table-layout-ct',
-    tableCls: Ext.baseCSSPrefix + 'table-layout',
-    cellCls: Ext.baseCSSPrefix + 'table-layout-cell',
+<span id='Ext-panel-Table-cfg-multiSelect'>    /**
+</span>     * @cfg {Boolean} multiSelect
+     * True to enable 'MULTI' selection mode on selection model. See {@link Ext.selection.Model#mode}.
+     */
 
-<span id='Ext-layout-container-Table-cfg-tableAttrs'>    /**
-</span>     * @cfg {Object} tableAttrs
-     * &lt;p&gt;An object containing properties which are added to the {@link Ext.core.DomHelper DomHelper} specification
-     * used to create the layout's &lt;tt&gt;&amp;lt;table&amp;gt;&lt;/tt&gt; element. Example:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;
-{
-    xtype: 'panel',
-    layout: {
-        type: 'table',
-        columns: 3,
-        tableAttrs: {
-            style: {
-                width: '100%'
-            }
-        }
-    }
-}&lt;/code&gt;&lt;/pre&gt;
+<span id='Ext-panel-Table-cfg-simpleSelect'>    /**
+</span>     * @cfg {Boolean} simpleSelect
+     * True to enable 'SIMPLE' selection mode on selection model. See {@link Ext.selection.Model#mode}.
      */
-    tableAttrs:null,
 
-<span id='Ext-layout-container-Table-cfg-trAttrs'>    /**
-</span>     * @cfg {Object} trAttrs
-     * &lt;p&gt;An object containing properties which are added to the {@link Ext.core.DomHelper DomHelper} specification
-     * used to create the layout's &lt;tt&gt;&amp;lt;tr&amp;gt;&lt;/tt&gt; elements.
+<span id='Ext-panel-Table-cfg-store'>    /**
+</span>     * @cfg {Ext.data.Store} store (required)
+     * The {@link Ext.data.Store Store} the grid should use as its data source.
      */
 
-<span id='Ext-layout-container-Table-cfg-tdAttrs'>    /**
-</span>     * @cfg {Object} tdAttrs
-     * &lt;p&gt;An object containing properties which are added to the {@link Ext.core.DomHelper DomHelper} specification
-     * used to create the layout's &lt;tt&gt;&amp;lt;td&amp;gt;&lt;/tt&gt; elements.
+<span id='Ext-panel-Table-cfg-scrollDelta'>    /**
+</span>     * @cfg {Number} scrollDelta
+     * Number of pixels to scroll when scrolling with mousewheel.
      */
+    scrollDelta: 40,
 
-<span id='Ext-layout-container-Table-method-renderItems'>    /**
-</span>     * @private
-     * Iterates over all passed items, ensuring they are rendered in a cell in the proper
-     * location in the table structure.
+<span id='Ext-panel-Table-cfg-scroll'>    /**
+</span>     * @cfg {String/Boolean} scroll
+     * Scrollers configuration. Valid values are 'both', 'horizontal' or 'vertical'.
+     * True implies 'both'. False implies 'none'.
      */
-    renderItems: function(items) {
-        var tbody = this.getTable().tBodies[0],
-            rows = tbody.rows,
-            i = 0,
-            len = items.length,
-            cells, curCell, rowIdx, cellIdx, item, trEl, tdEl, itemCt;
+    scroll: true,
 
-        // Calculate the correct cell structure for the current items
-        cells = this.calculateCells(items);
+<span id='Ext-panel-Table-cfg-columns'>    /**
+</span>     * @cfg {Ext.grid.column.Column[]} columns
+     * An array of {@link Ext.grid.column.Column column} definition objects which define all columns that appear in this
+     * grid. Each column definition provides the header text for the column, and a definition of where the data for that
+     * column comes from.
+     */
 
-        // Loop over each cell and compare to the current cells in the table, inserting/
-        // removing/moving cells as needed, and making sure each item is rendered into
-        // the correct cell.
-        for (; i &lt; len; i++) {
-            curCell = cells[i];
-            rowIdx = curCell.rowIdx;
-            cellIdx = curCell.cellIdx;
-            item = items[i];
-
-            // If no row present, create and insert one
-            trEl = rows[rowIdx];
-            if (!trEl) {
-                trEl = tbody.insertRow(rowIdx);
-                if (this.trAttrs) {
-                    trEl.set(this.trAttrs);
+<span id='Ext-panel-Table-cfg-forceFit'>    /**
+</span>     * @cfg {Boolean} forceFit
+     * Ttrue to force the columns to fit into the available width. Headers are first sized according to configuration,
+     * whether that be a specific width, or flex. Then they are all proportionally changed in width so that the entire
+     * content width is used.
+     */
+
+<span id='Ext-panel-Table-cfg-features'>    /**
+</span>     * @cfg {Ext.grid.feature.Feature[]} features
+     * An array of grid Features to be added to this grid. See {@link Ext.grid.feature.Feature} for usage.
+     */
+
+<span id='Ext-panel-Table-cfg-hideHeaders'>    /**
+</span>     * @cfg {Boolean} [hideHeaders=false]
+     * True to hide column headers.
+     */
+
+<span id='Ext-panel-Table-cfg-deferRowRender'>    /**
+</span>     * @cfg {Boolean} deferRowRender
+     * Defaults to true to enable deferred row rendering.
+     *
+     * This allows the View to execute a refresh quickly, with the expensive update of the row structure deferred so
+     * that layouts with GridPanels appear, and lay out more quickly.
+     */
+
+     deferRowRender: true,
+     
+<span id='Ext-panel-Table-cfg-sortableColumns'>    /**
+</span>     * @cfg {Boolean} sortableColumns
+     * False to disable column sorting via clicking the header and via the Sorting menu items.
+     */
+    sortableColumns: true,
+
+<span id='Ext-panel-Table-cfg-enableLocking'>    /**
+</span>     * @cfg {Boolean} [enableLocking=false]
+     * True to enable locking support for this grid. Alternatively, locking will also be automatically
+     * enabled if any of the columns in the column configuration contain the locked config option.
+     */
+    enableLocking: false,
+
+    verticalScrollDock: 'right',
+    verticalScrollerType: 'gridscroller',
+
+    horizontalScrollerPresentCls: Ext.baseCSSPrefix + 'horizontal-scroller-present',
+    verticalScrollerPresentCls: Ext.baseCSSPrefix + 'vertical-scroller-present',
+
+    // private property used to determine where to go down to find views
+    // this is here to support locking.
+    scrollerOwner: true,
+
+    invalidateScrollerOnRefresh: true,
+
+<span id='Ext-panel-Table-cfg-enableColumnMove'>    /**
+</span>     * @cfg {Boolean} enableColumnMove
+     * False to disable column dragging within this grid.
+     */
+    enableColumnMove: true,
+
+<span id='Ext-panel-Table-cfg-enableColumnResize'>    /**
+</span>     * @cfg {Boolean} enableColumnResize
+     * False to disable column resizing within this grid.
+     */
+    enableColumnResize: true,
+
+<span id='Ext-panel-Table-cfg-enableColumnHide'>    /**
+</span>     * @cfg {Boolean} enableColumnHide
+     * False to disable column hiding within this grid.
+     */
+    enableColumnHide: true,
+
+    initComponent: function() {
+        //&lt;debug&gt;
+        if (!this.viewType) {
+            Ext.Error.raise(&quot;You must specify a viewType config.&quot;);
+        }
+        if (this.headers) {
+            Ext.Error.raise(&quot;The headers config is not supported. Please specify columns instead.&quot;);
+        }
+        //&lt;/debug&gt;
+
+        var me          = this,
+            scroll      = me.scroll,
+            vertical    = false,
+            horizontal  = false,
+            headerCtCfg = me.columns || me.colModel,
+            i           = 0,
+            view,
+            border = me.border;
+
+        if (me.hideHeaders) {
+            border = false;
+        }
+
+        // Look up the configured Store. If none configured, use the fieldless, empty Store defined in Ext.data.Store.
+        me.store = Ext.data.StoreManager.lookup(me.store || 'ext-empty-store');
+
+        // The columns/colModel config may be either a fully instantiated HeaderContainer, or an array of Column definitions, or a config object of a HeaderContainer
+        // Either way, we extract a columns property referencing an array of Column definitions.
+        if (headerCtCfg instanceof Ext.grid.header.Container) {
+            me.headerCt = headerCtCfg;
+            me.headerCt.border = border;
+            me.columns = me.headerCt.items.items;
+        } else {
+            if (Ext.isArray(headerCtCfg)) {
+                headerCtCfg = {
+                    items: headerCtCfg,
+                    border: border
+                };
+            }
+            Ext.apply(headerCtCfg, {
+                forceFit: me.forceFit,
+                sortable: me.sortableColumns,
+                enableColumnMove: me.enableColumnMove,
+                enableColumnResize: me.enableColumnResize,
+                enableColumnHide: me.enableColumnHide,
+                border:  border
+            });
+            me.columns = headerCtCfg.items;
+
+             // If any of the Column objects contain a locked property, and are not processed, this is a lockable TablePanel, a
+             // special view will be injected by the Ext.grid.Lockable mixin, so no processing of .
+             if (me.enableLocking || Ext.ComponentQuery.query('{locked !== undefined}{processed != true}', me.columns).length) {
+                 me.self.mixin('lockable', Ext.grid.Lockable);
+                 me.injectLockable();
+             }
+        }
+
+        me.addEvents(
+<span id='Ext-panel-Table-event-reconfigure'>            /**
+</span>             * @event reconfigure
+             * Fires after a reconfigure.
+             * @param {Ext.panel.Table} this
+             */
+            'reconfigure',
+<span id='Ext-panel-Table-event-viewready'>            /**
+</span>             * @event viewready
+             * Fires when the grid view is available (use this for selecting a default row).
+             * @param {Ext.panel.Table} this
+             */
+            'viewready',
+<span id='Ext-panel-Table-event-scrollerhide'>            /**
+</span>             * @event scrollerhide
+             * Fires when a scroller is hidden.
+             * @param {Ext.grid.Scroller} scroller
+             * @param {String} orientation Orientation, can be 'vertical' or 'horizontal'
+             */
+            'scrollerhide',
+<span id='Ext-panel-Table-event-scrollershow'>            /**
+</span>             * @event scrollershow
+             * Fires when a scroller is shown.
+             * @param {Ext.grid.Scroller} scroller
+             * @param {String} orientation Orientation, can be 'vertical' or 'horizontal'
+             */
+            'scrollershow'
+        );
+
+        me.bodyCls = me.bodyCls || '';
+        me.bodyCls += (' ' + me.extraBodyCls);
+        
+        me.cls = me.cls || '';
+        me.cls += (' ' + me.extraBaseCls);
+
+        // autoScroll is not a valid configuration
+        delete me.autoScroll;
+
+        // If this TablePanel is lockable (Either configured lockable, or any of the defined columns has a 'locked' property)
+        // than a special lockable view containing 2 side-by-side grids will have been injected so we do not need to set up any UI.
+        if (!me.hasView) {
+
+            // If we were not configured with a ready-made headerCt (either by direct config with a headerCt property, or by passing
+            // a HeaderContainer instance as the 'columns' property, then go ahead and create one from the config object created above.
+            if (!me.headerCt) {
+                me.headerCt = Ext.create('Ext.grid.header.Container', headerCtCfg);
+            }
+
+            // Extract the array of Column objects
+            me.columns = me.headerCt.items.items;
+
+            if (me.hideHeaders) {
+                me.headerCt.height = 0;
+                me.headerCt.border = false;
+                me.headerCt.addCls(Ext.baseCSSPrefix + 'grid-header-ct-hidden');
+                me.addCls(Ext.baseCSSPrefix + 'grid-header-hidden');
+                // IE Quirks Mode fix
+                // If hidden configuration option was used, several layout calculations will be bypassed.
+                if (Ext.isIEQuirks) {
+                    me.headerCt.style = {
+                        display: 'none'
+                    };
                 }
             }
 
-            // If no cell present, create and insert one
-            itemCt = tdEl = Ext.get(trEl.cells[cellIdx] || trEl.insertCell(cellIdx));
-            if (this.needsDivWrap()) { //create wrapper div if needed - see docs below
-                itemCt = tdEl.first() || tdEl.createChild({tag: 'div'});
-                itemCt.setWidth(null);
+            // turn both on.
+            if (scroll === true || scroll === 'both') {
+                vertical = horizontal = true;
+            } else if (scroll === 'horizontal') {
+                horizontal = true;
+            } else if (scroll === 'vertical') {
+                vertical = true;
+            // All other values become 'none' or false.
+            } else {
+                me.headerCt.availableSpaceOffset = 0;
             }
 
-            // Render or move the component into the cell
-            if (!item.rendered) {
-                this.renderItem(item, itemCt, 0);
+            if (vertical) {
+                me.verticalScroller = Ext.ComponentManager.create(me.initVerticalScroller());
+                me.mon(me.verticalScroller, {
+                    bodyscroll: me.onVerticalScroll,
+                    scope: me
+                });
             }
-            else if (!this.isValidParent(item, itemCt, 0)) {
-                this.moveItem(item, itemCt, 0);
+
+            if (horizontal) {
+                me.horizontalScroller = Ext.ComponentManager.create(me.initHorizontalScroller());
+                me.mon(me.horizontalScroller, {
+                    bodyscroll: me.onHorizontalScroll,
+                    scope: me
+                });
             }
 
-            // Set the cell properties
-            if (this.tdAttrs) {
-                tdEl.set(this.tdAttrs);
+            me.headerCt.on('resize', me.onHeaderResize, me);
+            me.relayHeaderCtEvents(me.headerCt);
+            me.features = me.features || [];
+            if (!Ext.isArray(me.features)) {
+                me.features = [me.features];
             }
-            tdEl.set({
-                colSpan: item.colspan || 1,
-                rowSpan: item.rowspan || 1,
-                id: item.cellId || '',
-                cls: this.cellCls + ' ' + (item.cellCls || '')
+            me.dockedItems = me.dockedItems || [];
+            me.dockedItems.unshift(me.headerCt);
+            me.viewConfig = me.viewConfig || {};
+            me.viewConfig.invalidateScrollerOnRefresh = me.invalidateScrollerOnRefresh;
+
+            // AbstractDataView will look up a Store configured as an object
+            // getView converts viewConfig into a View instance
+            view = me.getView();
+
+            view.on({
+                afterrender: function () {
+                    // hijack the view el's scroll method
+                    view.el.scroll = Ext.Function.bind(me.elScroll, me);
+                    // We use to listen to document.body wheel events, but that's a
+                    // little much. We scope just to the view now.
+                    me.mon(view.el, {
+                        mousewheel: me.onMouseWheel,
+                        scope: me
+                    });
+                },
+                single: true
             });
+            me.items = [view];
+            me.hasView = true;
 
-            // If at the end of a row, remove any extra cells
-            if (!cells[i + 1] || cells[i + 1].rowIdx !== rowIdx) {
-                cellIdx++;
-                while (trEl.cells[cellIdx]) {
-                    trEl.deleteCell(cellIdx);
-                }
-            }
+            me.mon(view.store, {
+                load: me.onStoreLoad,
+                scope: me
+            });
+            me.mon(view, {
+                viewReady: me.onViewReady,
+                resize: me.onViewResize,
+                refresh: {
+                    fn: me.onViewRefresh,
+                    scope: me,
+                    buffer: 50
+                },
+                scope: me
+            });
+            this.relayEvents(view, [
+<span id='Ext-panel-Table-event-beforeitemmousedown'>                /**
+</span>                 * @event beforeitemmousedown
+                 * @alias Ext.view.View#beforeitemmousedown
+                 */
+                'beforeitemmousedown',
+<span id='Ext-panel-Table-event-beforeitemmouseup'>                /**
+</span>                 * @event beforeitemmouseup
+                 * @alias Ext.view.View#beforeitemmouseup
+                 */
+                'beforeitemmouseup',
+<span id='Ext-panel-Table-event-beforeitemmouseenter'>                /**
+</span>                 * @event beforeitemmouseenter
+                 * @alias Ext.view.View#beforeitemmouseenter
+                 */
+                'beforeitemmouseenter',
+<span id='Ext-panel-Table-event-beforeitemmouseleave'>                /**
+</span>                 * @event beforeitemmouseleave
+                 * @alias Ext.view.View#beforeitemmouseleave
+                 */
+                'beforeitemmouseleave',
+<span id='Ext-panel-Table-event-beforeitemclick'>                /**
+</span>                 * @event beforeitemclick
+                 * @alias Ext.view.View#beforeitemclick
+                 */
+                'beforeitemclick',
+<span id='Ext-panel-Table-event-beforeitemdblclick'>                /**
+</span>                 * @event beforeitemdblclick
+                 * @alias Ext.view.View#beforeitemdblclick
+                 */
+                'beforeitemdblclick',
+<span id='Ext-panel-Table-event-beforeitemcontextmenu'>                /**
+</span>                 * @event beforeitemcontextmenu
+                 * @alias Ext.view.View#beforeitemcontextmenu
+                 */
+                'beforeitemcontextmenu',
+<span id='Ext-panel-Table-event-itemmousedown'>                /**
+</span>                 * @event itemmousedown
+                 * @alias Ext.view.View#itemmousedown
+                 */
+                'itemmousedown',
+<span id='Ext-panel-Table-event-itemmouseup'>                /**
+</span>                 * @event itemmouseup
+                 * @alias Ext.view.View#itemmouseup
+                 */
+                'itemmouseup',
+<span id='Ext-panel-Table-event-itemmouseenter'>                /**
+</span>                 * @event itemmouseenter
+                 * @alias Ext.view.View#itemmouseenter
+                 */
+                'itemmouseenter',
+<span id='Ext-panel-Table-event-itemmouseleave'>                /**
+</span>                 * @event itemmouseleave
+                 * @alias Ext.view.View#itemmouseleave
+                 */
+                'itemmouseleave',
+<span id='Ext-panel-Table-event-itemclick'>                /**
+</span>                 * @event itemclick
+                 * @alias Ext.view.View#itemclick
+                 */
+                'itemclick',
+<span id='Ext-panel-Table-event-itemdblclick'>                /**
+</span>                 * @event itemdblclick
+                 * @alias Ext.view.View#itemdblclick
+                 */
+                'itemdblclick',
+<span id='Ext-panel-Table-event-itemcontextmenu'>                /**
+</span>                 * @event itemcontextmenu
+                 * @alias Ext.view.View#itemcontextmenu
+                 */
+                'itemcontextmenu',
+<span id='Ext-panel-Table-event-beforecontainermousedown'>                /**
+</span>                 * @event beforecontainermousedown
+                 * @alias Ext.view.View#beforecontainermousedown
+                 */
+                'beforecontainermousedown',
+<span id='Ext-panel-Table-event-beforecontainermouseup'>                /**
+</span>                 * @event beforecontainermouseup
+                 * @alias Ext.view.View#beforecontainermouseup
+                 */
+                'beforecontainermouseup',
+<span id='Ext-panel-Table-event-beforecontainermouseover'>                /**
+</span>                 * @event beforecontainermouseover
+                 * @alias Ext.view.View#beforecontainermouseover
+                 */
+                'beforecontainermouseover',
+<span id='Ext-panel-Table-event-beforecontainermouseout'>                /**
+</span>                 * @event beforecontainermouseout
+                 * @alias Ext.view.View#beforecontainermouseout
+                 */
+                'beforecontainermouseout',
+<span id='Ext-panel-Table-event-beforecontainerclick'>                /**
+</span>                 * @event beforecontainerclick
+                 * @alias Ext.view.View#beforecontainerclick
+                 */
+                'beforecontainerclick',
+<span id='Ext-panel-Table-event-beforecontainerdblclick'>                /**
+</span>                 * @event beforecontainerdblclick
+                 * @alias Ext.view.View#beforecontainerdblclick
+                 */
+                'beforecontainerdblclick',
+<span id='Ext-panel-Table-event-beforecontainercontextmenu'>                /**
+</span>                 * @event beforecontainercontextmenu
+                 * @alias Ext.view.View#beforecontainercontextmenu
+                 */
+                'beforecontainercontextmenu',
+<span id='Ext-panel-Table-event-containermouseup'>                /**
+</span>                 * @event containermouseup
+                 * @alias Ext.view.View#containermouseup
+                 */
+                'containermouseup',
+<span id='Ext-panel-Table-event-containermouseover'>                /**
+</span>                 * @event containermouseover
+                 * @alias Ext.view.View#containermouseover
+                 */
+                'containermouseover',
+<span id='Ext-panel-Table-event-containermouseout'>                /**
+</span>                 * @event containermouseout
+                 * @alias Ext.view.View#containermouseout
+                 */
+                'containermouseout',
+<span id='Ext-panel-Table-event-containerclick'>                /**
+</span>                 * @event containerclick
+                 * @alias Ext.view.View#containerclick
+                 */
+                'containerclick',
+<span id='Ext-panel-Table-event-containerdblclick'>                /**
+</span>                 * @event containerdblclick
+                 * @alias Ext.view.View#containerdblclick
+                 */
+                'containerdblclick',
+<span id='Ext-panel-Table-event-containercontextmenu'>                /**
+</span>                 * @event containercontextmenu
+                 * @alias Ext.view.View#containercontextmenu
+                 */
+                'containercontextmenu',
+<span id='Ext-panel-Table-event-selectionchange'>                /**
+</span>                 * @event selectionchange
+                 * @alias Ext.selection.Model#selectionchange
+                 */
+                'selectionchange',
+<span id='Ext-panel-Table-event-beforeselect'>                /**
+</span>                 * @event beforeselect
+                 * @alias Ext.selection.RowModel#beforeselect
+                 */
+                'beforeselect',
+<span id='Ext-panel-Table-event-select'>                /**
+</span>                 * @event select
+                 * @alias Ext.selection.RowModel#select
+                 */
+                'select',
+<span id='Ext-panel-Table-event-beforedeselect'>                /**
+</span>                 * @event beforedeselect
+                 * @alias Ext.selection.RowModel#beforedeselect
+                 */
+                'beforedeselect',
+<span id='Ext-panel-Table-event-deselect'>                /**
+</span>                 * @event deselect
+                 * @alias Ext.selection.RowModel#deselect
+                 */
+                'deselect'
+            ]);
         }
 
-        // Delete any extra rows
-        rowIdx++;
-        while (tbody.rows[rowIdx]) {
-            tbody.deleteRow(rowIdx);
+        me.callParent(arguments);
+    },
+    
+    onRender: function(){
+        var vScroll = this.verticalScroller,
+            hScroll = this.horizontalScroller;
+
+        if (vScroll) {
+            vScroll.ensureDimension();
         }
+        if (hScroll) {
+            hScroll.ensureDimension();
+        }
+        this.callParent(arguments);    
     },
 
-    afterLayout: function() {
+    // state management
+    initStateEvents: function(){
+        var events = this.stateEvents;
+        // push on stateEvents if they don't exist
+        Ext.each(['columnresize', 'columnmove', 'columnhide', 'columnshow', 'sortchange'], function(event){
+            if (Ext.Array.indexOf(events, event)) {
+                events.push(event);
+            }
+        });
         this.callParent();
+    },
+
+<span id='Ext-panel-Table-method-initHorizontalScroller'>    /**
+</span>     * Returns the horizontal scroller config.
+     */
+    initHorizontalScroller: function () {
+        var me = this,
+            ret = {
+                xtype: 'gridscroller',
+                dock: 'bottom',
+                section: me,
+                store: me.store
+            };
+
+        return ret;
+    },
+
+<span id='Ext-panel-Table-method-initVerticalScroller'>    /**
+</span>     * Returns the vertical scroller config.
+     */
+    initVerticalScroller: function () {
+        var me = this,
+            ret = me.verticalScroller || {};
+
+        Ext.applyIf(ret, {
+            xtype: me.verticalScrollerType,
+            dock: me.verticalScrollDock,
+            store: me.store
+        });
+
+        return ret;
+    },
+
+    relayHeaderCtEvents: function (headerCt) {
+        this.relayEvents(headerCt, [
+<span id='Ext-panel-Table-event-columnresize'>            /**
+</span>             * @event columnresize
+             * @alias Ext.grid.header.Container#columnresize
+             */
+            'columnresize',
+<span id='Ext-panel-Table-event-columnmove'>            /**
+</span>             * @event columnmove
+             * @alias Ext.grid.header.Container#columnmove
+             */
+            'columnmove',
+<span id='Ext-panel-Table-event-columnhide'>            /**
+</span>             * @event columnhide
+             * @alias Ext.grid.header.Container#columnhide
+             */
+            'columnhide',
+<span id='Ext-panel-Table-event-columnshow'>            /**
+</span>             * @event columnshow
+             * @alias Ext.grid.header.Container#columnshow
+             */
+            'columnshow',
+<span id='Ext-panel-Table-event-sortchange'>            /**
+</span>             * @event sortchange
+             * @alias Ext.grid.header.Container#sortchange
+             */
+            'sortchange'
+        ]);
+    },
+
+    getState: function(){
+        var me = this,
+            state = me.callParent(),
+            sorter = me.store.sorters.first();
 
-        if (this.needsDivWrap()) {
-            // set wrapper div width to match layed out item - see docs below
-            Ext.Array.forEach(this.getLayoutItems(), function(item) {
-                Ext.fly(item.el.dom.parentNode).setWidth(item.getWidth());
+        state.columns = (me.headerCt || me).getColumnsState();
+
+        if (sorter) {
+            state.sort = {
+                property: sorter.property,
+                direction: sorter.direction
+            };
+        }
+
+        return state;
+    },
+
+    applyState: function(state) {
+        var me = this,
+            sorter = state.sort,
+            store = me.store,
+            columns = state.columns;
+
+        delete state.columns;
+
+        // Ensure superclass has applied *its* state.
+        // AbstractComponent saves dimensions (and anchor/flex) plus collapsed state.
+        me.callParent(arguments);
+
+        if (columns) {
+            (me.headerCt || me).applyColumnsState(columns);
+        }
+
+        if (sorter) {
+            if (store.remoteSort) {
+                store.sorters.add(Ext.create('Ext.util.Sorter', {
+                    property: sorter.property,
+                    direction: sorter.direction
+                }));
+            }
+            else {
+                store.sort(sorter.property, sorter.direction);
+            }
+        }
+    },
+
+<span id='Ext-panel-Table-method-getStore'>    /**
+</span>     * Returns the store associated with this Panel.
+     * @return {Ext.data.Store} The store
+     */
+    getStore: function(){
+        return this.store;
+    },
+
+<span id='Ext-panel-Table-method-getView'>    /**
+</span>     * Gets the view for this panel.
+     * @return {Ext.view.Table}
+     */
+    getView: function() {
+        var me = this,
+            sm;
+
+        if (!me.view) {
+            sm = me.getSelectionModel();
+            me.view = me.createComponent(Ext.apply({}, me.viewConfig, {
+                deferInitialRefresh: me.deferRowRender,
+                xtype: me.viewType,
+                store: me.store,
+                headerCt: me.headerCt,
+                selModel: sm,
+                features: me.features,
+                panel: me
+            }));
+            me.mon(me.view, {
+                uievent: me.processEvent,
+                scope: me
             });
+            sm.view = me.view;
+            me.headerCt.view = me.view;
+            me.relayEvents(me.view, ['cellclick', 'celldblclick']);
         }
+        return me.view;
     },
 
-<span id='Ext-layout-container-Table-method-calculateCells'>    /**
+<span id='Ext-panel-Table-property-setAutoScroll'>    /**
 </span>     * @private
-     * Determine the row and cell indexes for each component, taking into consideration
-     * the number of columns and each item's configured colspan/rowspan values.
-     * @param {Array} items The layout components
-     * @return {Array} List of row and cell indexes for each of the components
-     */
-    calculateCells: function(items) {
-        var cells = [],
-            rowIdx = 0,
-            colIdx = 0,
-            cellIdx = 0,
-            totalCols = this.columns || Infinity,
-            rowspans = [], //rolling list of active rowspans for each column
-            i = 0, j,
-            len = items.length,
-            item;
+     * @override
+     * autoScroll is never valid for all classes which extend TablePanel.
+     */
+    setAutoScroll: Ext.emptyFn,
 
-        for (; i &lt; len; i++) {
-            item = items[i];
-
-            // Find the first available row/col slot not taken up by a spanning cell
-            while (colIdx &gt;= totalCols || rowspans[colIdx] &gt; 0) {
-                if (colIdx &gt;= totalCols) {
-                    // move down to next row
-                    colIdx = 0;
-                    cellIdx = 0;
-                    rowIdx++;
-
-                    // decrement all rowspans
-                    for (j = 0; j &lt; totalCols; j++) {
-                        if (rowspans[j] &gt; 0) {
-                            rowspans[j]--;
-                        }
+    // This method hijacks Ext.view.Table's el scroll method.
+    // This enables us to keep the virtualized scrollbars in sync
+    // with the view. It currently does NOT support animation.
+    elScroll: function(direction, distance, animate) {
+        var me = this,
+            scroller;
+
+        if (direction === &quot;up&quot; || direction === &quot;left&quot;) {
+            distance = -distance;
+        }
+        
+        if (direction === &quot;down&quot; || direction === &quot;up&quot;) {
+            scroller = me.getVerticalScroller();
+            
+            //if the grid does not currently need a vertical scroller don't try to update it (EXTJSIV-3891)
+            if (scroller) {
+                scroller.scrollByDeltaY(distance);
+            }
+        } else {
+            scroller = me.getHorizontalScroller();
+            
+            //if the grid does not currently need a horizontal scroller don't try to update it (EXTJSIV-3891)
+            if (scroller) {
+                scroller.scrollByDeltaX(distance);
+            }
+        }
+    },
+
+<span id='Ext-panel-Table-method-processEvent'>    /**
+</span>     * @private
+     * Processes UI events from the view. Propagates them to whatever internal Components need to process them.
+     * @param {String} type Event type, eg 'click'
+     * @param {Ext.view.Table} view TableView Component
+     * @param {HTMLElement} cell Cell HtmlElement the event took place within
+     * @param {Number} recordIndex Index of the associated Store Model (-1 if none)
+     * @param {Number} cellIndex Cell index within the row
+     * @param {Ext.EventObject} e Original event
+     */
+    processEvent: function(type, view, cell, recordIndex, cellIndex, e) {
+        var me = this,
+            header;
+
+        if (cellIndex !== -1) {
+            header = me.headerCt.getGridColumns()[cellIndex];
+            return header.processEvent.apply(header, arguments);
+        }
+    },
+
+<span id='Ext-panel-Table-method-determineScrollbars'>    /**
+</span>     * Requests a recalculation of scrollbars and puts them in if they are needed.
+     */
+    determineScrollbars: function() {
+        // Set a flag so that afterComponentLayout does not recurse back into here.
+        if (this.determineScrollbarsRunning) {
+            return;
+        }
+        this.determineScrollbarsRunning = true;
+        var me = this,
+            view = me.view,
+            box,
+            tableEl,
+            scrollWidth,
+            clientWidth,
+            scrollHeight,
+            clientHeight,
+            verticalScroller = me.verticalScroller,
+            horizontalScroller = me.horizontalScroller,
+            curScrollbars = (verticalScroller   &amp;&amp; verticalScroller.ownerCt === me ? 1 : 0) |
+                            (horizontalScroller &amp;&amp; horizontalScroller.ownerCt === me ? 2 : 0),
+            reqScrollbars = 0; // 1 = vertical, 2 = horizontal, 3 = both
+
+        // If we are not collapsed, and the view has been rendered AND filled, then we can determine scrollbars
+        if (!me.collapsed &amp;&amp; view &amp;&amp; view.viewReady) {
+
+            // Calculate maximum, *scrollbarless* space which the view has available.
+            // It will be the Fit Layout's calculated size, plus the widths of any currently shown scrollbars
+            box = view.el.getSize();
+
+            clientWidth  = box.width  + ((curScrollbars &amp; 1) ? verticalScroller.width : 0);
+            clientHeight = box.height + ((curScrollbars &amp; 2) ? horizontalScroller.height : 0);
+
+            // Calculate the width of the scrolling block
+            // There will never be a horizontal scrollbar if all columns are flexed.
+
+            scrollWidth = (me.headerCt.query('[flex]').length &amp;&amp; !me.headerCt.layout.tooNarrow) ? 0 : me.headerCt.getFullWidth();
+
+            // Calculate the height of the scrolling block
+            if (verticalScroller &amp;&amp; verticalScroller.el) {
+                scrollHeight = verticalScroller.getSizeCalculation().height;
+            } else {
+                tableEl = view.el.child('table', true);
+                scrollHeight = tableEl ? tableEl.offsetHeight : 0;
+            }
+
+            // View is too high.
+            // Definitely need a vertical scrollbar
+            if (scrollHeight &gt; clientHeight) {
+                reqScrollbars = 1;
+
+                // But if scrollable block width goes into the zone required by the vertical scrollbar, we'll also need a horizontal
+                if (horizontalScroller &amp;&amp; ((clientWidth - scrollWidth) &lt; verticalScroller.width)) {
+                    reqScrollbars = 3;
+                }
+            }
+
+            // View height fits. But we stil may need a horizontal scrollbar, and this might necessitate a vertical one.
+            else {
+                // View is too wide.
+                // Definitely need a horizontal scrollbar
+                if (scrollWidth &gt; clientWidth) {
+                    reqScrollbars = 2;
+
+                    // But if scrollable block height goes into the zone required by the horizontal scrollbar, we'll also need a vertical
+                    if (verticalScroller &amp;&amp; ((clientHeight - scrollHeight) &lt; horizontalScroller.height)) {
+                        reqScrollbars = 3;
                     }
+                }
+            }
+
+            // If scrollbar requirements have changed, change 'em...
+            if (reqScrollbars !== curScrollbars) {
+
+                // Suspend component layout while we add/remove the docked scrollers
+                me.suspendLayout = true;
+                if (reqScrollbars &amp; 1) {
+                    me.showVerticalScroller();
+                } else {
+                    me.hideVerticalScroller();
+                }
+                if (reqScrollbars &amp; 2) {
+                    me.showHorizontalScroller();
                 } else {
-                    colIdx++;
+                    me.hideHorizontalScroller();
                 }
+                me.suspendLayout = false;
+
+                // Lay out the Component.
+                me.doComponentLayout();
+                // Lay out me.items
+                me.getLayout().layout();
             }
+        }
+        delete me.determineScrollbarsRunning;
+    },
 
-            // Add the cell info to the list
-            cells.push({
-                rowIdx: rowIdx,
-                cellIdx: cellIdx
-            });
+    onViewResize: function() {
+        this.determineScrollbars();
+    },
+
+    afterComponentLayout: function() {
+        this.callParent(arguments);
+        this.determineScrollbars();
+        this.invalidateScroller();
+    },
+
+    onHeaderResize: function() {
+        if (!this.componentLayout.layoutBusy &amp;&amp; this.view &amp;&amp; this.view.rendered) {
+            this.determineScrollbars();
+            this.invalidateScroller();
+        }
+    },
+
+    afterCollapse: function() {
+        var me = this;
+        if (me.verticalScroller) {
+            me.verticalScroller.saveScrollPos();
+        }
+        if (me.horizontalScroller) {
+            me.horizontalScroller.saveScrollPos();
+        }
+        me.callParent(arguments);
+    },
+
+    afterExpand: function() {
+        var me = this;
+        me.callParent(arguments);
+        if (me.verticalScroller) {
+            me.verticalScroller.restoreScrollPos();
+        }
+        if (me.horizontalScroller) {
+            me.horizontalScroller.restoreScrollPos();
+        }
+    },
+
+<span id='Ext-panel-Table-method-hideHorizontalScroller'>    /**
+</span>     * Hides the verticalScroller and removes the horizontalScrollerPresentCls.
+     */
+    hideHorizontalScroller: function() {
+        var me = this;
+
+        if (me.horizontalScroller &amp;&amp; me.horizontalScroller.ownerCt === me) {
+            me.verticalScroller.setReservedSpace(0);
+            me.removeDocked(me.horizontalScroller, false);
+            me.removeCls(me.horizontalScrollerPresentCls);
+            me.fireEvent('scrollerhide', me.horizontalScroller, 'horizontal');
+        }
 
-            // Increment
-            for (j = item.colspan || 1; j; --j) {
-                rowspans[colIdx] = item.rowspan || 1;
-                ++colIdx;
+    },
+
+<span id='Ext-panel-Table-method-showHorizontalScroller'>    /**
+</span>     * Shows the horizontalScroller and add the horizontalScrollerPresentCls.
+     */
+    showHorizontalScroller: function() {
+        var me = this;
+
+        if (me.verticalScroller) {
+            me.verticalScroller.setReservedSpace(Ext.getScrollbarSize().height - 1);
+        }
+        if (me.horizontalScroller &amp;&amp; me.horizontalScroller.ownerCt !== me) {
+            me.addDocked(me.horizontalScroller);
+            me.addCls(me.horizontalScrollerPresentCls);
+            me.fireEvent('scrollershow', me.horizontalScroller, 'horizontal');
+        }
+    },
+
+<span id='Ext-panel-Table-method-hideVerticalScroller'>    /**
+</span>     * Hides the verticalScroller and removes the verticalScrollerPresentCls.
+     */
+    hideVerticalScroller: function() {
+        var me = this;
+
+        me.setHeaderReserveOffset(false);
+        if (me.verticalScroller &amp;&amp; me.verticalScroller.ownerCt === me) {
+            me.removeDocked(me.verticalScroller, false);
+            me.removeCls(me.verticalScrollerPresentCls);
+            me.fireEvent('scrollerhide', me.verticalScroller, 'vertical');
+        }
+    },
+
+<span id='Ext-panel-Table-method-showVerticalScroller'>    /**
+</span>     * Shows the verticalScroller and adds the verticalScrollerPresentCls.
+     */
+    showVerticalScroller: function() {
+        var me = this;
+
+        me.setHeaderReserveOffset(true);
+        if (me.verticalScroller &amp;&amp; me.verticalScroller.ownerCt !== me) {
+            me.addDocked(me.verticalScroller);
+            me.addCls(me.verticalScrollerPresentCls);
+            me.fireEvent('scrollershow', me.verticalScroller, 'vertical');
+        }
+    },
+
+    setHeaderReserveOffset: function (reserveOffset) {
+        var headerCt = this.headerCt,
+            layout = headerCt.layout;
+
+        // only trigger a layout when reserveOffset is changing
+        if (layout &amp;&amp; layout.reserveOffset !== reserveOffset) {
+            layout.reserveOffset = reserveOffset;
+            if (!this.suspendLayout) {
+                headerCt.doLayout();
+            }
+        }
+    },
+
+<span id='Ext-panel-Table-method-invalidateScroller'>    /**
+</span>     * Invalides scrollers that are present and forces a recalculation. (Not related to showing/hiding the scrollers)
+     */
+    invalidateScroller: function() {
+        var me = this,
+            vScroll = me.verticalScroller,
+            hScroll = me.horizontalScroller;
+
+        if (vScroll) {
+            vScroll.invalidate();
+        }
+        if (hScroll) {
+            hScroll.invalidate();
+        }
+    },
+
+    // refresh the view when a header moves
+    onHeaderMove: function(headerCt, header, fromIdx, toIdx) {
+        this.view.refresh();
+    },
+
+    // Section onHeaderHide is invoked after view.
+    onHeaderHide: function(headerCt, header) {
+        this.invalidateScroller();
+    },
+
+    onHeaderShow: function(headerCt, header) {
+        this.invalidateScroller();
+    },
+
+    getVerticalScroller: function() {
+        return this.getScrollerOwner().down('gridscroller[dock=' + this.verticalScrollDock + ']');
+    },
+
+    getHorizontalScroller: function() {
+        return this.getScrollerOwner().down('gridscroller[dock=bottom]');
+    },
+
+    onMouseWheel: function(e) {
+        var me = this,
+            vertScroller = me.getVerticalScroller(),
+            horizScroller = me.getHorizontalScroller(),
+            scrollDelta = -me.scrollDelta,
+            deltas = e.getWheelDeltas(),
+            deltaX = scrollDelta * deltas.x,
+            deltaY = scrollDelta * deltas.y,
+            vertScrollerEl, horizScrollerEl,
+            vertScrollerElDom, horizScrollerElDom,
+            horizontalCanScrollLeft, horizontalCanScrollRight,
+            verticalCanScrollDown, verticalCanScrollUp;
+
+        // calculate whether or not both scrollbars can scroll right/left and up/down
+        if (horizScroller) {
+            horizScrollerEl = horizScroller.scrollEl;
+            if (horizScrollerEl) {
+                horizScrollerElDom = horizScrollerEl.dom;
+                horizontalCanScrollRight = horizScrollerElDom.scrollLeft !== horizScrollerElDom.scrollWidth - horizScrollerElDom.clientWidth;
+                horizontalCanScrollLeft  = horizScrollerElDom.scrollLeft !== 0;
+            }
+        }
+        if (vertScroller) {
+            vertScrollerEl = vertScroller.scrollEl;
+            if (vertScrollerEl) {
+                vertScrollerElDom = vertScrollerEl.dom;
+                verticalCanScrollDown = vertScrollerElDom.scrollTop !== vertScrollerElDom.scrollHeight - vertScrollerElDom.clientHeight;
+                verticalCanScrollUp   = vertScrollerElDom.scrollTop !== 0;
             }
-            ++cellIdx;
         }
 
-        return cells;
+        if (horizScroller) {
+            if ((deltaX &lt; 0 &amp;&amp; horizontalCanScrollLeft) || (deltaX &gt; 0 &amp;&amp; horizontalCanScrollRight)) {
+                e.stopEvent();
+                horizScroller.scrollByDeltaX(deltaX);
+            }
+        }
+        if (vertScroller) {
+            if ((deltaY &lt; 0 &amp;&amp; verticalCanScrollUp) || (deltaY &gt; 0 &amp;&amp; verticalCanScrollDown)) {
+                e.stopEvent();
+                vertScroller.scrollByDeltaY(deltaY);
+            }
+        }
     },
 
-<span id='Ext-layout-container-Table-method-getTable'>    /**
+<span id='Ext-panel-Table-method-onViewReady'>    /**
 </span>     * @private
-     * Return the layout's table element, creating it if necessary.
-     */
-    getTable: function() {
-        var table = this.table;
-        if (!table) {
-            table = this.table = this.getTarget().createChild(
-                Ext.apply({
-                    tag: 'table',
-                    role: 'presentation',
-                    cls: this.tableCls,
-                    cellspacing: 0, //TODO should this be specified or should CSS handle it?
-                    cn: {tag: 'tbody'}
-                }, this.tableAttrs),
-                null, true
-            );
-        }
-        return table;
-    },
-
-<span id='Ext-layout-container-Table-method-needsDivWrap'>    /**
+     * Fires the TablePanel's viewready event when the view declares that its internal DOM is ready
+     */
+    onViewReady: function() {
+        var me = this;
+        me.fireEvent('viewready', me);
+        if (me.deferRowRender) {
+            me.determineScrollbars();
+            me.invalidateScroller();
+        }
+    },
+
+<span id='Ext-panel-Table-method-onViewRefresh'>    /**
 </span>     * @private
-     * Opera 10.5 has a bug where if a table cell's child has box-sizing:border-box and padding, it
-     * will include that padding in the size of the cell, making it always larger than the
-     * shrink-wrapped size of its contents. To get around this we have to wrap the contents in a div
-     * and then set that div's width to match the item rendered within it afterLayout. This method
-     * determines whether we need the wrapper div; it currently does a straight UA sniff as this bug
-     * seems isolated to just Opera 10.5, but feature detection could be added here if needed.
-     */
-    needsDivWrap: function() {
-        return Ext.isOpera10_5;
+     * Determines and invalidates scrollers on view refresh
+     */
+    onViewRefresh: function() {
+        var me = this;
+
+        // Refresh *during* render must be ignored.
+        if (!me.rendering) {
+            this.determineScrollbars();
+            if (this.invalidateScrollerOnRefresh) {
+                this.invalidateScroller();
+            }
+        }
+    },
+
+<span id='Ext-panel-Table-method-setScrollTop'>    /**
+</span>     * Sets the scrollTop of the TablePanel.
+     * @param {Number} top
+     */
+    setScrollTop: function(top) {
+        var me               = this,
+            rootCmp          = me.getScrollerOwner(),
+            verticalScroller = me.getVerticalScroller();
+
+        rootCmp.virtualScrollTop = top;
+        if (verticalScroller) {
+            verticalScroller.setScrollTop(top);
+        }
+    },
+
+    getScrollerOwner: function() {
+        var rootCmp = this;
+        if (!this.scrollerOwner) {
+            rootCmp = this.up('[scrollerOwner]');
+        }
+        return rootCmp;
+    },
+
+<span id='Ext-panel-Table-method-scrollByDeltaY'>    /**
+</span>     * Scrolls the TablePanel by deltaY
+     * @param {Number} deltaY
+     */
+    scrollByDeltaY: function(deltaY) {
+        var verticalScroller = this.getVerticalScroller();
+
+        if (verticalScroller) {
+            verticalScroller.scrollByDeltaY(deltaY);
+        }
+    },
+
+<span id='Ext-panel-Table-method-scrollByDeltaX'>    /**
+</span>     * Scrolls the TablePanel by deltaX
+     * @param {Number} deltaX
+     */
+    scrollByDeltaX: function(deltaX) {
+        var horizontalScroller = this.getHorizontalScroller();
+
+        if (horizontalScroller) {
+            horizontalScroller.scrollByDeltaX(deltaX);
+        }
+    },
+
+<span id='Ext-panel-Table-method-getLhsMarker'>    /**
+</span>     * Gets left hand side marker for header resizing.
+     * @private
+     */
+    getLhsMarker: function() {
+        var me = this;
+
+        if (!me.lhsMarker) {
+            me.lhsMarker = Ext.DomHelper.append(me.el, {
+                cls: Ext.baseCSSPrefix + 'grid-resize-marker'
+            }, true);
+        }
+        return me.lhsMarker;
+    },
+
+<span id='Ext-panel-Table-method-getRhsMarker'>    /**
+</span>     * Gets right hand side marker for header resizing.
+     * @private
+     */
+    getRhsMarker: function() {
+        var me = this;
+
+        if (!me.rhsMarker) {
+            me.rhsMarker = Ext.DomHelper.append(me.el, {
+                cls: Ext.baseCSSPrefix + 'grid-resize-marker'
+            }, true);
+        }
+        return me.rhsMarker;
+    },
+
+<span id='Ext-panel-Table-method-getSelectionModel'>    /**
+</span>     * Returns the selection model being used and creates it via the configuration if it has not been created already.
+     * @return {Ext.selection.Model} selModel
+     */
+    getSelectionModel: function(){
+        if (!this.selModel) {
+            this.selModel = {};
+        }
+
+        var mode = 'SINGLE',
+            type;
+        if (this.simpleSelect) {
+            mode = 'SIMPLE';
+        } else if (this.multiSelect) {
+            mode = 'MULTI';
+        }
+
+        Ext.applyIf(this.selModel, {
+            allowDeselect: this.allowDeselect,
+            mode: mode
+        });
+
+        if (!this.selModel.events) {
+            type = this.selModel.selType || this.selType;
+            this.selModel = Ext.create('selection.' + type, this.selModel);
+        }
+
+        if (!this.selModel.hasRelaySetup) {
+            this.relayEvents(this.selModel, [
+                'selectionchange', 'beforeselect', 'beforedeselect', 'select', 'deselect'
+            ]);
+            this.selModel.hasRelaySetup = true;
+        }
+
+        // lock the selection model if user
+        // has disabled selection
+        if (this.disableSelection) {
+            this.selModel.locked = true;
+        }
+        return this.selModel;
+    },
+
+    onVerticalScroll: function(event, target) {
+        var owner = this.getScrollerOwner(),
+            items = owner.query('tableview'),
+            i = 0,
+            len = items.length;
+
+        for (; i &lt; len; i++) {
+            items[i].el.dom.scrollTop = target.scrollTop;
+        }
+    },
+
+    onHorizontalScroll: function(event, target) {
+        var owner = this.getScrollerOwner(),
+            items = owner.query('tableview'),
+            center = items[1] || items[0];
+
+        center.el.dom.scrollLeft = target.scrollLeft;
+        this.headerCt.el.dom.scrollLeft = target.scrollLeft;
+    },
+
+    // template method meant to be overriden
+    onStoreLoad: Ext.emptyFn,
+
+    getEditorParent: function() {
+        return this.body;
+    },
+
+    bindStore: function(store) {
+        var me = this;
+        me.store = store;
+        me.getView().bindStore(store);
+    },
+    
+    beforeDestroy: function(){
+        // may be some duplication here since the horizontal and vertical
+        // scroller may be part of the docked items, but we need to clean
+        // them up in case they aren't visible.
+        Ext.destroy(this.horizontalScroller, this.verticalScroller);
+        this.callParent();
+    },
+
+<span id='Ext-panel-Table-method-reconfigure'>    /**
+</span>     * Reconfigures the table with a new store/columns. Either the store or the columns can be ommitted if you don't wish
+     * to change them.
+     * @param {Ext.data.Store} store (Optional) The new store.
+     * @param {Object[]} columns (Optional) An array of column configs
+     */
+    reconfigure: function(store, columns) {
+        var me = this,
+            headerCt = me.headerCt;
+
+        if (me.lockable) {
+            me.reconfigureLockable(store, columns);
+        } else {
+            if (columns) {
+                headerCt.suspendLayout = true;
+                headerCt.removeAll();
+                headerCt.add(columns);
+            }
+            if (store) {
+                store = Ext.StoreManager.lookup(store);
+                me.bindStore(store);
+            } else {
+                me.getView().refresh();
+            }
+            if (columns) {
+                headerCt.suspendLayout = false;
+                me.forceComponentLayout();
+            }
+        }
+        me.fireEvent('reconfigure', me);
     }
 });</pre>
 </body>