Upgrade to ExtJS 4.0.1 - Released 05/18/2011
[extjs.git] / src / selection / CheckboxModel.js
1 /**
2  * @class Ext.selection.CheckboxModel
3  * @extends Ext.selection.RowModel
4  *
5  * A selection model that renders a column of checkboxes that can be toggled to
6  * select or deselect rows. The default mode for this selection model is MULTI.
7  *
8  * The selection model will inject a header for the checkboxes in the first view
9  * and according to the 'injectCheckbox' configuration.
10  */
11 Ext.define('Ext.selection.CheckboxModel', {
12     alias: 'selection.checkboxmodel',
13     extend: 'Ext.selection.RowModel',
14
15     /**
16      * @cfg {String} mode
17      * Modes of selection.
18      * Valid values are SINGLE, SIMPLE, and MULTI. Defaults to 'MULTI'
19      */
20     mode: 'MULTI',
21
22     /**
23      * @cfg {Mixed} injectCheckbox
24      * Instructs the SelectionModel whether or not to inject the checkbox header
25      * automatically or not. (Note: By not placing the checkbox in manually, the
26      * grid view will need to be rendered 2x on initial render.)
27      * Supported values are a Number index, false and the strings 'first' and 'last'.
28      * Default is 0.
29      */
30     injectCheckbox: 0,
31
32     /**
33      * @cfg {Boolean} checkOnly <tt>true</tt> if rows can only be selected by clicking on the
34      * checkbox column (defaults to <tt>false</tt>).
35      */
36     checkOnly: false,
37
38     // private
39     checkerOnCls: Ext.baseCSSPrefix + 'grid-hd-checker-on',
40
41     bindComponent: function() {
42         this.sortable = false;
43         this.callParent(arguments);
44
45         var view     = this.views[0],
46             headerCt = view.headerCt;
47
48         if (this.injectCheckbox !== false) {
49             if (this.injectCheckbox == 'first') {
50                 this.injectCheckbox = 0;
51             } else if (this.injectCheckbox == 'last') {
52                 this.injectCheckbox = headerCt.getColumnCount();
53             }
54             headerCt.add(this.injectCheckbox,  this.getHeaderConfig());
55         }
56         headerCt.on('headerclick', this.onHeaderClick, this);
57     },
58
59     /**
60      * Toggle the ui header between checked and unchecked state.
61      * @param {Boolean} isChecked
62      * @private
63      */
64     toggleUiHeader: function(isChecked) {
65         var view     = this.views[0],
66             headerCt = view.headerCt,
67             checkHd  = headerCt.child('gridcolumn[isCheckerHd]');
68
69         if (checkHd) {
70             if (isChecked) {
71                 checkHd.el.addCls(this.checkerOnCls);
72             } else {
73                 checkHd.el.removeCls(this.checkerOnCls);
74             }
75         }
76     },
77
78     /**
79      * Toggle between selecting all and deselecting all when clicking on
80      * a checkbox header.
81      */
82     onHeaderClick: function(headerCt, header, e) {
83         if (header.isCheckerHd) {
84             e.stopEvent();
85             var isChecked = header.el.hasCls(Ext.baseCSSPrefix + 'grid-hd-checker-on');
86             if (isChecked) {
87                 // We have to supress the event or it will scrollTo the change
88                 this.deselectAll(true);
89             } else {
90                 // We have to supress the event or it will scrollTo the change
91                 this.selectAll(true);
92             }
93         }
94     },
95
96     /**
97      * Retrieve a configuration to be used in a HeaderContainer.
98      * This should be used when injectCheckbox is set to false.
99      */
100     getHeaderConfig: function() {
101         return {
102             isCheckerHd: true,
103             text : '&#160;',
104             width: 24,
105             sortable: false,
106             fixed: true,
107             hideable: false,
108             menuDisabled: true,
109             dataIndex: '',
110             cls: Ext.baseCSSPrefix + 'column-header-checkbox ',
111             renderer: Ext.Function.bind(this.renderer, this)
112         };
113     },
114
115     /**
116      * Generates the HTML to be rendered in the injected checkbox column for each row.
117      * Creates the standard checkbox markup by default; can be overridden to provide custom rendering.
118      * See {@link Ext.grid.column.Column#renderer} for description of allowed parameters.
119      */
120     renderer: function(value, metaData, record, rowIndex, colIndex, store, view) {
121         metaData.tdCls = Ext.baseCSSPrefix + 'grid-cell-special';
122         return '<div class="' + Ext.baseCSSPrefix + 'grid-row-checker">&#160;</div>';
123     },
124
125     // override
126     onRowMouseDown: function(view, record, item, index, e) {
127         view.el.focus();
128         var me = this,
129             checker = e.getTarget('.' + Ext.baseCSSPrefix + 'grid-row-checker');
130
131         // checkOnly set, but we didn't click on a checker.
132         if (me.checkOnly && !checker) {
133             return;
134         }
135
136         if (checker) {
137             var mode = me.getSelectionMode();
138             // dont change the mode if its single otherwise
139             // we would get multiple selection
140             if (mode !== 'SINGLE') {
141                 me.setSelectionMode('SIMPLE');
142             }
143             me.selectWithEvent(record, e);
144             me.setSelectionMode(mode);
145         } else {
146             me.selectWithEvent(record, e);
147         }
148     },
149
150     /**
151      * Synchronize header checker value as selection changes.
152      * @private
153      */
154     onSelectChange: function(record, isSelected) {
155         this.callParent([record, isSelected]);
156         // check to see if all records are selected
157         var hdSelectStatus = this.selected.getCount() === this.store.getCount();
158         this.toggleUiHeader(hdSelectStatus);
159     }
160 });