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