Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / docs / source / Table2.html
1 <!DOCTYPE html><html><head><title>Sencha Documentation Project</title><link rel="stylesheet" href="../reset.css" type="text/css"><link rel="stylesheet" href="../prettify.css" type="text/css"><link rel="stylesheet" href="../prettify_sa.css" type="text/css"><script type="text/javascript" src="../prettify.js"></script></head><body onload="prettyPrint()"><pre class="prettyprint"><pre><span id='Ext-panel.Table'>/**
2 </span> * @class Ext.panel.Table
3  * @extends Ext.panel.Panel
4  * @xtype tablepanel
5  * @private
6  * @author Nicolas Ferrero
7  * TablePanel is a private class and the basis of both TreePanel and GridPanel.
8  *
9  * TablePanel aggregates:
10  *
11  *  - a Selection Model
12  *  - a View
13  *  - a Store
14  *  - Scrollers
15  *  - Ext.grid.header.Container
16  *
17  */
18 Ext.define('Ext.panel.Table', {
19     extend: 'Ext.panel.Panel',
20
21     alias: 'widget.tablepanel',
22
23     uses: [
24         'Ext.selection.RowModel',
25         'Ext.grid.Scroller',
26         'Ext.grid.header.Container',
27         'Ext.grid.Lockable'
28     ],
29
30     cls: Ext.baseCSSPrefix + 'grid',
31     extraBodyCls: Ext.baseCSSPrefix + 'grid-body',
32
33     layout: 'fit',
34 <span id='Ext-panel.Table-property-hasView'>    /**
35 </span>     * Boolean to indicate that a view has been injected into the panel.
36      * @property hasView
37      */
38     hasView: false,
39
40     // each panel should dictate what viewType and selType to use
41     viewType: null,
42     selType: 'rowmodel',
43
44 <span id='Ext-panel.Table-cfg-scrollDelta'>    /**
45 </span>     * @cfg {Number} scrollDelta
46      * Number of pixels to scroll when scrolling with mousewheel.
47      * Defaults to 40.
48      */
49     scrollDelta: 40,
50
51 <span id='Ext-panel.Table-cfg-scroll'>    /**
52 </span>     * @cfg {String/Boolean} scroll
53      * Valid values are 'both', 'horizontal' or 'vertical'. true implies 'both'. false implies 'none'.
54      * Defaults to true.
55      */
56     scroll: true,
57
58 <span id='Ext-panel.Table-cfg-columns'>    /**
59 </span>     * @cfg {Array} columns
60      * An array of {@link Ext.grid.column.Column column} definition objects which define all columns that appear in this grid. Each
61      * column definition provides the header text for the column, and a definition of where the data for that column comes from.
62      */
63
64 <span id='Ext-panel.Table-cfg-forceFit'>    /**
65 </span>     * @cfg {Boolean} forceFit
66      * Specify as &lt;code&gt;true&lt;/code&gt; to force the columns to fit into the available width. Headers are first sized according to configuration, whether that be
67      * a specific width, or flex. Then they are all proportionally changed in width so that the entire content width is used..
68      */
69
70 <span id='Ext-panel.Table-cfg-hideHeaders'>    /**
71 </span>     * @cfg {Boolean} hideHeaders
72      * Specify as &lt;code&gt;true&lt;/code&gt; to hide the headers.
73      */
74
75 <span id='Ext-panel.Table-cfg-sortableColumns'>    /**
76 </span>     * @cfg {Boolean} sortableColumns
77      * Defaults to true. Set to false to disable column sorting via clicking the
78      * header and via the Sorting menu items.
79      */
80     sortableColumns: true,
81
82     verticalScrollDock: 'right',
83     verticalScrollerType: 'gridscroller',
84
85     horizontalScrollerPresentCls: Ext.baseCSSPrefix + 'horizontal-scroller-present',
86     verticalScrollerPresentCls: Ext.baseCSSPrefix + 'vertical-scroller-present',
87
88     // private property used to determine where to go down to find views
89     // this is here to support locking.
90     scrollerOwner: true,
91
92     invalidateScrollerOnRefresh: true,
93     
94     enableColumnMove: true,
95     enableColumnResize: true,
96
97
98     initComponent: function() {
99         //&lt;debug&gt;
100         if (!this.viewType) {
101             Ext.Error.raise(&quot;You must specify a viewType config.&quot;);
102         }
103         if (!this.store) {
104             Ext.Error.raise(&quot;You must specify a store config&quot;);
105         }
106         if (this.headers) {
107             Ext.Error.raise(&quot;The headers config is not supported. Please specify columns instead.&quot;);
108         }
109         //&lt;/debug&gt;
110
111         var me          = this,
112             scroll      = me.scroll,
113             vertical    = false,
114             horizontal  = false,
115             headerCtCfg = me.columns || me.colModel,
116             i           = 0,
117             view,
118             border = me.border;
119
120         // Set our determinScrollbars method to reference a buffered call to determinScrollbars which fires on a 30ms buffer.
121         me.determineScrollbars = Ext.Function.createBuffered(me.determineScrollbars, 30);
122         me.injectView = Ext.Function.createBuffered(me.injectView, 30);
123
124         if (me.hideHeaders) {
125             border = false;
126         }
127
128         // The columns/colModel config may be either a fully instantiated HeaderContainer, or an array of Column definitions, or a config object of a HeaderContainer
129         // Either way, we extract a columns property referencing an array of Column definitions.
130         if (headerCtCfg instanceof Ext.grid.header.Container) {
131             me.headerCt = headerCtCfg;
132             me.headerCt.border = border;
133             me.columns = me.headerCt.items.items;
134         } else {
135             if (Ext.isArray(headerCtCfg)) {
136                 headerCtCfg = {
137                     items: headerCtCfg,
138                     border: border
139                 };
140             }
141             Ext.apply(headerCtCfg, {
142                 forceFit: me.forceFit,
143                 sortable: me.sortableColumns,
144                 enableColumnMove: me.enableColumnMove,
145                 enableColumnResize: me.enableColumnResize,
146                 border:  border
147             });
148             me.columns = headerCtCfg.items;
149
150              // If any of the Column objects contain a locked property, and are not processed, this is a lockable TablePanel, a
151              // special view will be injected by the Ext.grid.Lockable mixin, so no processing of .
152              if (Ext.ComponentQuery.query('{locked !== undefined}{processed != true}', me.columns).length) {
153                  me.self.mixin('lockable', Ext.grid.Lockable);
154                  me.injectLockable();
155              }
156         }
157
158         me.store = Ext.data.StoreManager.lookup(me.store);
159         me.addEvents(
160 <span id='Ext-panel.Table-event-scrollerhide'>            /**
161 </span>             * @event scrollerhide
162              * Fires when a scroller is hidden
163              * @param {Ext.grid.Scroller} scroller
164              * @param {String} orientation Orientation, can be 'vertical' or 'horizontal'
165              */
166             'scrollerhide',
167 <span id='Ext-panel.Table-event-scrollershow'>            /**
168 </span>             * @event scrollershow
169              * Fires when a scroller is shown
170              * @param {Ext.grid.Scroller} scroller
171              * @param {String} orientation Orientation, can be 'vertical' or 'horizontal'
172              */
173             'scrollershow'
174         );
175
176         me.bodyCls = me.bodyCls || '';
177         me.bodyCls += (' ' + me.extraBodyCls);
178
179         // autoScroll is not a valid configuration
180         delete me.autoScroll;
181
182         // If this TablePanel is lockable (Either configured lockable, or any of the defined columns has a 'locked' property)
183         // 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.
184         if (!me.hasView) {
185
186             // If we were not configured with a ready-made headerCt (either by direct config with a headerCt property, or by passing
187             // a HeaderContainer instance as the 'columns' property, then go ahead and create one from the config object created above.
188             if (!me.headerCt) {
189                 me.headerCt = Ext.create('Ext.grid.header.Container', headerCtCfg);
190             }
191
192             // Extract the array of Column objects
193             me.columns = me.headerCt.items.items;
194
195             if (me.hideHeaders) {
196                 me.headerCt.height = 0;
197                 me.headerCt.border = false;
198                 me.headerCt.addCls(Ext.baseCSSPrefix + 'grid-header-ct-hidden');
199                 me.addCls(Ext.baseCSSPrefix + 'grid-header-hidden');
200                 // IE Quirks Mode fix
201                 // If hidden configuration option was used, several layout calculations will be bypassed.
202                 if (Ext.isIEQuirks) {
203                     me.headerCt.style = {
204                         display: 'none'
205                     };
206                 }
207             }
208
209             // turn both on.
210             if (scroll === true || scroll === 'both') {
211                 vertical = horizontal = true;
212             } else if (scroll === 'horizontal') {
213                 horizontal = true;
214             } else if (scroll === 'vertical') {
215                 vertical = true;
216             // All other values become 'none' or false.
217             } else {
218                 me.headerCt.availableSpaceOffset = 0;
219             }
220
221             if (vertical) {
222                 me.verticalScroller = me.verticalScroller || {};
223                 Ext.applyIf(me.verticalScroller, {
224                     dock: me.verticalScrollDock,
225                     xtype: me.verticalScrollerType,
226                     store: me.store
227                 });
228                 me.verticalScroller = Ext.ComponentManager.create(me.verticalScroller);
229                 me.mon(me.verticalScroller, {
230                     bodyscroll: me.onVerticalScroll,
231                     scope: me
232                 });
233             }
234
235             if (horizontal) {
236                 me.horizontalScroller = Ext.ComponentManager.create({
237                     xtype: 'gridscroller',
238                     section: me,
239                     dock: 'bottom',
240                     store: me.store
241                 });
242                 me.mon(me.horizontalScroller, {
243                     bodyscroll: me.onHorizontalScroll,
244                     scope: me
245                 });
246             }
247
248             me.headerCt.on('columnresize', me.onHeaderResize, me);
249             me.relayEvents(me.headerCt, ['columnresize', 'columnmove', 'columnhide', 'columnshow', 'sortchange']);
250             me.features = me.features || [];
251             me.dockedItems = me.dockedItems || [];
252             me.dockedItems.unshift(me.headerCt);
253             me.viewConfig = me.viewConfig || {};
254             me.viewConfig.invalidateScrollerOnRefresh = me.invalidateScrollerOnRefresh;
255
256             // AbstractDataView will look up a Store configured as an object
257             // getView converts viewConfig into a View instance
258             view = me.getView();
259
260             if (view) {
261                 me.mon(view.store, {
262                     load: me.onStoreLoad,
263                     scope: me
264                 });
265                 me.mon(view, {
266                     refresh: {
267                         fn: this.onViewRefresh,
268                         scope: me,
269                         buffer: 50
270                     },
271                     itemupdate: me.onViewItemUpdate,
272                     scope: me
273                 });
274                 this.relayEvents(view, [
275 <span id='Ext-panel.Table-event-beforeitemmousedown'>                    /**
276 </span>                     * @event beforeitemmousedown
277                      * Fires before the mousedown event on an item is processed. Returns false to cancel the default action.
278                      * @param {Ext.view.View} this
279                      * @param {Ext.data.Model} record The record that belongs to the item
280                      * @param {HTMLElement} item The item's element
281                      * @param {Number} index The item's index
282                      * @param {Ext.EventObject} e The raw event object
283                      */
284                     'beforeitemmousedown',
285 <span id='Ext-panel.Table-event-beforeitemmouseup'>                    /**
286 </span>                     * @event beforeitemmouseup
287                      * Fires before the mouseup event on an item is processed. Returns false to cancel the default action.
288                      * @param {Ext.view.View} this
289                      * @param {Ext.data.Model} record The record that belongs to the item
290                      * @param {HTMLElement} item The item's element
291                      * @param {Number} index The item's index
292                      * @param {Ext.EventObject} e The raw event object
293                      */
294                     'beforeitemmouseup',
295 <span id='Ext-panel.Table-event-beforeitemmouseenter'>                    /**
296 </span>                     * @event beforeitemmouseenter
297                      * Fires before the mouseenter event on an item is processed. Returns false to cancel the default action.
298                      * @param {Ext.view.View} this
299                      * @param {Ext.data.Model} record The record that belongs to the item
300                      * @param {HTMLElement} item The item's element
301                      * @param {Number} index The item's index
302                      * @param {Ext.EventObject} e The raw event object
303                      */
304                     'beforeitemmouseenter',
305 <span id='Ext-panel.Table-event-beforeitemmouseleave'>                    /**
306 </span>                     * @event beforeitemmouseleave
307                      * Fires before the mouseleave event on an item is processed. Returns false to cancel the default action.
308                      * @param {Ext.view.View} this
309                      * @param {Ext.data.Model} record The record that belongs to the item
310                      * @param {HTMLElement} item The item's element
311                      * @param {Number} index The item's index
312                      * @param {Ext.EventObject} e The raw event object
313                      */
314                     'beforeitemmouseleave',
315 <span id='Ext-panel.Table-event-beforeitemclick'>                    /**
316 </span>                     * @event beforeitemclick
317                      * Fires before the click event on an item is processed. Returns false to cancel the default action.
318                      * @param {Ext.view.View} this
319                      * @param {Ext.data.Model} record The record that belongs to the item
320                      * @param {HTMLElement} item The item's element
321                      * @param {Number} index The item's index
322                      * @param {Ext.EventObject} e The raw event object
323                      */
324                     'beforeitemclick',
325 <span id='Ext-panel.Table-event-beforeitemdblclick'>                    /**
326 </span>                     * @event beforeitemdblclick
327                      * Fires before the dblclick event on an item is processed. Returns false to cancel the default action.
328                      * @param {Ext.view.View} this
329                      * @param {Ext.data.Model} record The record that belongs to the item
330                      * @param {HTMLElement} item The item's element
331                      * @param {Number} index The item's index
332                      * @param {Ext.EventObject} e The raw event object
333                      */
334                     'beforeitemdblclick',
335 <span id='Ext-panel.Table-event-beforeitemcontextmenu'>                    /**
336 </span>                     * @event beforeitemcontextmenu
337                      * Fires before the contextmenu event on an item is processed. Returns false to cancel the default action.
338                      * @param {Ext.view.View} this
339                      * @param {Ext.data.Model} record The record that belongs to the item
340                      * @param {HTMLElement} item The item's element
341                      * @param {Number} index The item's index
342                      * @param {Ext.EventObject} e The raw event object
343                      */
344                     'beforeitemcontextmenu',
345 <span id='Ext-panel.Table-event-itemmousedown'>                    /**
346 </span>                     * @event itemmousedown
347                      * Fires when there is a mouse down on an item
348                      * @param {Ext.view.View} this
349                      * @param {Ext.data.Model} record The record that belongs to the item
350                      * @param {HTMLElement} item The item's element
351                      * @param {Number} index The item's index
352                      * @param {Ext.EventObject} e The raw event object
353                      */
354                     'itemmousedown',
355 <span id='Ext-panel.Table-event-itemmouseup'>                    /**
356 </span>                     * @event itemmouseup
357                      * Fires when there is a mouse up on an item
358                      * @param {Ext.view.View} this
359                      * @param {Ext.data.Model} record The record that belongs to the item
360                      * @param {HTMLElement} item The item's element
361                      * @param {Number} index The item's index
362                      * @param {Ext.EventObject} e The raw event object
363                      */
364                     'itemmouseup',
365 <span id='Ext-panel.Table-event-itemmouseenter'>                    /**
366 </span>                     * @event itemmouseenter
367                      * Fires when the mouse enters an item.
368                      * @param {Ext.view.View} this
369                      * @param {Ext.data.Model} record The record that belongs to the item
370                      * @param {HTMLElement} item The item's element
371                      * @param {Number} index The item's index
372                      * @param {Ext.EventObject} e The raw event object
373                      */
374                     'itemmouseenter',
375 <span id='Ext-panel.Table-event-itemmouseleave'>                    /**
376 </span>                     * @event itemmouseleave
377                      * Fires when the mouse leaves an item.
378                      * @param {Ext.view.View} this
379                      * @param {Ext.data.Model} record The record that belongs to the item
380                      * @param {HTMLElement} item The item's element
381                      * @param {Number} index The item's index
382                      * @param {Ext.EventObject} e The raw event object
383                      */
384                     'itemmouseleave',
385 <span id='Ext-panel.Table-event-itemclick'>                    /**
386 </span>                     * @event itemclick
387                      * Fires when an item is clicked.
388                      * @param {Ext.view.View} this
389                      * @param {Ext.data.Model} record The record that belongs to the item
390                      * @param {HTMLElement} item The item's element
391                      * @param {Number} index The item's index
392                      * @param {Ext.EventObject} e The raw event object
393                      */
394                     'itemclick',
395 <span id='Ext-panel.Table-event-itemdblclick'>                    /**
396 </span>                     * @event itemdblclick
397                      * Fires when an item is double clicked.
398                      * @param {Ext.view.View} this
399                      * @param {Ext.data.Model} record The record that belongs to the item
400                      * @param {HTMLElement} item The item's element
401                      * @param {Number} index The item's index
402                      * @param {Ext.EventObject} e The raw event object
403                      */
404                     'itemdblclick',
405 <span id='Ext-panel.Table-event-itemcontextmenu'>                    /**
406 </span>                     * @event itemcontextmenu
407                      * Fires when an item is right clicked.
408                      * @param {Ext.view.View} this
409                      * @param {Ext.data.Model} record The record that belongs to the item
410                      * @param {HTMLElement} item The item's element
411                      * @param {Number} index The item's index
412                      * @param {Ext.EventObject} e The raw event object
413                      */
414                     'itemcontextmenu',
415 <span id='Ext-panel.Table-event-beforecontainermousedown'>                    /**
416 </span>                     * @event beforecontainermousedown
417                      * Fires before the mousedown event on the container is processed. Returns false to cancel the default action.
418                      * @param {Ext.view.View} this
419                      * @param {Ext.EventObject} e The raw event object
420                      */
421                     'beforecontainermousedown',
422 <span id='Ext-panel.Table-event-beforecontainermouseup'>                    /**
423 </span>                     * @event beforecontainermouseup
424                      * Fires before the mouseup event on the container is processed. Returns false to cancel the default action.
425                      * @param {Ext.view.View} this
426                      * @param {Ext.EventObject} e The raw event object
427                      */
428                     'beforecontainermouseup',
429 <span id='Ext-panel.Table-event-beforecontainermouseover'>                    /**
430 </span>                     * @event beforecontainermouseover
431                      * Fires before the mouseover event on the container is processed. Returns false to cancel the default action.
432                      * @param {Ext.view.View} this
433                      * @param {Ext.EventObject} e The raw event object
434                      */
435                     'beforecontainermouseover',
436 <span id='Ext-panel.Table-event-beforecontainermouseout'>                    /**
437 </span>                     * @event beforecontainermouseout
438                      * Fires before the mouseout event on the container is processed. Returns false to cancel the default action.
439                      * @param {Ext.view.View} this
440                      * @param {Ext.EventObject} e The raw event object
441                      */
442                     'beforecontainermouseout',
443 <span id='Ext-panel.Table-event-beforecontainerclick'>                    /**
444 </span>                     * @event beforecontainerclick
445                      * Fires before the click event on the container is processed. Returns false to cancel the default action.
446                      * @param {Ext.view.View} this
447                      * @param {Ext.EventObject} e The raw event object
448                      */
449                     'beforecontainerclick',
450 <span id='Ext-panel.Table-event-beforecontainerdblclick'>                    /**
451 </span>                     * @event beforecontainerdblclick
452                      * Fires before the dblclick event on the container is processed. Returns false to cancel the default action.
453                      * @param {Ext.view.View} this
454                      * @param {Ext.EventObject} e The raw event object
455                      */
456                     'beforecontainerdblclick',
457 <span id='Ext-panel.Table-event-beforecontainercontextmenu'>                    /**
458 </span>                     * @event beforecontainercontextmenu
459                      * Fires before the contextmenu event on the container is processed. Returns false to cancel the default action.
460                      * @param {Ext.view.View} this
461                      * @param {Ext.EventObject} e The raw event object
462                      */
463                     'beforecontainercontextmenu',
464 <span id='Ext-panel.Table-event-containermouseup'>                    /**
465 </span>                     * @event containermouseup
466                      * Fires when there is a mouse up on the container
467                      * @param {Ext.view.View} this
468                      * @param {Ext.EventObject} e The raw event object
469                      */
470                     'containermouseup',
471 <span id='Ext-panel.Table-event-containermouseover'>                    /**
472 </span>                     * @event containermouseover
473                      * Fires when you move the mouse over the container.
474                      * @param {Ext.view.View} this
475                      * @param {Ext.EventObject} e The raw event object
476                      */
477                     'containermouseover',
478 <span id='Ext-panel.Table-event-containermouseout'>                    /**
479 </span>                     * @event containermouseout
480                      * Fires when you move the mouse out of the container.
481                      * @param {Ext.view.View} this
482                      * @param {Ext.EventObject} e The raw event object
483                      */
484                     'containermouseout',
485 <span id='Ext-panel.Table-event-containerclick'>                    /**
486 </span>                     * @event containerclick
487                      * Fires when the container is clicked.
488                      * @param {Ext.view.View} this
489                      * @param {Ext.EventObject} e The raw event object
490                      */
491                     'containerclick',
492 <span id='Ext-panel.Table-event-containerdblclick'>                    /**
493 </span>                     * @event containerdblclick
494                      * Fires when the container is double clicked.
495                      * @param {Ext.view.View} this
496                      * @param {Ext.EventObject} e The raw event object
497                      */
498                     'containerdblclick',
499 <span id='Ext-panel.Table-event-containercontextmenu'>                    /**
500 </span>                     * @event containercontextmenu
501                      * Fires when the container is right clicked.
502                      * @param {Ext.view.View} this
503                      * @param {Ext.EventObject} e The raw event object
504                      */
505                     'containercontextmenu',
506
507 <span id='Ext-panel.Table-event-selectionchange'>                    /**
508 </span>                     * @event selectionchange
509                      * Fires when the selected nodes change. Relayed event from the underlying selection model.
510                      * @param {Ext.view.View} this
511                      * @param {Array} selections Array of the selected nodes
512                      */
513                     'selectionchange',
514 <span id='Ext-panel.Table-event-beforeselect'>                    /**
515 </span>                     * @event beforeselect
516                      * Fires before a selection is made. If any handlers return false, the selection is cancelled.
517                      * @param {Ext.view.View} this
518                      * @param {HTMLElement} node The node to be selected
519                      * @param {Array} selections Array of currently selected nodes
520                      */
521                     'beforeselect'
522                 ]);
523             }
524         }
525         me.callParent(arguments);
526     },
527
528     // state management
529     initStateEvents: function(){
530         var events = this.stateEvents;
531         // push on stateEvents if they don't exist
532         Ext.each(['columnresize', 'columnmove', 'columnhide', 'columnshow', 'sortchange'], function(event){
533             if (Ext.Array.indexOf(events, event)) {
534                 events.push(event);
535             }
536         });
537         this.callParent();
538     },
539
540     getState: function(){
541         var state = {
542             columns: []
543         },
544         sorter = this.store.sorters.first();
545
546         this.headerCt.items.each(function(header){
547             state.columns.push({
548                 id: header.headerId,
549                 width: header.flex ? undefined : header.width,
550                 hidden: header.hidden,
551                 sortable: header.sortable
552             });
553         });
554
555         if (sorter) {
556             state.sort = {
557                 property: sorter.property,
558                 direction: sorter.direction
559             };
560         }
561         return state;
562     },
563
564     applyState: function(state) {
565         var headers = state.columns,
566             length = headers ? headers.length : 0,
567             headerCt = this.headerCt,
568             items = headerCt.items,
569             sorter = state.sort,
570             store = this.store,
571             i = 0,
572             index,
573             headerState,
574             header;
575
576         for (; i &lt; length; ++i) {
577             headerState = headers[i];
578             header = headerCt.down('gridcolumn[headerId=' + headerState.id + ']');
579             index = items.indexOf(header);
580             if (i !== index) {
581                 headerCt.moveHeader(index, i);
582             }
583             header.sortable = headerState.sortable;
584             if (Ext.isDefined(headerState.width)) {
585                 delete header.flex;
586                 if (header.rendered) {
587                     header.setWidth(headerState.width);
588                 } else {
589                     header.minWidth = header.width = headerState.width;
590                 }
591             }
592             header.hidden = headerState.hidden;
593         }
594
595         if (sorter) {
596             if (store.remoteSort) {
597                 store.sorters.add(Ext.create('Ext.util.Sorter', {
598                     property: sorter.property,
599                     direction: sorter.direction
600                 }));
601             }
602             else {
603                 store.sort(sorter.property, sorter.direction);
604             }
605         }
606     },
607
608 <span id='Ext-panel.Table-method-getStore'>    /**
609 </span>     * Returns the store associated with this Panel.
610      * @return {Ext.data.Store} The store
611      */
612     getStore: function(){
613         return this.store;
614     },
615
616 <span id='Ext-panel.Table-method-getView'>    /**
617 </span>     * Gets the view for this panel.
618      * @return {Ext.view.Table}
619      */
620     getView: function() {
621         var me = this,
622             sm;
623
624         if (!me.view) {
625             sm = me.getSelectionModel();
626             me.view = me.createComponent(Ext.apply({}, me.viewConfig, {
627                 xtype: me.viewType,
628                 store: me.store,
629                 headerCt: me.headerCt,
630                 selModel: sm,
631                 features: me.features,
632                 panel: me
633             }));
634             me.mon(me.view, {
635                 uievent: me.processEvent,
636                 scope: me
637             });
638             sm.view = me.view;
639             me.headerCt.view = me.view;
640             me.relayEvents(me.view, ['cellclick', 'celldblclick']);
641         }
642         return me.view;
643     },
644
645 <span id='Ext-panel.Table-property-setAutoScroll'>    /**
646 </span>     * @private
647      * @override
648      * autoScroll is never valid for all classes which extend TablePanel.
649      */
650     setAutoScroll: Ext.emptyFn,
651
652     // This method hijacks Ext.view.Table's el scroll method.
653     // This enables us to keep the virtualized scrollbars in sync
654     // with the view. It currently does NOT support animation.
655     elScroll: function(direction, distance, animate) {
656         var me = this,
657             scroller;
658
659         if (direction === &quot;up&quot; || direction === &quot;left&quot;) {
660             distance = -distance;
661         }
662
663         if (direction === &quot;down&quot; || direction === &quot;up&quot;) {
664             scroller = me.getVerticalScroller();
665             scroller.scrollByDeltaY(distance);
666         } else {
667             scroller = me.getHorizontalScroller();
668             scroller.scrollByDeltaX(distance);
669         }
670     },
671     
672     afterLayout: function() {
673         this.callParent(arguments);
674         this.injectView();
675     },
676     
677
678 <span id='Ext-panel.Table-method-injectView'>    /**
679 </span>     * @private
680      * Called after this Component has achieved its correct initial size, after all layouts have done their thing.
681      * This is so we can add the View only after the initial size is known. This method is buffered 30ms.
682      */
683     injectView: function() {
684         if (!this.hasView &amp;&amp; !this.collapsed) {
685             var me   = this,
686                 view = me.getView();
687
688             me.hasView = true;
689             me.add(view);
690
691             // hijack the view el's scroll method
692             view.el.scroll = Ext.Function.bind(me.elScroll, me);
693             // We use to listen to document.body wheel events, but that's a
694             // little much. We scope just to the view now.
695             me.mon(view.el, {
696                 mousewheel: me.onMouseWheel,
697                 scope: me
698             });
699         }
700     },
701
702     afterExpand: function() {
703         this.callParent(arguments);
704         if (!this.hasView) {
705             this.injectView();
706         }
707     },
708
709 <span id='Ext-panel.Table-method-processEvent'>    /**
710 </span>     * @private
711      * Process UI events from the view. Propagate them to whatever internal Components need to process them
712      * @param {String} type Event type, eg 'click'
713      * @param {TableView} view TableView Component
714      * @param {HtmlElement} cell Cell HtmlElement the event took place within
715      * @param {Number} recordIndex Index of the associated Store Model (-1 if none)
716      * @param {Number} cellIndex Cell index within the row
717      * @param {EventObject} e Original event
718      */
719     processEvent: function(type, view, cell, recordIndex, cellIndex, e) {
720         var me = this,
721             header;
722
723         if (cellIndex !== -1) {
724             header = me.headerCt.getGridColumns()[cellIndex];
725             return header.processEvent.apply(header, arguments);
726         }
727     },
728
729 <span id='Ext-panel.Table-method-determineScrollbars'>    /**
730 </span>     * Request a recalculation of scrollbars and put them in if they are needed.
731      */
732     determineScrollbars: function() {
733         var me = this,
734             viewElDom,
735             centerScrollWidth,
736             centerClientWidth,
737             scrollHeight,
738             clientHeight;
739
740         if (!me.collapsed &amp;&amp; me.view &amp;&amp; me.view.el) {
741             viewElDom = me.view.el.dom;
742             //centerScrollWidth = viewElDom.scrollWidth;
743             centerScrollWidth = me.headerCt.getFullWidth();
744 <span id='Ext-panel.Table-property-centerClientWidth'>            /**
745 </span>             * clientWidth often returns 0 in IE resulting in an
746              * infinity result, here we use offsetWidth bc there are
747              * no possible scrollbars and we don't care about margins
748              */
749             centerClientWidth = viewElDom.offsetWidth;
750             if (me.verticalScroller &amp;&amp; me.verticalScroller.el) {
751                 scrollHeight = me.verticalScroller.getSizeCalculation().height;
752             } else {
753                 scrollHeight = viewElDom.scrollHeight;
754             }
755
756             clientHeight = viewElDom.clientHeight;
757
758             if (!me.collapsed &amp;&amp; scrollHeight &gt; clientHeight) {
759                 me.showVerticalScroller();
760             } else {
761                 me.hideVerticalScroller();
762             }
763
764             if (!me.collapsed &amp;&amp; centerScrollWidth &gt; (centerClientWidth + Ext.getScrollBarWidth() - 2)) {
765                 me.showHorizontalScroller();
766             } else {
767                 me.hideHorizontalScroller();
768             }
769         }
770     },
771
772     onHeaderResize: function() {
773         if (this.view &amp;&amp; this.view.rendered) {
774             this.determineScrollbars();
775             this.invalidateScroller();
776         }
777     },
778
779 <span id='Ext-panel.Table-method-hideHorizontalScroller'>    /**
780 </span>     * Hide the verticalScroller and remove the horizontalScrollerPresentCls.
781      */
782     hideHorizontalScroller: function() {
783         var me = this;
784
785         if (me.horizontalScroller &amp;&amp; me.horizontalScroller.ownerCt === me) {
786             me.verticalScroller.offsets.bottom = 0;
787             me.removeDocked(me.horizontalScroller, false);
788             me.removeCls(me.horizontalScrollerPresentCls);
789             me.fireEvent('scrollerhide', me.horizontalScroller, 'horizontal');
790         }
791
792     },
793
794 <span id='Ext-panel.Table-method-showHorizontalScroller'>    /**
795 </span>     * Show the horizontalScroller and add the horizontalScrollerPresentCls.
796      */
797     showHorizontalScroller: function() {
798         var me = this;
799
800         if (me.verticalScroller) {
801             me.verticalScroller.offsets.bottom = Ext.getScrollBarWidth() - 2;
802         }
803         if (me.horizontalScroller &amp;&amp; me.horizontalScroller.ownerCt !== me) {
804             me.addDocked(me.horizontalScroller);
805             me.addCls(me.horizontalScrollerPresentCls);
806             me.fireEvent('scrollershow', me.horizontalScroller, 'horizontal');
807         }
808     },
809
810 <span id='Ext-panel.Table-method-hideVerticalScroller'>    /**
811 </span>     * Hide the verticalScroller and remove the verticalScrollerPresentCls.
812      */
813     hideVerticalScroller: function() {
814         var me = this,
815             headerCt = me.headerCt;
816
817         // only trigger a layout when reserveOffset is changing
818         if (headerCt &amp;&amp; headerCt.layout.reserveOffset) {
819             headerCt.layout.reserveOffset = false;
820             headerCt.doLayout();
821         }
822         if (me.verticalScroller &amp;&amp; me.verticalScroller.ownerCt === me) {
823             me.removeDocked(me.verticalScroller, false);
824             me.removeCls(me.verticalScrollerPresentCls);
825             me.fireEvent('scrollerhide', me.verticalScroller, 'vertical');
826         }
827     },
828
829 <span id='Ext-panel.Table-method-showVerticalScroller'>    /**
830 </span>     * Show the verticalScroller and add the verticalScrollerPresentCls.
831      */
832     showVerticalScroller: function() {
833         var me = this,
834             headerCt = me.headerCt;
835
836         // only trigger a layout when reserveOffset is changing
837         if (headerCt &amp;&amp; !headerCt.layout.reserveOffset) {
838             headerCt.layout.reserveOffset = true;
839             headerCt.doLayout();
840         }
841         if (me.verticalScroller &amp;&amp; me.verticalScroller.ownerCt !== me) {
842             me.addDocked(me.verticalScroller);
843             me.addCls(me.verticalScrollerPresentCls);
844             me.fireEvent('scrollershow', me.verticalScroller, 'vertical');
845         }
846     },
847
848 <span id='Ext-panel.Table-method-invalidateScroller'>    /**
849 </span>     * Invalides scrollers that are present and forces a recalculation.
850      * (Not related to showing/hiding the scrollers)
851      */
852     invalidateScroller: function() {
853         var me = this,
854             vScroll = me.verticalScroller,
855             hScroll = me.horizontalScroller;
856
857         if (vScroll) {
858             vScroll.invalidate();
859         }
860         if (hScroll) {
861             hScroll.invalidate();
862         }
863     },
864
865     // refresh the view when a header moves
866     onHeaderMove: function(headerCt, header, fromIdx, toIdx) {
867         this.view.refresh();
868     },
869
870     // Section onHeaderHide is invoked after view.
871     onHeaderHide: function(headerCt, header) {
872         this.invalidateScroller();
873     },
874
875     onHeaderShow: function(headerCt, header) {
876         this.invalidateScroller();
877     },
878
879     getVerticalScroller: function() {
880         return this.getScrollerOwner().down('gridscroller[dock=' + this.verticalScrollDock + ']');
881     },
882
883     getHorizontalScroller: function() {
884         return this.getScrollerOwner().down('gridscroller[dock=bottom]');
885     },
886
887     onMouseWheel: function(e) {
888         var me = this,
889             browserEvent = e.browserEvent,
890             vertScroller = me.getVerticalScroller(),
891             horizScroller = me.getHorizontalScroller(),
892             scrollDelta = me.scrollDelta,
893             deltaY, deltaX,
894             vertScrollerEl, horizScrollerEl,
895             origScrollLeft, origScrollTop,
896             newScrollLeft, newScrollTop;
897
898         // Track original scroll values, so we can see if we've
899         // reached the end of our scroll height/width.
900         if (horizScroller) {
901             horizScrollerEl = horizScroller.el;
902             if (horizScrollerEl) {
903                 origScrollLeft = horizScrollerEl.dom.scrollLeft;
904             }
905         }
906         if (vertScroller) {
907             vertScrollerEl = vertScroller.el;
908             if (vertScrollerEl) {
909                 origScrollTop = vertScrollerEl.dom.scrollTop;
910             }
911         }
912
913         // Webkit Horizontal Axis
914         if (browserEvent.wheelDeltaX || browserEvent.wheelDeltaY) {
915             deltaX = -browserEvent.wheelDeltaX / 120 * scrollDelta / 3;
916             deltaY = -browserEvent.wheelDeltaY / 120 * scrollDelta / 3;
917             if (horizScroller) {
918                 newScrollLeft = horizScroller.scrollByDeltaX(deltaX);
919             }
920             if (vertScroller) {
921                 newScrollTop = vertScroller.scrollByDeltaY(deltaY);
922             }
923         } else {
924             // Gecko Horizontal Axis
925             if (browserEvent.axis &amp;&amp; browserEvent.axis === 1) {
926                 if (horizScroller) {
927                     deltaX = -(scrollDelta * e.getWheelDelta()) / 3;
928                     newScrollLeft = horizScroller.scrollByDeltaX(deltaX);
929                 }
930             } else {
931                 if (vertScroller) {
932
933                     deltaY = -(scrollDelta * e.getWheelDelta() / 3);
934                     newScrollTop = vertScroller.scrollByDeltaY(deltaY);
935                 }
936             }
937         }
938
939         // If after given our delta, the scroller has not progressed, then we're
940         // at the end of our scroll range and shouldn't stop the browser event.
941         if ((deltaX !== 0 &amp;&amp; newScrollLeft !== origScrollLeft) ||
942             (deltaY !== 0 &amp;&amp; newScrollTop !== origScrollTop)) {
943             e.stopEvent();
944         }
945     },
946
947 <span id='Ext-panel.Table-method-onViewRefresh'>    /**
948 </span>     * @private
949      * Determine and invalidate scrollers on view refresh
950      */
951     onViewRefresh: function() {
952         if (Ext.isIE) {
953             this.syncCellHeight();
954         }
955         this.determineScrollbars();
956         if (this.invalidateScrollerOnRefresh) {
957             this.invalidateScroller();
958         }
959     },
960
961     onViewItemUpdate: function(record, index, tr) {
962         if (Ext.isIE) {
963             this.syncCellHeight([tr]);
964         }
965     },
966
967     // BrowserBug: IE will not stretch the td to fit the height of the entire
968     // tr, so manually sync cellheights on refresh and when an item has been
969     // updated.
970     syncCellHeight: function(trs) {
971         var me    = this,
972             i     = 0,
973             tds,
974             j, tdsLn,
975             tr, td,
976             trsLn,
977             rowHeights = [],
978             cellHeights,
979             cellClsSelector = ('.' + Ext.baseCSSPrefix + 'grid-cell');
980
981         trs   = trs || me.view.getNodes();
982         
983         trsLn = trs.length;
984         // Reading loop
985         for (; i &lt; trsLn; i++) {
986             tr = trs[i];
987             tds = Ext.fly(tr).query(cellClsSelector);
988             tdsLn = tds.length;
989             cellHeights = [];
990             for (j = 0; j &lt; tdsLn; j++) {
991                 td = tds[j];
992                 cellHeights.push(td.clientHeight);
993             }
994             rowHeights.push(Ext.Array.max(cellHeights));
995         }
996
997         // Setting loop
998         for (i = 0; i &lt; trsLn; i++) {
999             tr = trs[i];
1000             tdsLn = tr.childNodes.length;
1001             for (j = 0; j &lt; tdsLn; j++) {
1002                 td = Ext.fly(tr.childNodes[j]);
1003                 if (rowHeights[i]) {
1004                     if (td.is(cellClsSelector)) {
1005                         td.setHeight(rowHeights[i]);
1006                     } else {
1007                         td.down(cellClsSelector).setHeight(rowHeights[i]);
1008                     }
1009                 }
1010                 
1011             }
1012         }
1013     },
1014
1015 <span id='Ext-panel.Table-method-setScrollTop'>    /**
1016 </span>     * Sets the scrollTop of the TablePanel.
1017      * @param {Number} deltaY
1018      */
1019     setScrollTop: function(top) {
1020         var me               = this,
1021             rootCmp          = me.getScrollerOwner(),
1022             verticalScroller = me.getVerticalScroller();
1023
1024         rootCmp.virtualScrollTop = top;
1025         if (verticalScroller) {
1026             verticalScroller.setScrollTop(top);
1027         }
1028
1029     },
1030
1031     getScrollerOwner: function() {
1032         var rootCmp = this;
1033         if (!this.scrollerOwner) {
1034             rootCmp = this.up('[scrollerOwner]');
1035         }
1036         return rootCmp;
1037     },
1038
1039 <span id='Ext-panel.Table-method-scrollByDeltaY'>    /**
1040 </span>     * Scrolls the TablePanel by deltaY
1041      * @param {Number} deltaY
1042      */
1043     scrollByDeltaY: function(deltaY) {
1044         var rootCmp = this.getScrollerOwner(),
1045             scrollerRight;
1046         scrollerRight = rootCmp.down('gridscroller[dock=' + this.verticalScrollDock + ']');
1047         if (scrollerRight) {
1048             scrollerRight.scrollByDeltaY(deltaY);
1049         }
1050     },
1051
1052
1053 <span id='Ext-panel.Table-method-scrollByDeltaX'>    /**
1054 </span>     * Scrolls the TablePanel by deltaX
1055      * @param {Number} deltaY
1056      */
1057     scrollByDeltaX: function(deltaX) {
1058         this.horizontalScroller.scrollByDeltaX(deltaX);
1059     },
1060
1061 <span id='Ext-panel.Table-method-getLhsMarker'>    /**
1062 </span>     * Get left hand side marker for header resizing.
1063      * @private
1064      */
1065     getLhsMarker: function() {
1066         var me = this;
1067
1068         if (!me.lhsMarker) {
1069             me.lhsMarker = Ext.core.DomHelper.append(me.el, {
1070                 cls: Ext.baseCSSPrefix + 'grid-resize-marker'
1071             }, true);
1072         }
1073         return me.lhsMarker;
1074     },
1075
1076 <span id='Ext-panel.Table-method-getRhsMarker'>    /**
1077 </span>     * Get right hand side marker for header resizing.
1078      * @private
1079      */
1080     getRhsMarker: function() {
1081         var me = this;
1082
1083         if (!me.rhsMarker) {
1084             me.rhsMarker = Ext.core.DomHelper.append(me.el, {
1085                 cls: Ext.baseCSSPrefix + 'grid-resize-marker'
1086             }, true);
1087         }
1088         return me.rhsMarker;
1089     },
1090
1091 <span id='Ext-panel.Table-method-getSelectionModel'>    /**
1092 </span>     * Returns the selection model being used and creates it via the configuration
1093      * if it has not been created already.
1094      * @return {Ext.selection.Model} selModel
1095      */
1096     getSelectionModel: function(){
1097         if (!this.selModel) {
1098             this.selModel = {};
1099         }
1100
1101         var mode = 'SINGLE',
1102             type;
1103         if (this.simpleSelect) {
1104             mode = 'SIMPLE';
1105         } else if (this.multiSelect) {
1106             mode = 'MULTI';
1107         }
1108
1109         Ext.applyIf(this.selModel, {
1110             allowDeselect: this.allowDeselect,
1111             mode: mode
1112         });
1113
1114         if (!this.selModel.events) {
1115             type = this.selModel.selType || this.selType;
1116             this.selModel = Ext.create('selection.' + type, this.selModel);
1117         }
1118
1119         if (!this.selModel.hasRelaySetup) {
1120             this.relayEvents(this.selModel, ['selectionchange', 'select', 'deselect']);
1121             this.selModel.hasRelaySetup = true;
1122         }
1123
1124         // lock the selection model if user
1125         // has disabled selection
1126         if (this.disableSelection) {
1127             this.selModel.locked = true;
1128         }
1129         return this.selModel;
1130     },
1131
1132     onVerticalScroll: function(event, target) {
1133         var owner = this.getScrollerOwner(),
1134             items = owner.query('tableview'),
1135             i = 0,
1136             len = items.length;
1137
1138         for (; i &lt; len; i++) {
1139             items[i].el.dom.scrollTop = target.scrollTop;
1140         }
1141     },
1142
1143     onHorizontalScroll: function(event, target) {
1144         var owner = this.getScrollerOwner(),
1145             items = owner.query('tableview'),
1146             i = 0,
1147             len = items.length,
1148             center,
1149             centerEl,
1150             centerScrollWidth,
1151             centerClientWidth,
1152             width;
1153
1154         center = items[1] || items[0];
1155         centerEl = center.el.dom;
1156         centerScrollWidth = centerEl.scrollWidth;
1157         centerClientWidth = centerEl.offsetWidth;
1158         width = this.horizontalScroller.getWidth();
1159
1160         centerEl.scrollLeft = target.scrollLeft;
1161         this.headerCt.el.dom.scrollLeft = target.scrollLeft;
1162     },
1163
1164     // template method meant to be overriden
1165     onStoreLoad: Ext.emptyFn,
1166
1167     getEditorParent: function() {
1168         return this.body;
1169     },
1170
1171     bindStore: function(store) {
1172         var me = this;
1173         me.store = store;
1174         me.getView().bindStore(store);
1175     },
1176
1177     reconfigure: function(store, columns) {
1178         var me = this;
1179
1180         if (me.lockable) {
1181             me.reconfigureLockable(store, columns);
1182             return;
1183         }
1184
1185         if (columns) {
1186             me.headerCt.removeAll();
1187             me.headerCt.add(columns);
1188         }
1189         if (store) {
1190             store = Ext.StoreManager.lookup(store);
1191             me.bindStore(store);
1192         } else {
1193             me.getView().refresh();
1194         }
1195     },
1196
1197     afterComponentLayout: function() {
1198         this.callParent(arguments);
1199         this.determineScrollbars();
1200         this.invalidateScroller();
1201     }
1202 });</pre></pre></body></html>