Upgrade to ExtJS 3.3.1 - Released 11/30/2010
[extjs.git] / src / widgets / grid / GridPanel.js
1 /*!
2  * Ext JS Library 3.3.1
3  * Copyright(c) 2006-2010 Sencha Inc.
4  * licensing@sencha.com
5  * http://www.sencha.com/license
6  */
7 /**
8  * @class Ext.grid.GridPanel
9  * @extends Ext.Panel
10  * <p>This class represents the primary interface of a component based grid control to represent data
11  * in a tabular format of rows and columns. The GridPanel is composed of the following:</p>
12  * <div class="mdetail-params"><ul>
13  * <li><b>{@link Ext.data.Store Store}</b> : The Model holding the data records (rows)
14  * <div class="sub-desc"></div></li>
15  * <li><b>{@link Ext.grid.ColumnModel Column model}</b> : Column makeup
16  * <div class="sub-desc"></div></li>
17  * <li><b>{@link Ext.grid.GridView View}</b> : Encapsulates the user interface
18  * <div class="sub-desc"></div></li>
19  * <li><b>{@link Ext.grid.AbstractSelectionModel selection model}</b> : Selection behavior
20  * <div class="sub-desc"></div></li>
21  * </ul></div>
22  * <p>Example usage:</p>
23  * <pre><code>
24 var grid = new Ext.grid.GridPanel({
25     {@link #store}: new {@link Ext.data.Store}({
26         {@link Ext.data.Store#autoDestroy autoDestroy}: true,
27         {@link Ext.data.Store#reader reader}: reader,
28         {@link Ext.data.Store#data data}: xg.dummyData
29     }),
30     {@link #colModel}: new {@link Ext.grid.ColumnModel}({
31         {@link Ext.grid.ColumnModel#defaults defaults}: {
32             width: 120,
33             sortable: true
34         },
35         {@link Ext.grid.ColumnModel#columns columns}: [
36             {id: 'company', header: 'Company', width: 200, sortable: true, dataIndex: 'company'},
37             {header: 'Price', renderer: Ext.util.Format.usMoney, dataIndex: 'price'},
38             {header: 'Change', dataIndex: 'change'},
39             {header: '% Change', dataIndex: 'pctChange'},
40             // instead of specifying renderer: Ext.util.Format.dateRenderer('m/d/Y') use xtype
41             {
42                 header: 'Last Updated', width: 135, dataIndex: 'lastChange',
43                 xtype: 'datecolumn', format: 'M d, Y'
44             }
45         ],
46     }),
47     {@link #viewConfig}: {
48         {@link Ext.grid.GridView#forceFit forceFit}: true,
49
50 //      Return CSS class to apply to rows depending upon data values
51         {@link Ext.grid.GridView#getRowClass getRowClass}: function(record, index) {
52             var c = record.{@link Ext.data.Record#get get}('change');
53             if (c < 0) {
54                 return 'price-fall';
55             } else if (c > 0) {
56                 return 'price-rise';
57             }
58         }
59     },
60     {@link #sm}: new Ext.grid.RowSelectionModel({singleSelect:true}),
61     width: 600,
62     height: 300,
63     frame: true,
64     title: 'Framed with Row Selection and Horizontal Scrolling',
65     iconCls: 'icon-grid'
66 });
67  * </code></pre>
68  * <p><b><u>Notes:</u></b></p>
69  * <div class="mdetail-params"><ul>
70  * <li>Although this class inherits many configuration options from base classes, some of them
71  * (such as autoScroll, autoWidth, layout, items, etc) are not used by this class, and will
72  * have no effect.</li>
73  * <li>A grid <b>requires</b> a width in which to scroll its columns, and a height in which to
74  * scroll its rows. These dimensions can either be set explicitly through the
75  * <tt>{@link Ext.BoxComponent#height height}</tt> and <tt>{@link Ext.BoxComponent#width width}</tt>
76  * configuration options or implicitly set by using the grid as a child item of a
77  * {@link Ext.Container Container} which will have a {@link Ext.Container#layout layout manager}
78  * provide the sizing of its child items (for example the Container of the Grid may specify
79  * <tt>{@link Ext.Container#layout layout}:'fit'</tt>).</li>
80  * <li>To access the data in a Grid, it is necessary to use the data model encapsulated
81  * by the {@link #store Store}. See the {@link #cellclick} event for more details.</li>
82  * </ul></div>
83  * @constructor
84  * @param {Object} config The config object
85  * @xtype grid
86  */
87 Ext.grid.GridPanel = Ext.extend(Ext.Panel, {
88     /**
89      * @cfg {String} autoExpandColumn
90      * <p>The <tt>{@link Ext.grid.Column#id id}</tt> of a {@link Ext.grid.Column column} in
91      * this grid that should expand to fill unused space. This value specified here can not
92      * be <tt>0</tt>.</p>
93      * <br><p><b>Note</b>: If the Grid's {@link Ext.grid.GridView view} is configured with
94      * <tt>{@link Ext.grid.GridView#forceFit forceFit}=true</tt> the <tt>autoExpandColumn</tt>
95      * is ignored. See {@link Ext.grid.Column}.<tt>{@link Ext.grid.Column#width width}</tt>
96      * for additional details.</p>
97      * <p>See <tt>{@link #autoExpandMax}</tt> and <tt>{@link #autoExpandMin}</tt> also.</p>
98      */
99     autoExpandColumn : false,
100     
101     /**
102      * @cfg {Number} autoExpandMax The maximum width the <tt>{@link #autoExpandColumn}</tt>
103      * can have (if enabled). Defaults to <tt>1000</tt>.
104      */
105     autoExpandMax : 1000,
106     
107     /**
108      * @cfg {Number} autoExpandMin The minimum width the <tt>{@link #autoExpandColumn}</tt>
109      * can have (if enabled). Defaults to <tt>50</tt>.
110      */
111     autoExpandMin : 50,
112     
113     /**
114      * @cfg {Boolean} columnLines <tt>true</tt> to add css for column separation lines.
115      * Default is <tt>false</tt>.
116      */
117     columnLines : false,
118     
119     /**
120      * @cfg {Object} cm Shorthand for <tt>{@link #colModel}</tt>.
121      */
122     /**
123      * @cfg {Object} colModel The {@link Ext.grid.ColumnModel} to use when rendering the grid (required).
124      */
125     /**
126      * @cfg {Array} columns An array of {@link Ext.grid.Column columns} to auto create a
127      * {@link Ext.grid.ColumnModel}.  The ColumnModel may be explicitly created via the
128      * <tt>{@link #colModel}</tt> configuration property.
129      */
130     /**
131      * @cfg {String} ddGroup The DD group this GridPanel belongs to. Defaults to <tt>'GridDD'</tt> if not specified.
132      */
133     /**
134      * @cfg {String} ddText
135      * Configures the text in the drag proxy.  Defaults to:
136      * <pre><code>
137      * ddText : '{0} selected row{1}'
138      * </code></pre>
139      * <tt>{0}</tt> is replaced with the number of selected rows.
140      */
141     ddText : '{0} selected row{1}',
142     
143     /**
144      * @cfg {Boolean} deferRowRender <P>Defaults to <tt>true</tt> to enable deferred row rendering.</p>
145      * <p>This allows the GridPanel to be initially rendered empty, with the expensive update of the row
146      * structure deferred so that layouts with GridPanels appear more quickly.</p>
147      */
148     deferRowRender : true,
149     
150     /**
151      * @cfg {Boolean} disableSelection <p><tt>true</tt> to disable selections in the grid. Defaults to <tt>false</tt>.</p>
152      * <p>Ignored if a {@link #selModel SelectionModel} is specified.</p>
153      */
154     /**
155      * @cfg {Boolean} enableColumnResize <tt>false</tt> to turn off column resizing for the whole grid. Defaults to <tt>true</tt>.
156      */
157     /**
158      * @cfg {Boolean} enableColumnHide
159      * Defaults to <tt>true</tt> to enable {@link Ext.grid.Column#hidden hiding of columns}
160      * with the {@link #enableHdMenu header menu}.
161      */
162     enableColumnHide : true,
163     
164     /**
165      * @cfg {Boolean} enableColumnMove Defaults to <tt>true</tt> to enable drag and drop reorder of columns. <tt>false</tt>
166      * to turn off column reordering via drag drop.
167      */
168     enableColumnMove : true,
169     
170     /**
171      * @cfg {Boolean} enableDragDrop <p>Enables dragging of the selected rows of the GridPanel. Defaults to <tt>false</tt>.</p>
172      * <p>Setting this to <b><tt>true</tt></b> causes this GridPanel's {@link #getView GridView} to
173      * create an instance of {@link Ext.grid.GridDragZone}. <b>Note</b>: this is available only <b>after</b>
174      * the Grid has been rendered as the GridView's <tt>{@link Ext.grid.GridView#dragZone dragZone}</tt>
175      * property.</p>
176      * <p>A cooperating {@link Ext.dd.DropZone DropZone} must be created who's implementations of
177      * {@link Ext.dd.DropZone#onNodeEnter onNodeEnter}, {@link Ext.dd.DropZone#onNodeOver onNodeOver},
178      * {@link Ext.dd.DropZone#onNodeOut onNodeOut} and {@link Ext.dd.DropZone#onNodeDrop onNodeDrop} are able
179      * to process the {@link Ext.grid.GridDragZone#getDragData data} which is provided.</p>
180      */
181     enableDragDrop : false,
182     
183     /**
184      * @cfg {Boolean} enableHdMenu Defaults to <tt>true</tt> to enable the drop down button for menu in the headers.
185      */
186     enableHdMenu : true,
187     
188     /**
189      * @cfg {Boolean} hideHeaders True to hide the grid's header. Defaults to <code>false</code>.
190      */
191     /**
192      * @cfg {Object} loadMask An {@link Ext.LoadMask} config or true to mask the grid while
193      * loading. Defaults to <code>false</code>.
194      */
195     loadMask : false,
196     
197     /**
198      * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if <tt>autoHeight</tt> is not on.
199      */
200     /**
201      * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Defaults to <tt>25</tt>.
202      */
203     minColumnWidth : 25,
204     
205     /**
206      * @cfg {Object} sm Shorthand for <tt>{@link #selModel}</tt>.
207      */
208     /**
209      * @cfg {Object} selModel Any subclass of {@link Ext.grid.AbstractSelectionModel} that will provide
210      * the selection model for the grid (defaults to {@link Ext.grid.RowSelectionModel} if not specified).
211      */
212     /**
213      * @cfg {Ext.data.Store} store The {@link Ext.data.Store} the grid should use as its data source (required).
214      */
215     /**
216      * @cfg {Boolean} stripeRows <tt>true</tt> to stripe the rows. Default is <tt>false</tt>.
217      * <p>This causes the CSS class <tt><b>x-grid3-row-alt</b></tt> to be added to alternate rows of
218      * the grid. A default CSS rule is provided which sets a background colour, but you can override this
219      * with a rule which either overrides the <b>background-color</b> style using the '!important'
220      * modifier, or which uses a CSS selector of higher specificity.</p>
221      */
222     stripeRows : false,
223     
224     /**
225      * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is <tt>true</tt>
226      * for GridPanel, but <tt>false</tt> for EditorGridPanel.
227      */
228     trackMouseOver : true,
229     
230     /**
231      * @cfg {Array} stateEvents
232      * An array of events that, when fired, should trigger this component to save its state.
233      * Defaults to:<pre><code>
234      * stateEvents: ['columnmove', 'columnresize', 'sortchange', 'groupchange']
235      * </code></pre>
236      * <p>These can be any types of events supported by this component, including browser or
237      * custom events (e.g., <tt>['click', 'customerchange']</tt>).</p>
238      * <p>See {@link Ext.Component#stateful} for an explanation of saving and restoring
239      * Component state.</p>
240      */
241     stateEvents : ['columnmove', 'columnresize', 'sortchange', 'groupchange'],
242     
243     /**
244      * @cfg {Object} view The {@link Ext.grid.GridView} used by the grid. This can be set
245      * before a call to {@link Ext.Component#render render()}.
246      */
247     view : null,
248
249     /**
250      * @cfg {Array} bubbleEvents
251      * <p>An array of events that, when fired, should be bubbled to any parent container.
252      * See {@link Ext.util.Observable#enableBubble}.
253      * Defaults to <tt>[]</tt>.
254      */
255     bubbleEvents: [],
256
257     /**
258      * @cfg {Object} viewConfig A config object that will be applied to the grid's UI view.  Any of
259      * the config options available for {@link Ext.grid.GridView} can be specified here. This option
260      * is ignored if <tt>{@link #view}</tt> is specified.
261      */
262
263     // private
264     rendered : false,
265     
266     // private
267     viewReady : false,
268
269     // private
270     initComponent : function() {
271         Ext.grid.GridPanel.superclass.initComponent.call(this);
272
273         if (this.columnLines) {
274             this.cls = (this.cls || '') + ' x-grid-with-col-lines';
275         }
276         // override any provided value since it isn't valid
277         // and is causing too many bug reports ;)
278         this.autoScroll = false;
279         this.autoWidth = false;
280
281         if(Ext.isArray(this.columns)){
282             this.colModel = new Ext.grid.ColumnModel(this.columns);
283             delete this.columns;
284         }
285
286         // check and correct shorthanded configs
287         if(this.ds){
288             this.store = this.ds;
289             delete this.ds;
290         }
291         if(this.cm){
292             this.colModel = this.cm;
293             delete this.cm;
294         }
295         if(this.sm){
296             this.selModel = this.sm;
297             delete this.sm;
298         }
299         this.store = Ext.StoreMgr.lookup(this.store);
300
301         this.addEvents(
302             // raw events
303             /**
304              * @event click
305              * The raw click event for the entire grid.
306              * @param {Ext.EventObject} e
307              */
308             'click',
309             /**
310              * @event dblclick
311              * The raw dblclick event for the entire grid.
312              * @param {Ext.EventObject} e
313              */
314             'dblclick',
315             /**
316              * @event contextmenu
317              * The raw contextmenu event for the entire grid.
318              * @param {Ext.EventObject} e
319              */
320             'contextmenu',
321             /**
322              * @event mousedown
323              * The raw mousedown event for the entire grid.
324              * @param {Ext.EventObject} e
325              */
326             'mousedown',
327             /**
328              * @event mouseup
329              * The raw mouseup event for the entire grid.
330              * @param {Ext.EventObject} e
331              */
332             'mouseup',
333             /**
334              * @event mouseover
335              * The raw mouseover event for the entire grid.
336              * @param {Ext.EventObject} e
337              */
338             'mouseover',
339             /**
340              * @event mouseout
341              * The raw mouseout event for the entire grid.
342              * @param {Ext.EventObject} e
343              */
344             'mouseout',
345             /**
346              * @event keypress
347              * The raw keypress event for the entire grid.
348              * @param {Ext.EventObject} e
349              */
350             'keypress',
351             /**
352              * @event keydown
353              * The raw keydown event for the entire grid.
354              * @param {Ext.EventObject} e
355              */
356             'keydown',
357
358             // custom events
359             /**
360              * @event cellmousedown
361              * Fires before a cell is clicked
362              * @param {Grid} this
363              * @param {Number} rowIndex
364              * @param {Number} columnIndex
365              * @param {Ext.EventObject} e
366              */
367             'cellmousedown',
368             /**
369              * @event rowmousedown
370              * Fires before a row is clicked
371              * @param {Grid} this
372              * @param {Number} rowIndex
373              * @param {Ext.EventObject} e
374              */
375             'rowmousedown',
376             /**
377              * @event headermousedown
378              * Fires before a header is clicked
379              * @param {Grid} this
380              * @param {Number} columnIndex
381              * @param {Ext.EventObject} e
382              */
383             'headermousedown',
384
385             /**
386              * @event groupmousedown
387              * Fires before a group header is clicked. <b>Only applies for grids with a {@link Ext.grid.GroupingView GroupingView}</b>.
388              * @param {Grid} this
389              * @param {String} groupField
390              * @param {String} groupValue
391              * @param {Ext.EventObject} e
392              */
393             'groupmousedown',
394
395             /**
396              * @event rowbodymousedown
397              * Fires before the row body is clicked. <b>Only applies for grids with {@link Ext.grid.GridView#enableRowBody enableRowBody} configured.</b>
398              * @param {Grid} this
399              * @param {Number} rowIndex
400              * @param {Ext.EventObject} e
401              */
402             'rowbodymousedown',
403
404             /**
405              * @event containermousedown
406              * Fires before the container is clicked. The container consists of any part of the grid body that is not covered by a row.
407              * @param {Grid} this
408              * @param {Ext.EventObject} e
409              */
410             'containermousedown',
411
412             /**
413              * @event cellclick
414              * Fires when a cell is clicked.
415              * The data for the cell is drawn from the {@link Ext.data.Record Record}
416              * for this row. To access the data in the listener function use the
417              * following technique:
418              * <pre><code>
419 function(grid, rowIndex, columnIndex, e) {
420     var record = grid.getStore().getAt(rowIndex);  // Get the Record
421     var fieldName = grid.getColumnModel().getDataIndex(columnIndex); // Get field name
422     var data = record.get(fieldName);
423 }
424 </code></pre>
425              * @param {Grid} this
426              * @param {Number} rowIndex
427              * @param {Number} columnIndex
428              * @param {Ext.EventObject} e
429              */
430             'cellclick',
431             /**
432              * @event celldblclick
433              * Fires when a cell is double clicked
434              * @param {Grid} this
435              * @param {Number} rowIndex
436              * @param {Number} columnIndex
437              * @param {Ext.EventObject} e
438              */
439             'celldblclick',
440             /**
441              * @event rowclick
442              * Fires when a row is clicked
443              * @param {Grid} this
444              * @param {Number} rowIndex
445              * @param {Ext.EventObject} e
446              */
447             'rowclick',
448             /**
449              * @event rowdblclick
450              * Fires when a row is double clicked
451              * @param {Grid} this
452              * @param {Number} rowIndex
453              * @param {Ext.EventObject} e
454              */
455             'rowdblclick',
456             /**
457              * @event headerclick
458              * Fires when a header is clicked
459              * @param {Grid} this
460              * @param {Number} columnIndex
461              * @param {Ext.EventObject} e
462              */
463             'headerclick',
464             /**
465              * @event headerdblclick
466              * Fires when a header cell is double clicked
467              * @param {Grid} this
468              * @param {Number} columnIndex
469              * @param {Ext.EventObject} e
470              */
471             'headerdblclick',
472             /**
473              * @event groupclick
474              * Fires when group header is clicked. <b>Only applies for grids with a {@link Ext.grid.GroupingView GroupingView}</b>.
475              * @param {Grid} this
476              * @param {String} groupField
477              * @param {String} groupValue
478              * @param {Ext.EventObject} e
479              */
480             'groupclick',
481             /**
482              * @event groupdblclick
483              * Fires when group header is double clicked. <b>Only applies for grids with a {@link Ext.grid.GroupingView GroupingView}</b>.
484              * @param {Grid} this
485              * @param {String} groupField
486              * @param {String} groupValue
487              * @param {Ext.EventObject} e
488              */
489             'groupdblclick',
490             /**
491              * @event containerclick
492              * Fires when the container is clicked. The container consists of any part of the grid body that is not covered by a row.
493              * @param {Grid} this
494              * @param {Ext.EventObject} e
495              */
496             'containerclick',
497             /**
498              * @event containerdblclick
499              * Fires when the container is double clicked. The container consists of any part of the grid body that is not covered by a row.
500              * @param {Grid} this
501              * @param {Ext.EventObject} e
502              */
503             'containerdblclick',
504
505             /**
506              * @event rowbodyclick
507              * Fires when the row body is clicked. <b>Only applies for grids with {@link Ext.grid.GridView#enableRowBody enableRowBody} configured.</b>
508              * @param {Grid} this
509              * @param {Number} rowIndex
510              * @param {Ext.EventObject} e
511              */
512             'rowbodyclick',
513             /**
514              * @event rowbodydblclick
515              * Fires when the row body is double clicked. <b>Only applies for grids with {@link Ext.grid.GridView#enableRowBody enableRowBody} configured.</b>
516              * @param {Grid} this
517              * @param {Number} rowIndex
518              * @param {Ext.EventObject} e
519              */
520             'rowbodydblclick',
521
522             /**
523              * @event rowcontextmenu
524              * Fires when a row is right clicked
525              * @param {Grid} this
526              * @param {Number} rowIndex
527              * @param {Ext.EventObject} e
528              */
529             'rowcontextmenu',
530             /**
531              * @event cellcontextmenu
532              * Fires when a cell is right clicked
533              * @param {Grid} this
534              * @param {Number} rowIndex
535              * @param {Number} cellIndex
536              * @param {Ext.EventObject} e
537              */
538             'cellcontextmenu',
539             /**
540              * @event headercontextmenu
541              * Fires when a header is right clicked
542              * @param {Grid} this
543              * @param {Number} columnIndex
544              * @param {Ext.EventObject} e
545              */
546             'headercontextmenu',
547             /**
548              * @event groupcontextmenu
549              * Fires when group header is right clicked. <b>Only applies for grids with a {@link Ext.grid.GroupingView GroupingView}</b>.
550              * @param {Grid} this
551              * @param {String} groupField
552              * @param {String} groupValue
553              * @param {Ext.EventObject} e
554              */
555             'groupcontextmenu',
556             /**
557              * @event containercontextmenu
558              * Fires when the container is right clicked. The container consists of any part of the grid body that is not covered by a row.
559              * @param {Grid} this
560              * @param {Ext.EventObject} e
561              */
562             'containercontextmenu',
563             /**
564              * @event rowbodycontextmenu
565              * Fires when the row body is right clicked. <b>Only applies for grids with {@link Ext.grid.GridView#enableRowBody enableRowBody} configured.</b>
566              * @param {Grid} this
567              * @param {Number} rowIndex
568              * @param {Ext.EventObject} e
569              */
570             'rowbodycontextmenu',
571             /**
572              * @event bodyscroll
573              * Fires when the body element is scrolled
574              * @param {Number} scrollLeft
575              * @param {Number} scrollTop
576              */
577             'bodyscroll',
578             /**
579              * @event columnresize
580              * Fires when the user resizes a column
581              * @param {Number} columnIndex
582              * @param {Number} newSize
583              */
584             'columnresize',
585             /**
586              * @event columnmove
587              * Fires when the user moves a column
588              * @param {Number} oldIndex
589              * @param {Number} newIndex
590              */
591             'columnmove',
592             /**
593              * @event sortchange
594              * Fires when the grid's store sort changes
595              * @param {Grid} this
596              * @param {Object} sortInfo An object with the keys field and direction
597              */
598             'sortchange',
599             /**
600              * @event groupchange
601              * Fires when the grid's grouping changes (only applies for grids with a {@link Ext.grid.GroupingView GroupingView})
602              * @param {Grid} this
603              * @param {String} groupField A string with the grouping field, null if the store is not grouped.
604              */
605             'groupchange',
606             /**
607              * @event reconfigure
608              * Fires when the grid is reconfigured with a new store and/or column model.
609              * @param {Grid} this
610              * @param {Ext.data.Store} store The new store
611              * @param {Ext.grid.ColumnModel} colModel The new column model
612              */
613             'reconfigure',
614             /**
615              * @event viewready
616              * Fires when the grid view is available (use this for selecting a default row).
617              * @param {Grid} this
618              */
619             'viewready'
620         );
621     },
622
623     // private
624     onRender : function(ct, position){
625         Ext.grid.GridPanel.superclass.onRender.apply(this, arguments);
626
627         var c = this.getGridEl();
628
629         this.el.addClass('x-grid-panel');
630
631         this.mon(c, {
632             scope: this,
633             mousedown: this.onMouseDown,
634             click: this.onClick,
635             dblclick: this.onDblClick,
636             contextmenu: this.onContextMenu
637         });
638
639         this.relayEvents(c, ['mousedown','mouseup','mouseover','mouseout','keypress', 'keydown']);
640
641         var view = this.getView();
642         view.init(this);
643         view.render();
644         this.getSelectionModel().init(this);
645     },
646
647     // private
648     initEvents : function(){
649         Ext.grid.GridPanel.superclass.initEvents.call(this);
650
651         if(this.loadMask){
652             this.loadMask = new Ext.LoadMask(this.bwrap,
653                     Ext.apply({store:this.store}, this.loadMask));
654         }
655     },
656
657     initStateEvents : function(){
658         Ext.grid.GridPanel.superclass.initStateEvents.call(this);
659         this.mon(this.colModel, 'hiddenchange', this.saveState, this, {delay: 100});
660     },
661
662     applyState : function(state){
663         var cm = this.colModel,
664             cs = state.columns,
665             store = this.store,
666             s,
667             c,
668             colIndex;
669
670         if(cs){
671             for(var i = 0, len = cs.length; i < len; i++){
672                 s = cs[i];
673                 c = cm.getColumnById(s.id);
674                 if(c){
675                     colIndex = cm.getIndexById(s.id);
676                     cm.setState(colIndex, {
677                         hidden: s.hidden,
678                         width: s.width,
679                         sortable: s.sortable
680                     });
681                     if(colIndex != i){
682                         cm.moveColumn(colIndex, i);
683                     }
684                 }
685             }
686         }
687         if(store){
688             s = state.sort;
689             if(s){
690                 store[store.remoteSort ? 'setDefaultSort' : 'sort'](s.field, s.direction);
691             }
692             s = state.group;
693             if(store.groupBy){
694                 if(s){
695                     store.groupBy(s);
696                 }else{
697                     store.clearGrouping();
698                 }
699             }
700
701         }
702         var o = Ext.apply({}, state);
703         delete o.columns;
704         delete o.sort;
705         Ext.grid.GridPanel.superclass.applyState.call(this, o);
706     },
707
708     getState : function(){
709         var o = {columns: []},
710             store = this.store,
711             ss,
712             gs;
713
714         for(var i = 0, c; (c = this.colModel.config[i]); i++){
715             o.columns[i] = {
716                 id: c.id,
717                 width: c.width
718             };
719             if(c.hidden){
720                 o.columns[i].hidden = true;
721             }
722             if(c.sortable){
723                 o.columns[i].sortable = true;
724             }
725         }
726         if(store){
727             ss = store.getSortState();
728             if(ss){
729                 o.sort = ss;
730             }
731             if(store.getGroupState){
732                 gs = store.getGroupState();
733                 if(gs){
734                     o.group = gs;
735                 }
736             }
737         }
738         return o;
739     },
740
741     // private
742     afterRender : function(){
743         Ext.grid.GridPanel.superclass.afterRender.call(this);
744         var v = this.view;
745         this.on('bodyresize', v.layout, v);
746         v.layout(true);
747         if(this.deferRowRender){
748             if (!this.deferRowRenderTask){
749                 this.deferRowRenderTask = new Ext.util.DelayedTask(v.afterRender, this.view);
750             }
751             this.deferRowRenderTask.delay(10);
752         }else{
753             v.afterRender();
754         }
755         this.viewReady = true;
756     },
757
758     /**
759      * <p>Reconfigures the grid to use a different Store and Column Model
760      * and fires the 'reconfigure' event. The View will be bound to the new
761      * objects and refreshed.</p>
762      * <p>Be aware that upon reconfiguring a GridPanel, certain existing settings <i>may</i> become
763      * invalidated. For example the configured {@link #autoExpandColumn} may no longer exist in the
764      * new ColumnModel. Also, an existing {@link Ext.PagingToolbar PagingToolbar} will still be bound
765      * to the old Store, and will need rebinding. Any {@link #plugins} might also need reconfiguring
766      * with the new data.</p>
767      * @param {Ext.data.Store} store The new {@link Ext.data.Store} object
768      * @param {Ext.grid.ColumnModel} colModel The new {@link Ext.grid.ColumnModel} object
769      */
770     reconfigure : function(store, colModel){
771         var rendered = this.rendered;
772         if(rendered){
773             if(this.loadMask){
774                 this.loadMask.destroy();
775                 this.loadMask = new Ext.LoadMask(this.bwrap,
776                         Ext.apply({}, {store:store}, this.initialConfig.loadMask));
777             }
778         }
779         if(this.view){
780             this.view.initData(store, colModel);
781         }
782         this.store = store;
783         this.colModel = colModel;
784         if(rendered){
785             this.view.refresh(true);
786         }
787         this.fireEvent('reconfigure', this, store, colModel);
788     },
789
790     // private
791     onDestroy : function(){
792         if (this.deferRowRenderTask && this.deferRowRenderTask.cancel){
793             this.deferRowRenderTask.cancel();
794         }
795         if(this.rendered){
796             Ext.destroy(this.view, this.loadMask);
797         }else if(this.store && this.store.autoDestroy){
798             this.store.destroy();
799         }
800         Ext.destroy(this.colModel, this.selModel);
801         this.store = this.selModel = this.colModel = this.view = this.loadMask = null;
802         Ext.grid.GridPanel.superclass.onDestroy.call(this);
803     },
804
805     // private
806     processEvent : function(name, e){
807         this.view.processEvent(name, e);
808     },
809
810     // private
811     onClick : function(e){
812         this.processEvent('click', e);
813     },
814
815     // private
816     onMouseDown : function(e){
817         this.processEvent('mousedown', e);
818     },
819
820     // private
821     onContextMenu : function(e, t){
822         this.processEvent('contextmenu', e);
823     },
824
825     // private
826     onDblClick : function(e){
827         this.processEvent('dblclick', e);
828     },
829
830     // private
831     walkCells : function(row, col, step, fn, scope){
832         var cm    = this.colModel,
833             clen  = cm.getColumnCount(),
834             ds    = this.store,
835             rlen  = ds.getCount(),
836             first = true;
837
838         if(step < 0){
839             if(col < 0){
840                 row--;
841                 first = false;
842             }
843             while(row >= 0){
844                 if(!first){
845                     col = clen-1;
846                 }
847                 first = false;
848                 while(col >= 0){
849                     if(fn.call(scope || this, row, col, cm) === true){
850                         return [row, col];
851                     }
852                     col--;
853                 }
854                 row--;
855             }
856         } else {
857             if(col >= clen){
858                 row++;
859                 first = false;
860             }
861             while(row < rlen){
862                 if(!first){
863                     col = 0;
864                 }
865                 first = false;
866                 while(col < clen){
867                     if(fn.call(scope || this, row, col, cm) === true){
868                         return [row, col];
869                     }
870                     col++;
871                 }
872                 row++;
873             }
874         }
875         return null;
876     },
877
878     /**
879      * Returns the grid's underlying element.
880      * @return {Element} The element
881      */
882     getGridEl : function(){
883         return this.body;
884     },
885
886     // private for compatibility, overridden by editor grid
887     stopEditing : Ext.emptyFn,
888
889     /**
890      * Returns the grid's selection model configured by the <code>{@link #selModel}</code>
891      * configuration option. If no selection model was configured, this will create
892      * and return a {@link Ext.grid.RowSelectionModel RowSelectionModel}.
893      * @return {SelectionModel}
894      */
895     getSelectionModel : function(){
896         if(!this.selModel){
897             this.selModel = new Ext.grid.RowSelectionModel(
898                     this.disableSelection ? {selectRow: Ext.emptyFn} : null);
899         }
900         return this.selModel;
901     },
902
903     /**
904      * Returns the grid's data store.
905      * @return {Ext.data.Store} The store
906      */
907     getStore : function(){
908         return this.store;
909     },
910
911     /**
912      * Returns the grid's ColumnModel.
913      * @return {Ext.grid.ColumnModel} The column model
914      */
915     getColumnModel : function(){
916         return this.colModel;
917     },
918
919     /**
920      * Returns the grid's GridView object.
921      * @return {Ext.grid.GridView} The grid view
922      */
923     getView : function() {
924         if (!this.view) {
925             this.view = new Ext.grid.GridView(this.viewConfig);
926         }
927         
928         return this.view;
929     },
930     /**
931      * Called to get grid's drag proxy text, by default returns this.ddText.
932      * @return {String} The text
933      */
934     getDragDropText : function(){
935         var count = this.selModel.getCount();
936         return String.format(this.ddText, count, count == 1 ? '' : 's');
937     }
938
939     /**
940      * @cfg {String/Number} activeItem
941      * @hide
942      */
943     /**
944      * @cfg {Boolean} autoDestroy
945      * @hide
946      */
947     /**
948      * @cfg {Object/String/Function} autoLoad
949      * @hide
950      */
951     /**
952      * @cfg {Boolean} autoWidth
953      * @hide
954      */
955     /**
956      * @cfg {Boolean/Number} bufferResize
957      * @hide
958      */
959     /**
960      * @cfg {String} defaultType
961      * @hide
962      */
963     /**
964      * @cfg {Object} defaults
965      * @hide
966      */
967     /**
968      * @cfg {Boolean} hideBorders
969      * @hide
970      */
971     /**
972      * @cfg {Mixed} items
973      * @hide
974      */
975     /**
976      * @cfg {String} layout
977      * @hide
978      */
979     /**
980      * @cfg {Object} layoutConfig
981      * @hide
982      */
983     /**
984      * @cfg {Boolean} monitorResize
985      * @hide
986      */
987     /**
988      * @property items
989      * @hide
990      */
991     /**
992      * @method add
993      * @hide
994      */
995     /**
996      * @method cascade
997      * @hide
998      */
999     /**
1000      * @method doLayout
1001      * @hide
1002      */
1003     /**
1004      * @method find
1005      * @hide
1006      */
1007     /**
1008      * @method findBy
1009      * @hide
1010      */
1011     /**
1012      * @method findById
1013      * @hide
1014      */
1015     /**
1016      * @method findByType
1017      * @hide
1018      */
1019     /**
1020      * @method getComponent
1021      * @hide
1022      */
1023     /**
1024      * @method getLayout
1025      * @hide
1026      */
1027     /**
1028      * @method getUpdater
1029      * @hide
1030      */
1031     /**
1032      * @method insert
1033      * @hide
1034      */
1035     /**
1036      * @method load
1037      * @hide
1038      */
1039     /**
1040      * @method remove
1041      * @hide
1042      */
1043     /**
1044      * @event add
1045      * @hide
1046      */
1047     /**
1048      * @event afterlayout
1049      * @hide
1050      */
1051     /**
1052      * @event beforeadd
1053      * @hide
1054      */
1055     /**
1056      * @event beforeremove
1057      * @hide
1058      */
1059     /**
1060      * @event remove
1061      * @hide
1062      */
1063
1064
1065
1066     /**
1067      * @cfg {String} allowDomMove  @hide
1068      */
1069     /**
1070      * @cfg {String} autoEl @hide
1071      */
1072     /**
1073      * @cfg {String} applyTo  @hide
1074      */
1075     /**
1076      * @cfg {String} autoScroll  @hide
1077      */
1078     /**
1079      * @cfg {String} bodyBorder  @hide
1080      */
1081     /**
1082      * @cfg {String} bodyStyle  @hide
1083      */
1084     /**
1085      * @cfg {String} contentEl  @hide
1086      */
1087     /**
1088      * @cfg {String} disabledClass  @hide
1089      */
1090     /**
1091      * @cfg {String} elements  @hide
1092      */
1093     /**
1094      * @cfg {String} html  @hide
1095      */
1096     /**
1097      * @cfg {Boolean} preventBodyReset
1098      * @hide
1099      */
1100     /**
1101      * @property disabled
1102      * @hide
1103      */
1104     /**
1105      * @method applyToMarkup
1106      * @hide
1107      */
1108     /**
1109      * @method enable
1110      * @hide
1111      */
1112     /**
1113      * @method disable
1114      * @hide
1115      */
1116     /**
1117      * @method setDisabled
1118      * @hide
1119      */
1120 });
1121 Ext.reg('grid', Ext.grid.GridPanel);