Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / docs / source / Column.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5   <title>The source code</title>
6   <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
7   <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
8   <style type="text/css">
9     .highlight { display: block; background-color: #ddd; }
10   </style>
11   <script type="text/javascript">
12     function highlight() {
13       document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
14     }
15   </script>
16 </head>
17 <body onload="prettyPrint(); highlight();">
18   <pre class="prettyprint lang-js"><span id='Ext-grid-column-Column'>/**
19 </span> * This class specifies the definition for a column inside a {@link Ext.grid.Panel}. It encompasses
20  * both the grid header configuration as well as displaying data within the grid itself. If the
21  * {@link #columns} configuration is specified, this column will become a column group and can
22  * contain other columns inside. In general, this class will not be created directly, rather
23  * an array of column configurations will be passed to the grid:
24  *
25  *     @example
26  *     Ext.create('Ext.data.Store', {
27  *         storeId:'employeeStore',
28  *         fields:['firstname', 'lastname', 'senority', 'dep', 'hired'],
29  *         data:[
30  *             {firstname:&quot;Michael&quot;, lastname:&quot;Scott&quot;, senority:7, dep:&quot;Manangement&quot;, hired:&quot;01/10/2004&quot;},
31  *             {firstname:&quot;Dwight&quot;, lastname:&quot;Schrute&quot;, senority:2, dep:&quot;Sales&quot;, hired:&quot;04/01/2004&quot;},
32  *             {firstname:&quot;Jim&quot;, lastname:&quot;Halpert&quot;, senority:3, dep:&quot;Sales&quot;, hired:&quot;02/22/2006&quot;},
33  *             {firstname:&quot;Kevin&quot;, lastname:&quot;Malone&quot;, senority:4, dep:&quot;Accounting&quot;, hired:&quot;06/10/2007&quot;},
34  *             {firstname:&quot;Angela&quot;, lastname:&quot;Martin&quot;, senority:5, dep:&quot;Accounting&quot;, hired:&quot;10/21/2008&quot;}
35  *         ]
36  *     });
37  *
38  *     Ext.create('Ext.grid.Panel', {
39  *         title: 'Column Demo',
40  *         store: Ext.data.StoreManager.lookup('employeeStore'),
41  *         columns: [
42  *             {text: 'First Name',  dataIndex:'firstname'},
43  *             {text: 'Last Name',  dataIndex:'lastname'},
44  *             {text: 'Hired Month',  dataIndex:'hired', xtype:'datecolumn', format:'M'},
45  *             {text: 'Department (Yrs)', xtype:'templatecolumn', tpl:'{dep} ({senority})'}
46  *         ],
47  *         width: 400,
48  *         renderTo: Ext.getBody()
49  *     });
50  *
51  * # Convenience Subclasses
52  *
53  * There are several column subclasses that provide default rendering for various data types
54  *
55  *  - {@link Ext.grid.column.Action}: Renders icons that can respond to click events inline
56  *  - {@link Ext.grid.column.Boolean}: Renders for boolean values
57  *  - {@link Ext.grid.column.Date}: Renders for date values
58  *  - {@link Ext.grid.column.Number}: Renders for numeric values
59  *  - {@link Ext.grid.column.Template}: Renders a value using an {@link Ext.XTemplate} using the record data
60  *
61  * # Setting Sizes
62  *
63  * The columns are laid out by a {@link Ext.layout.container.HBox} layout, so a column can either
64  * be given an explicit width value or a flex configuration. If no width is specified the grid will
65  * automatically the size the column to 100px. For column groups, the size is calculated by measuring
66  * the width of the child columns, so a width option should not be specified in that case.
67  *
68  * # Header Options
69  *
70  *  - {@link #text}: Sets the header text for the column
71  *  - {@link #sortable}: Specifies whether the column can be sorted by clicking the header or using the column menu
72  *  - {@link #hideable}: Specifies whether the column can be hidden using the column menu
73  *  - {@link #menuDisabled}: Disables the column header menu
74  *  - {@link #draggable}: Specifies whether the column header can be reordered by dragging
75  *  - {@link #groupable}: Specifies whether the grid can be grouped by the column dataIndex. See also {@link Ext.grid.feature.Grouping}
76  *
77  * # Data Options
78  *
79  *  - {@link #dataIndex}: The dataIndex is the field in the underlying {@link Ext.data.Store} to use as the value for the column.
80  *  - {@link #renderer}: Allows the underlying store value to be transformed before being displayed in the grid
81  */
82 Ext.define('Ext.grid.column.Column', {
83     extend: 'Ext.grid.header.Container',
84     alias: 'widget.gridcolumn',
85     requires: ['Ext.util.KeyNav'],
86     alternateClassName: 'Ext.grid.Column',
87
88     baseCls: Ext.baseCSSPrefix + 'column-header ' + Ext.baseCSSPrefix + 'unselectable',
89
90     // Not the standard, automatically applied overCls because we must filter out overs of child headers.
91     hoverCls: Ext.baseCSSPrefix + 'column-header-over',
92
93     handleWidth: 5,
94
95     sortState: null,
96
97     possibleSortStates: ['ASC', 'DESC'],
98
99     renderTpl:
100         '&lt;div id=&quot;{id}-titleContainer&quot; class=&quot;' + Ext.baseCSSPrefix + 'column-header-inner&quot;&gt;' +
101             '&lt;span id=&quot;{id}-textEl&quot; class=&quot;' + Ext.baseCSSPrefix + 'column-header-text&quot;&gt;' +
102                 '{text}' +
103             '&lt;/span&gt;' +
104             '&lt;tpl if=&quot;!values.menuDisabled&quot;&gt;'+
105                 '&lt;div id=&quot;{id}-triggerEl&quot; class=&quot;' + Ext.baseCSSPrefix + 'column-header-trigger&quot;&gt;&lt;/div&gt;'+
106             '&lt;/tpl&gt;' +
107         '&lt;/div&gt;',
108
109 <span id='Ext-grid-column-Column-cfg-columns'>    /**
110 </span>     * @cfg {Object[]} columns
111      * An optional array of sub-column definitions. This column becomes a group, and houses the columns defined in the
112      * `columns` config.
113      *
114      * Group columns may not be sortable. But they may be hideable and moveable. And you may move headers into and out
115      * of a group. Note that if all sub columns are dragged out of a group, the group is destroyed.
116      */
117
118 <span id='Ext-grid-column-Column-cfg-dataIndex'>    /**
119 </span>     * @cfg {String} dataIndex
120      * The name of the field in the grid's {@link Ext.data.Store}'s {@link Ext.data.Model} definition from
121      * which to draw the column's value. **Required.**
122      */
123     dataIndex: null,
124
125 <span id='Ext-grid-column-Column-cfg-text'>    /**
126 </span>     * @cfg {String} text
127      * The header text to be used as innerHTML (html tags are accepted) to display in the Grid.
128      * **Note**: to have a clickable header with no text displayed you can use the default of `&amp;#160;` aka `&amp;nbsp;`.
129      */
130     text: '&amp;#160;',
131
132 <span id='Ext-grid-column-Column-cfg-sortable'>    /**
133 </span>     * @cfg {Boolean} sortable
134      * False to disable sorting of this column. Whether local/remote sorting is used is specified in
135      * `{@link Ext.data.Store#remoteSort}`. Defaults to true.
136      */
137     sortable: true,
138
139 <span id='Ext-grid-column-Column-cfg-groupable'>    /**
140 </span>     * @cfg {Boolean} groupable
141      * If the grid uses a {@link Ext.grid.feature.Grouping}, this option may be used to disable the header menu
142      * item to group by the column selected. By default, the header menu group option is enabled. Set to false to
143      * disable (but still show) the group option in the header menu for the column.
144      */
145
146 <span id='Ext-grid-column-Column-cfg-fixed'>    /**
147 </span>     * @cfg {Boolean} fixed
148      * @deprecated.
149      * True to prevent the column from being resizable.
150      */
151
152 <span id='Ext-grid-column-Column-cfg-resizable'>    /**
153 </span>     * @cfg {Boolean} resizable
154      * Set to &lt;code&gt;false&lt;/code&gt; to prevent the column from being resizable. Defaults to &lt;code&gt;true&lt;/code&gt;
155      */
156
157 <span id='Ext-grid-column-Column-cfg-hideable'>    /**
158 </span>     * @cfg {Boolean} hideable
159      * False to prevent the user from hiding this column. Defaults to true.
160      */
161     hideable: true,
162
163 <span id='Ext-grid-column-Column-cfg-menuDisabled'>    /**
164 </span>     * @cfg {Boolean} menuDisabled
165      * True to disable the column header menu containing sort/hide options. Defaults to false.
166      */
167     menuDisabled: false,
168
169 <span id='Ext-grid-column-Column-cfg-renderer'>    /**
170 </span>     * @cfg {Function} renderer
171      * A renderer is an 'interceptor' method which can be used transform data (value, appearance, etc.)
172      * before it is rendered. Example:
173      *
174      *     {
175      *         renderer: function(value){
176      *             if (value === 1) {
177      *                 return '1 person';
178      *             }
179      *             return value + ' people';
180      *         }
181      *     }
182      *
183      * @cfg {Object} renderer.value The data value for the current cell
184      * @cfg {Object} renderer.metaData A collection of metadata about the current cell; can be used or modified
185      * by the renderer. Recognized properties are: tdCls, tdAttr, and style.
186      * @cfg {Ext.data.Model} renderer.record The record for the current row
187      * @cfg {Number} renderer.rowIndex The index of the current row
188      * @cfg {Number} renderer.colIndex The index of the current column
189      * @cfg {Ext.data.Store} renderer.store The data store
190      * @cfg {Ext.view.View} renderer.view The current view
191      * @cfg {String} renderer.return The HTML string to be rendered.
192      */
193     renderer: false,
194
195 <span id='Ext-grid-column-Column-cfg-align'>    /**
196 </span>     * @cfg {String} align
197      * Sets the alignment of the header and rendered columns. Defaults to 'left'.
198      */
199     align: 'left',
200
201 <span id='Ext-grid-column-Column-cfg-draggable'>    /**
202 </span>     * @cfg {Boolean} draggable
203      * False to disable drag-drop reordering of this column. Defaults to true.
204      */
205     draggable: true,
206
207     // Header does not use the typical ComponentDraggable class and therefore we
208     // override this with an emptyFn. It is controlled at the HeaderDragZone.
209     initDraggable: Ext.emptyFn,
210
211 <span id='Ext-grid-column-Column-cfg-tdCls'>    /**
212 </span>     * @cfg {String} tdCls
213      * A CSS class names to apply to the table cells for this column.
214      */
215
216 <span id='Ext-grid-column-Column-cfg-editor'>    /**
217 </span>     * @cfg {Object/String} editor
218      * An optional xtype or config object for a {@link Ext.form.field.Field Field} to use for editing.
219      * Only applicable if the grid is using an {@link Ext.grid.plugin.Editing Editing} plugin.
220      */
221
222 <span id='Ext-grid-column-Column-cfg-field'>    /**
223 </span>     * @cfg {Object/String} field
224      * Alias for {@link #editor}.
225      * @deprecated 4.0.5 Use {@link #editor} instead.
226      */
227
228 <span id='Ext-grid-column-Column-property-triggerEl'>    /**
229 </span>     * @property {Ext.Element} triggerEl
230      * Element that acts as button for column header dropdown menu.
231      */
232
233 <span id='Ext-grid-column-Column-property-textEl'>    /**
234 </span>     * @property {Ext.Element} textEl
235      * Element that contains the text in column header.
236      */
237
238 <span id='Ext-grid-column-Column-property-isHeader'>    /**
239 </span>     * @private
240      * Set in this class to identify, at runtime, instances which are not instances of the
241      * HeaderContainer base class, but are in fact, the subclass: Header.
242      */
243     isHeader: true,
244
245     initComponent: function() {
246         var me = this,
247             i,
248             len,
249             item;
250
251         if (Ext.isDefined(me.header)) {
252             me.text = me.header;
253             delete me.header;
254         }
255
256         // Flexed Headers need to have a minWidth defined so that they can never be squeezed out of existence by the
257         // HeaderContainer's specialized Box layout, the ColumnLayout. The ColumnLayout's overridden calculateChildboxes
258         // method extends the available layout space to accommodate the &quot;desiredWidth&quot; of all the columns.
259         if (me.flex) {
260             me.minWidth = me.minWidth || Ext.grid.plugin.HeaderResizer.prototype.minColWidth;
261         }
262         // Non-flexed Headers may never be squeezed in the event of a shortfall so
263         // always set their minWidth to their current width.
264         else {
265             me.minWidth = me.width;
266         }
267
268         if (!me.triStateSort) {
269             me.possibleSortStates.length = 2;
270         }
271
272         // A group header; It contains items which are themselves Headers
273         if (Ext.isDefined(me.columns)) {
274             me.isGroupHeader = true;
275
276             //&lt;debug&gt;
277             if (me.dataIndex) {
278                 Ext.Error.raise('Ext.grid.column.Column: Group header may not accept a dataIndex');
279             }
280             if ((me.width &amp;&amp; me.width !== Ext.grid.header.Container.prototype.defaultWidth) || me.flex) {
281                 Ext.Error.raise('Ext.grid.column.Column: Group header does not support setting explicit widths or flexs. The group header width is calculated by the sum of its children.');
282             }
283             //&lt;/debug&gt;
284
285             // The headers become child items
286             me.items = me.columns;
287             delete me.columns;
288             delete me.flex;
289             me.width = 0;
290
291             // Acquire initial width from sub headers
292             for (i = 0, len = me.items.length; i &lt; len; i++) {
293                 item = me.items[i];
294                 if (!item.hidden) {
295                     me.width += item.width || Ext.grid.header.Container.prototype.defaultWidth;
296                 }
297                 //&lt;debug&gt;
298                 if (item.flex) {
299                     Ext.Error.raise('Ext.grid.column.Column: items of a grouped header do not support flexed values. Each item must explicitly define its width.');
300                 }
301                 //&lt;/debug&gt;
302             }
303             me.minWidth = me.width;
304
305             me.cls = (me.cls||'') + ' ' + Ext.baseCSSPrefix + 'group-header';
306             me.sortable = false;
307             me.resizable = false;
308             me.align = 'center';
309         }
310
311         me.addChildEls('titleContainer', 'triggerEl', 'textEl');
312
313         // Initialize as a HeaderContainer
314         me.callParent(arguments);
315     },
316
317     onAdd: function(childHeader) {
318         childHeader.isSubHeader = true;
319         childHeader.addCls(Ext.baseCSSPrefix + 'group-sub-header');
320         this.callParent(arguments);
321     },
322
323     onRemove: function(childHeader) {
324         childHeader.isSubHeader = false;
325         childHeader.removeCls(Ext.baseCSSPrefix + 'group-sub-header');
326         this.callParent(arguments);
327     },
328
329     initRenderData: function() {
330         var me = this;
331
332         Ext.applyIf(me.renderData, {
333             text: me.text,
334             menuDisabled: me.menuDisabled
335         });
336         return me.callParent(arguments);
337     },
338
339     applyColumnState: function (state) {
340         var me = this,
341             defined = Ext.isDefined;
342             
343         // apply any columns
344         me.applyColumnsState(state.columns);
345
346         // Only state properties which were saved should be restored.
347         // (Only user-changed properties were saved by getState)
348         if (defined(state.hidden)) {
349             me.hidden = state.hidden;
350         }
351         if (defined(state.locked)) {
352             me.locked = state.locked;
353         }
354         if (defined(state.sortable)) {
355             me.sortable = state.sortable;
356         }
357         if (defined(state.width)) {
358             delete me.flex;
359             me.width = state.width;
360         } else if (defined(state.flex)) {
361             delete me.width;
362             me.flex = state.flex;
363         }
364     },
365
366     getColumnState: function () {
367         var me = this,
368             columns = [],
369             state = {
370                 id: me.headerId
371             };
372
373         me.savePropsToState(['hidden', 'sortable', 'locked', 'flex', 'width'], state);
374         
375         if (me.isGroupHeader) {
376             me.items.each(function(column){
377                 columns.push(column.getColumnState());
378             });
379             if (columns.length) {
380                 state.columns = columns;
381             }
382         } else if (me.isSubHeader &amp;&amp; me.ownerCt.hidden) {
383             // don't set hidden on the children so they can auto height
384             delete me.hidden;
385         }
386
387         if ('width' in state) {
388             delete state.flex; // width wins
389         }
390         return state;
391     },
392
393 <span id='Ext-grid-column-Column-method-setText'>    /**
394 </span>     * Sets the header text for this Column.
395      * @param {String} text The header to display on this Column.
396      */
397     setText: function(text) {
398         this.text = text;
399         if (this.rendered) {
400             this.textEl.update(text);
401         }
402     },
403
404     // Find the topmost HeaderContainer: An ancestor which is NOT a Header.
405     // Group Headers are themselves HeaderContainers
406     getOwnerHeaderCt: function() {
407         return this.up(':not([isHeader])');
408     },
409
410 <span id='Ext-grid-column-Column-method-getIndex'>    /**
411 </span>     * Returns the true grid column index associated with this column only if this column is a base level Column. If it
412      * is a group column, it returns `false`.
413      * @return {Number}
414      */
415     getIndex: function() {
416         return this.isGroupColumn ? false : this.getOwnerHeaderCt().getHeaderIndex(this);
417     },
418
419     onRender: function() {
420         var me = this,
421             grid = me.up('tablepanel');
422
423         // Disable the menu if there's nothing to show in the menu, ie:
424         // Column cannot be sorted, grouped or locked, and there are no grid columns which may be hidden
425         if (grid &amp;&amp; (!me.sortable || grid.sortableColumns === false) &amp;&amp; !me.groupable &amp;&amp; !me.lockable &amp;&amp; (grid.enableColumnHide === false || !me.getOwnerHeaderCt().getHideableColumns().length)) {
426             me.menuDisabled = true;
427         }
428         me.callParent(arguments);
429     },
430
431     afterRender: function() {
432         var me = this,
433             el = me.el;
434
435         me.callParent(arguments);
436
437         el.addCls(Ext.baseCSSPrefix + 'column-header-align-' + me.align).addClsOnOver(me.overCls);
438
439         me.mon(el, {
440             click:     me.onElClick,
441             dblclick:  me.onElDblClick,
442             scope:     me
443         });
444
445         // BrowserBug: Ie8 Strict Mode, this will break the focus for this browser,
446         // must be fixed when focus management will be implemented.
447         if (!Ext.isIE8 || !Ext.isStrict) {
448             me.mon(me.getFocusEl(), {
449                 focus: me.onTitleMouseOver,
450                 blur: me.onTitleMouseOut,
451                 scope: me
452             });
453         }
454
455         me.mon(me.titleContainer, {
456             mouseenter:  me.onTitleMouseOver,
457             mouseleave:  me.onTitleMouseOut,
458             scope:      me
459         });
460
461         me.keyNav = Ext.create('Ext.util.KeyNav', el, {
462             enter: me.onEnterKey,
463             down: me.onDownKey,
464             scope: me
465         });
466     },
467
468 <span id='Ext-grid-column-Column-method-setWidth'>    /**
469 </span>     * Sets the width of this Column.
470      * @param {Number} width New width.
471      */
472     setWidth: function(width, /* private - used internally */ doLayout) {
473         var me = this,
474             headerCt = me.ownerCt,
475             siblings,
476             len, i,
477             oldWidth = me.getWidth(),
478             groupWidth = 0,
479             sibling;
480
481         if (width !== oldWidth) {
482             me.oldWidth = oldWidth;
483
484             // Non-flexed Headers may never be squeezed in the event of a shortfall so
485             // always set the minWidth to their current width.
486             me.minWidth = me.width = width;
487
488             // Bubble size changes upwards to group headers
489             if (headerCt.isGroupHeader) {
490                 siblings = headerCt.items.items;
491                 len = siblings.length;
492
493                 for (i = 0; i &lt; len; i++) {
494                     sibling = siblings[i];
495                     if (!sibling.hidden) {
496                         groupWidth += (sibling === me) ? width : sibling.getWidth();
497                     }
498                 }
499                 headerCt.setWidth(groupWidth, doLayout);
500             } else if (doLayout !== false) {
501                 // Allow the owning Container to perform the sizing
502                 headerCt.doLayout();
503             }
504         }
505     },
506
507     afterComponentLayout: function(width, height) {
508         var me = this,
509             ownerHeaderCt = this.getOwnerHeaderCt();
510
511         me.callParent(arguments);
512
513         // Only changes at the base level inform the grid's HeaderContainer which will update the View
514         // Skip this if the width is null or undefined which will be the Box layout's initial pass  through the child Components
515         // Skip this if it's the initial size setting in which case there is no ownerheaderCt yet - that is set afterRender
516         if (width &amp;&amp; !me.isGroupHeader &amp;&amp; ownerHeaderCt) {
517             ownerHeaderCt.onHeaderResize(me, width, true);
518         }
519         if (me.oldWidth &amp;&amp; (width !== me.oldWidth)) {
520             ownerHeaderCt.fireEvent('columnresize', ownerHeaderCt, this, width);
521         }
522         delete me.oldWidth;
523     },
524
525     // private
526     // After the container has laid out and stretched, it calls this to correctly pad the inner to center the text vertically
527     // Total available header height must be passed to enable padding for inner elements to be calculated.
528     setPadding: function(headerHeight) {
529         var me = this,
530             lineHeight = Ext.util.TextMetrics.measure(me.textEl.dom, me.text).height;
531
532         // Top title containing element must stretch to match height of sibling group headers
533         if (!me.isGroupHeader) {
534             if (me.titleContainer.getHeight() &lt; headerHeight) {
535                 me.titleContainer.dom.style.height = headerHeight + 'px';
536             }
537         }
538         headerHeight = me.titleContainer.getViewSize().height;
539
540         // Vertically center the header text in potentially vertically stretched header
541         if (lineHeight) {
542             me.titleContainer.setStyle({
543                 paddingTop: Math.max(((headerHeight - lineHeight) / 2), 0) + 'px'
544             });
545         }
546
547         // Only IE needs this
548         if (Ext.isIE &amp;&amp; me.triggerEl) {
549             me.triggerEl.setHeight(headerHeight);
550         }
551     },
552
553     onDestroy: function() {
554         var me = this;
555         // force destroy on the textEl, IE reports a leak
556         Ext.destroy(me.textEl, me.keyNav);
557         delete me.keyNav;
558         me.callParent(arguments);
559     },
560
561     onTitleMouseOver: function() {
562         this.titleContainer.addCls(this.hoverCls);
563     },
564
565     onTitleMouseOut: function() {
566         this.titleContainer.removeCls(this.hoverCls);
567     },
568
569     onDownKey: function(e) {
570         if (this.triggerEl) {
571             this.onElClick(e, this.triggerEl.dom || this.el.dom);
572         }
573     },
574
575     onEnterKey: function(e) {
576         this.onElClick(e, this.el.dom);
577     },
578
579 <span id='Ext-grid-column-Column-method-onElDblClick'>    /**
580 </span>     * @private
581      * Double click
582      * @param e
583      * @param t
584      */
585     onElDblClick: function(e, t) {
586         var me = this,
587             ownerCt = me.ownerCt;
588         if (ownerCt &amp;&amp; Ext.Array.indexOf(ownerCt.items, me) !== 0 &amp;&amp; me.isOnLeftEdge(e) ) {
589             ownerCt.expandToFit(me.previousSibling('gridcolumn'));
590         }
591     },
592
593     onElClick: function(e, t) {
594
595         // The grid's docked HeaderContainer.
596         var me = this,
597             ownerHeaderCt = me.getOwnerHeaderCt();
598
599         if (ownerHeaderCt &amp;&amp; !ownerHeaderCt.ddLock) {
600             // Firefox doesn't check the current target in a within check.
601             // Therefore we check the target directly and then within (ancestors)
602             if (me.triggerEl &amp;&amp; (e.target === me.triggerEl.dom || t === me.triggerEl.dom || e.within(me.triggerEl))) {
603                 ownerHeaderCt.onHeaderTriggerClick(me, e, t);
604             // if its not on the left hand edge, sort
605             } else if (e.getKey() || (!me.isOnLeftEdge(e) &amp;&amp; !me.isOnRightEdge(e))) {
606                 me.toggleSortState();
607                 ownerHeaderCt.onHeaderClick(me, e, t);
608             }
609         }
610     },
611
612 <span id='Ext-grid-column-Column-method-processEvent'>    /**
613 </span>     * @private
614      * Process UI events from the view. The owning TablePanel calls this method, relaying events from the TableView
615      * @param {String} type Event type, eg 'click'
616      * @param {Ext.view.Table} view TableView Component
617      * @param {HTMLElement} cell Cell HtmlElement the event took place within
618      * @param {Number} recordIndex Index of the associated Store Model (-1 if none)
619      * @param {Number} cellIndex Cell index within the row
620      * @param {Ext.EventObject} e Original event
621      */
622     processEvent: function(type, view, cell, recordIndex, cellIndex, e) {
623         return this.fireEvent.apply(this, arguments);
624     },
625
626     toggleSortState: function() {
627         var me = this,
628             idx,
629             nextIdx;
630
631         if (me.sortable) {
632             idx = Ext.Array.indexOf(me.possibleSortStates, me.sortState);
633
634             nextIdx = (idx + 1) % me.possibleSortStates.length;
635             me.setSortState(me.possibleSortStates[nextIdx]);
636         }
637     },
638
639     doSort: function(state) {
640         var ds = this.up('tablepanel').store;
641         ds.sort({
642             property: this.getSortParam(),
643             direction: state
644         });
645     },
646
647 <span id='Ext-grid-column-Column-method-getSortParam'>    /**
648 </span>     * Returns the parameter to sort upon when sorting this header. By default this returns the dataIndex and will not
649      * need to be overriden in most cases.
650      * @return {String}
651      */
652     getSortParam: function() {
653         return this.dataIndex;
654     },
655
656     //setSortState: function(state, updateUI) {
657     //setSortState: function(state, doSort) {
658     setSortState: function(state, skipClear, initial) {
659         var me = this,
660             colSortClsPrefix = Ext.baseCSSPrefix + 'column-header-sort-',
661             ascCls = colSortClsPrefix + 'ASC',
662             descCls = colSortClsPrefix + 'DESC',
663             nullCls = colSortClsPrefix + 'null',
664             ownerHeaderCt = me.getOwnerHeaderCt(),
665             oldSortState = me.sortState;
666
667         if (oldSortState !== state &amp;&amp; me.getSortParam()) {
668             me.addCls(colSortClsPrefix + state);
669             // don't trigger a sort on the first time, we just want to update the UI
670             if (state &amp;&amp; !initial) {
671                 me.doSort(state);
672             }
673             switch (state) {
674                 case 'DESC':
675                     me.removeCls([ascCls, nullCls]);
676                     break;
677                 case 'ASC':
678                     me.removeCls([descCls, nullCls]);
679                     break;
680                 case null:
681                     me.removeCls([ascCls, descCls]);
682                     break;
683             }
684             if (ownerHeaderCt &amp;&amp; !me.triStateSort &amp;&amp; !skipClear) {
685                 ownerHeaderCt.clearOtherSortStates(me);
686             }
687             me.sortState = state;
688             ownerHeaderCt.fireEvent('sortchange', ownerHeaderCt, me, state);
689         }
690     },
691
692     hide: function() {
693         var me = this,
694             items,
695             len, i,
696             lb,
697             newWidth = 0,
698             ownerHeaderCt = me.getOwnerHeaderCt();
699
700         // Hiding means setting to zero width, so cache the width
701         me.oldWidth = me.getWidth();
702
703         // Hiding a group header hides itself, and then informs the HeaderContainer about its sub headers (Suppressing header layout)
704         if (me.isGroupHeader) {
705             items = me.items.items;
706             me.callParent(arguments);
707             ownerHeaderCt.onHeaderHide(me);
708             for (i = 0, len = items.length; i &lt; len; i++) {
709                 items[i].hidden = true;
710                 ownerHeaderCt.onHeaderHide(items[i], true);
711             }
712             return;
713         }
714
715         // TODO: Work with Jamie to produce a scheme where we can show/hide/resize without triggering a layout cascade
716         lb = me.ownerCt.componentLayout.layoutBusy;
717         me.ownerCt.componentLayout.layoutBusy = true;
718         me.callParent(arguments);
719         me.ownerCt.componentLayout.layoutBusy = lb;
720
721         // Notify owning HeaderContainer
722         ownerHeaderCt.onHeaderHide(me);
723
724         if (me.ownerCt.isGroupHeader) {
725             // If we've just hidden the last header in a group, then hide the group
726             items = me.ownerCt.query('&gt;:not([hidden])');
727             if (!items.length) {
728                 me.ownerCt.hide();
729             }
730             // Size the group down to accommodate fewer sub headers
731             else {
732                 for (i = 0, len = items.length; i &lt; len; i++) {
733                     newWidth += items[i].getWidth();
734                 }
735                 me.ownerCt.minWidth = newWidth;
736                 me.ownerCt.setWidth(newWidth);
737             }
738         }
739     },
740
741     show: function() {
742         var me = this,
743             ownerCt = me.ownerCt,
744             ownerCtCompLayout = ownerCt.componentLayout,
745             ownerCtCompLayoutBusy = ownerCtCompLayout.layoutBusy,
746             ownerCtLayout = ownerCt.layout,
747             ownerCtLayoutBusy = ownerCtLayout.layoutBusy,
748             items,
749             len, i,
750             item,
751             newWidth = 0;
752
753         // TODO: Work with Jamie to produce a scheme where we can show/hide/resize without triggering a layout cascade
754
755         // Suspend our owner's layouts (both component and container):
756         ownerCtCompLayout.layoutBusy = ownerCtLayout.layoutBusy = true;
757
758         me.callParent(arguments);
759
760         ownerCtCompLayout.layoutBusy = ownerCtCompLayoutBusy;
761         ownerCtLayout.layoutBusy = ownerCtLayoutBusy;
762
763         // If a sub header, ensure that the group header is visible
764         if (me.isSubHeader) {
765             if (!ownerCt.isVisible()) {
766                 ownerCt.show();
767             }
768         }
769
770         // If we've just shown a group with all its sub headers hidden, then show all its sub headers
771         if (me.isGroupHeader &amp;&amp; !me.query(':not([hidden])').length) {
772             items = me.query('&gt;*');
773             for (i = 0, len = items.length; i &lt; len; i++) {
774                 item = items[i];
775                 item.preventLayout = true;
776                 item.show();
777                 newWidth += item.getWidth();
778                 delete item.preventLayout;
779             }
780             me.setWidth(newWidth);
781         }
782
783         // Resize the owning group to accommodate
784         if (ownerCt.isGroupHeader &amp;&amp; me.preventLayout !== true) {
785             items = ownerCt.query('&gt;:not([hidden])');
786             for (i = 0, len = items.length; i &lt; len; i++) {
787                 newWidth += items[i].getWidth();
788             }
789             ownerCt.minWidth = newWidth;
790             ownerCt.setWidth(newWidth);
791         }
792
793         // Notify owning HeaderContainer
794         ownerCt = me.getOwnerHeaderCt();
795         if (ownerCt) {
796             ownerCt.onHeaderShow(me, me.preventLayout);
797         }
798     },
799
800     getDesiredWidth: function() {
801         var me = this;
802         if (me.rendered &amp;&amp; me.componentLayout &amp;&amp; me.componentLayout.lastComponentSize) {
803             // headers always have either a width or a flex
804             // because HeaderContainer sets a defaults width
805             // therefore we can ignore the natural width
806             // we use the componentLayout's tracked width so that
807             // we can calculate the desired width when rendered
808             // but not visible because its being obscured by a layout
809             return me.componentLayout.lastComponentSize.width;
810         // Flexed but yet to be rendered this could be the case
811         // where a HeaderContainer and Headers are simply used as data
812         // structures and not rendered.
813         }
814         else if (me.flex) {
815             // this is going to be wrong, the defaultWidth
816             return me.width;
817         }
818         else {
819             return me.width;
820         }
821     },
822
823     getCellSelector: function() {
824         return '.' + Ext.baseCSSPrefix + 'grid-cell-' + this.getItemId();
825     },
826
827     getCellInnerSelector: function() {
828         return this.getCellSelector() + ' .' + Ext.baseCSSPrefix + 'grid-cell-inner';
829     },
830
831     isOnLeftEdge: function(e) {
832         return (e.getXY()[0] - this.el.getLeft() &lt;= this.handleWidth);
833     },
834
835     isOnRightEdge: function(e) {
836         return (this.el.getRight() - e.getXY()[0] &lt;= this.handleWidth);
837     }
838
839     // intentionally omit getEditor and setEditor definitions bc we applyIf into columns
840     // when the editing plugin is injected
841
842 <span id='Ext-grid-column-Column-method-getEditor'>    /**
843 </span>     * @method getEditor
844      * Retrieves the editing field for editing associated with this header. Returns false if there is no field
845      * associated with the Header the method will return false. If the field has not been instantiated it will be
846      * created. Note: These methods only has an implementation if a Editing plugin has been enabled on the grid.
847      * @param {Object} record The {@link Ext.data.Model Model} instance being edited.
848      * @param {Object} defaultField An object representing a default field to be created
849      * @return {Ext.form.field.Field} field
850      */
851 <span id='Ext-grid-column-Column-method-setEditor'>    /**
852 </span>     * @method setEditor
853      * Sets the form field to be used for editing. Note: This method only has an implementation if an Editing plugin has
854      * been enabled on the grid.
855      * @param {Object} field An object representing a field to be created. If no xtype is specified a 'textfield' is
856      * assumed.
857      */
858 });
859 </pre>
860 </body>
861 </html>