Upgrade to ExtJS 3.1.0 - Released 12/16/2009
[extjs.git] / docs / source / RowSelectionModel.html
1 <html>\r
2 <head>\r
3   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />    \r
4   <title>The source code</title>\r
5     <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />\r
6     <script type="text/javascript" src="../resources/prettify/prettify.js"></script>\r
7 </head>\r
8 <body  onload="prettyPrint();">\r
9     <pre class="prettyprint lang-js"><div id="cls-Ext.grid.RowSelectionModel"></div>/**
10  * @class Ext.grid.RowSelectionModel
11  * @extends Ext.grid.AbstractSelectionModel
12  * The default SelectionModel used by {@link Ext.grid.GridPanel}.
13  * It supports multiple selections and keyboard selection/navigation. The objects stored
14  * as selections and returned by {@link #getSelected}, and {@link #getSelections} are
15  * the {@link Ext.data.Record Record}s which provide the data for the selected rows.
16  * @constructor
17  * @param {Object} config
18  */
19 Ext.grid.RowSelectionModel = Ext.extend(Ext.grid.AbstractSelectionModel,  {
20     <div id="cfg-Ext.grid.RowSelectionModel-singleSelect"></div>/**
21      * @cfg {Boolean} singleSelect
22      * <tt>true</tt> to allow selection of only one row at a time (defaults to <tt>false</tt>
23      * allowing multiple selections)
24      */
25     singleSelect : false,
26     
27     constructor : function(config){
28         Ext.apply(this, config);
29         this.selections = new Ext.util.MixedCollection(false, function(o){
30             return o.id;
31         });
32
33         this.last = false;
34         this.lastActive = false;
35
36         this.addEvents(
37                 <div id="event-Ext.grid.RowSelectionModel-selectionchange"></div>/**
38                  * @event selectionchange
39                  * Fires when the selection changes
40                  * @param {SelectionModel} this
41                  */
42                 'selectionchange',
43                 <div id="event-Ext.grid.RowSelectionModel-beforerowselect"></div>/**
44                  * @event beforerowselect
45                  * Fires before a row is selected, return false to cancel the selection.
46                  * @param {SelectionModel} this
47                  * @param {Number} rowIndex The index to be selected
48                  * @param {Boolean} keepExisting False if other selections will be cleared
49                  * @param {Record} record The record to be selected
50                  */
51                 'beforerowselect',
52                 <div id="event-Ext.grid.RowSelectionModel-rowselect"></div>/**
53                  * @event rowselect
54                  * Fires when a row is selected.
55                  * @param {SelectionModel} this
56                  * @param {Number} rowIndex The selected index
57                  * @param {Ext.data.Record} r The selected record
58                  */
59                 'rowselect',
60                 <div id="event-Ext.grid.RowSelectionModel-rowdeselect"></div>/**
61                  * @event rowdeselect
62                  * Fires when a row is deselected.  To prevent deselection
63                  * {@link Ext.grid.AbstractSelectionModel#lock lock the selections}. 
64                  * @param {SelectionModel} this
65                  * @param {Number} rowIndex
66                  * @param {Record} record
67                  */
68                 'rowdeselect'
69         );
70         Ext.grid.RowSelectionModel.superclass.constructor.call(this);
71     },
72
73     <div id="cfg-Ext.grid.RowSelectionModel-moveEditorOnEnter"></div>/**
74      * @cfg {Boolean} moveEditorOnEnter
75      * <tt>false</tt> to turn off moving the editor to the next row down when the enter key is pressed
76      * or the next row up when shift + enter keys are pressed.
77      */
78     // private
79     initEvents : function(){
80
81         if(!this.grid.enableDragDrop && !this.grid.enableDrag){
82             this.grid.on('rowmousedown', this.handleMouseDown, this);
83         }
84
85         this.rowNav = new Ext.KeyNav(this.grid.getGridEl(), {
86             'up' : function(e){
87                 if(!e.shiftKey || this.singleSelect){
88                     this.selectPrevious(false);
89                 }else if(this.last !== false && this.lastActive !== false){
90                     var last = this.last;
91                     this.selectRange(this.last,  this.lastActive-1);
92                     this.grid.getView().focusRow(this.lastActive);
93                     if(last !== false){
94                         this.last = last;
95                     }
96                 }else{
97                     this.selectFirstRow();
98                 }
99             },
100             'down' : function(e){
101                 if(!e.shiftKey || this.singleSelect){
102                     this.selectNext(false);
103                 }else if(this.last !== false && this.lastActive !== false){
104                     var last = this.last;
105                     this.selectRange(this.last,  this.lastActive+1);
106                     this.grid.getView().focusRow(this.lastActive);
107                     if(last !== false){
108                         this.last = last;
109                     }
110                 }else{
111                     this.selectFirstRow();
112                 }
113             },
114             scope: this
115         });
116
117         this.grid.getView().on({
118             scope: this,
119             refresh: this.onRefresh,
120             rowupdated: this.onRowUpdated,
121             rowremoved: this.onRemove
122         });
123     },
124
125     // private
126     onRefresh : function(){
127         var ds = this.grid.store, index;
128         var s = this.getSelections();
129         this.clearSelections(true);
130         for(var i = 0, len = s.length; i < len; i++){
131             var r = s[i];
132             if((index = ds.indexOfId(r.id)) != -1){
133                 this.selectRow(index, true);
134             }
135         }
136         if(s.length != this.selections.getCount()){
137             this.fireEvent('selectionchange', this);
138         }
139     },
140
141     // private
142     onRemove : function(v, index, r){
143         if(this.selections.remove(r) !== false){
144             this.fireEvent('selectionchange', this);
145         }
146     },
147
148     // private
149     onRowUpdated : function(v, index, r){
150         if(this.isSelected(r)){
151             v.onRowSelect(index);
152         }
153     },
154
155     <div id="method-Ext.grid.RowSelectionModel-selectRecords"></div>/**
156      * Select records.
157      * @param {Array} records The records to select
158      * @param {Boolean} keepExisting (optional) <tt>true</tt> to keep existing selections
159      */
160     selectRecords : function(records, keepExisting){
161         if(!keepExisting){
162             this.clearSelections();
163         }
164         var ds = this.grid.store;
165         for(var i = 0, len = records.length; i < len; i++){
166             this.selectRow(ds.indexOf(records[i]), true);
167         }
168     },
169
170     <div id="method-Ext.grid.RowSelectionModel-getCount"></div>/**
171      * Gets the number of selected rows.
172      * @return {Number}
173      */
174     getCount : function(){
175         return this.selections.length;
176     },
177
178     <div id="method-Ext.grid.RowSelectionModel-selectFirstRow"></div>/**
179      * Selects the first row in the grid.
180      */
181     selectFirstRow : function(){
182         this.selectRow(0);
183     },
184
185     <div id="method-Ext.grid.RowSelectionModel-selectLastRow"></div>/**
186      * Select the last row.
187      * @param {Boolean} keepExisting (optional) <tt>true</tt> to keep existing selections
188      */
189     selectLastRow : function(keepExisting){
190         this.selectRow(this.grid.store.getCount() - 1, keepExisting);
191     },
192
193     <div id="method-Ext.grid.RowSelectionModel-selectNext"></div>/**
194      * Selects the row immediately following the last selected row.
195      * @param {Boolean} keepExisting (optional) <tt>true</tt> to keep existing selections
196      * @return {Boolean} <tt>true</tt> if there is a next row, else <tt>false</tt>
197      */
198     selectNext : function(keepExisting){
199         if(this.hasNext()){
200             this.selectRow(this.last+1, keepExisting);
201             this.grid.getView().focusRow(this.last);
202             return true;
203         }
204         return false;
205     },
206
207     <div id="method-Ext.grid.RowSelectionModel-selectPrevious"></div>/**
208      * Selects the row that precedes the last selected row.
209      * @param {Boolean} keepExisting (optional) <tt>true</tt> to keep existing selections
210      * @return {Boolean} <tt>true</tt> if there is a previous row, else <tt>false</tt>
211      */
212     selectPrevious : function(keepExisting){
213         if(this.hasPrevious()){
214             this.selectRow(this.last-1, keepExisting);
215             this.grid.getView().focusRow(this.last);
216             return true;
217         }
218         return false;
219     },
220
221     <div id="method-Ext.grid.RowSelectionModel-hasNext"></div>/**
222      * Returns true if there is a next record to select
223      * @return {Boolean}
224      */
225     hasNext : function(){
226         return this.last !== false && (this.last+1) < this.grid.store.getCount();
227     },
228
229     <div id="method-Ext.grid.RowSelectionModel-hasPrevious"></div>/**
230      * Returns true if there is a previous record to select
231      * @return {Boolean}
232      */
233     hasPrevious : function(){
234         return !!this.last;
235     },
236
237
238     <div id="method-Ext.grid.RowSelectionModel-getSelections"></div>/**
239      * Returns the selected records
240      * @return {Array} Array of selected records
241      */
242     getSelections : function(){
243         return [].concat(this.selections.items);
244     },
245
246     <div id="method-Ext.grid.RowSelectionModel-getSelected"></div>/**
247      * Returns the first selected record.
248      * @return {Record}
249      */
250     getSelected : function(){
251         return this.selections.itemAt(0);
252     },
253
254     <div id="method-Ext.grid.RowSelectionModel-each"></div>/**
255      * Calls the passed function with each selection. If the function returns
256      * <tt>false</tt>, iteration is stopped and this function returns
257      * <tt>false</tt>. Otherwise it returns <tt>true</tt>.
258      * @param {Function} fn The function to call upon each iteration. It is passed the selected {@link Ext.data.Record Record}.
259      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to this RowSelectionModel.
260      * @return {Boolean} true if all selections were iterated
261      */
262     each : function(fn, scope){
263         var s = this.getSelections();
264         for(var i = 0, len = s.length; i < len; i++){
265             if(fn.call(scope || this, s[i], i) === false){
266                 return false;
267             }
268         }
269         return true;
270     },
271
272     <div id="method-Ext.grid.RowSelectionModel-clearSelections"></div>/**
273      * Clears all selections if the selection model
274      * {@link Ext.grid.AbstractSelectionModel#isLocked is not locked}.
275      * @param {Boolean} fast (optional) <tt>true</tt> to bypass the
276      * conditional checks and events described in {@link #deselectRow}.
277      */
278     clearSelections : function(fast){
279         if(this.isLocked()){
280             return;
281         }
282         if(fast !== true){
283             var ds = this.grid.store;
284             var s = this.selections;
285             s.each(function(r){
286                 this.deselectRow(ds.indexOfId(r.id));
287             }, this);
288             s.clear();
289         }else{
290             this.selections.clear();
291         }
292         this.last = false;
293     },
294
295
296     <div id="method-Ext.grid.RowSelectionModel-selectAll"></div>/**
297      * Selects all rows if the selection model
298      * {@link Ext.grid.AbstractSelectionModel#isLocked is not locked}. 
299      */
300     selectAll : function(){
301         if(this.isLocked()){
302             return;
303         }
304         this.selections.clear();
305         for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
306             this.selectRow(i, true);
307         }
308     },
309
310     <div id="method-Ext.grid.RowSelectionModel-hasSelection"></div>/**
311      * Returns <tt>true</tt> if there is a selection.
312      * @return {Boolean}
313      */
314     hasSelection : function(){
315         return this.selections.length > 0;
316     },
317
318     <div id="method-Ext.grid.RowSelectionModel-isSelected"></div>/**
319      * Returns <tt>true</tt> if the specified row is selected.
320      * @param {Number/Record} index The record or index of the record to check
321      * @return {Boolean}
322      */
323     isSelected : function(index){
324         var r = Ext.isNumber(index) ? this.grid.store.getAt(index) : index;
325         return (r && this.selections.key(r.id) ? true : false);
326     },
327
328     <div id="method-Ext.grid.RowSelectionModel-isIdSelected"></div>/**
329      * Returns <tt>true</tt> if the specified record id is selected.
330      * @param {String} id The id of record to check
331      * @return {Boolean}
332      */
333     isIdSelected : function(id){
334         return (this.selections.key(id) ? true : false);
335     },
336
337     // private
338     handleMouseDown : function(g, rowIndex, e){
339         if(e.button !== 0 || this.isLocked()){
340             return;
341         }
342         var view = this.grid.getView();
343         if(e.shiftKey && !this.singleSelect && this.last !== false){
344             var last = this.last;
345             this.selectRange(last, rowIndex, e.ctrlKey);
346             this.last = last; // reset the last
347             view.focusRow(rowIndex);
348         }else{
349             var isSelected = this.isSelected(rowIndex);
350             if(e.ctrlKey && isSelected){
351                 this.deselectRow(rowIndex);
352             }else if(!isSelected || this.getCount() > 1){
353                 this.selectRow(rowIndex, e.ctrlKey || e.shiftKey);
354                 view.focusRow(rowIndex);
355             }
356         }
357     },
358
359     <div id="method-Ext.grid.RowSelectionModel-selectRows"></div>/**
360      * Selects multiple rows.
361      * @param {Array} rows Array of the indexes of the row to select
362      * @param {Boolean} keepExisting (optional) <tt>true</tt> to keep
363      * existing selections (defaults to <tt>false</tt>)
364      */
365     selectRows : function(rows, keepExisting){
366         if(!keepExisting){
367             this.clearSelections();
368         }
369         for(var i = 0, len = rows.length; i < len; i++){
370             this.selectRow(rows[i], true);
371         }
372     },
373
374     <div id="method-Ext.grid.RowSelectionModel-selectRange"></div>/**
375      * Selects a range of rows if the selection model
376      * {@link Ext.grid.AbstractSelectionModel#isLocked is not locked}.
377      * All rows in between startRow and endRow are also selected.
378      * @param {Number} startRow The index of the first row in the range
379      * @param {Number} endRow The index of the last row in the range
380      * @param {Boolean} keepExisting (optional) True to retain existing selections
381      */
382     selectRange : function(startRow, endRow, keepExisting){
383         var i;
384         if(this.isLocked()){
385             return;
386         }
387         if(!keepExisting){
388             this.clearSelections();
389         }
390         if(startRow <= endRow){
391             for(i = startRow; i <= endRow; i++){
392                 this.selectRow(i, true);
393             }
394         }else{
395             for(i = startRow; i >= endRow; i--){
396                 this.selectRow(i, true);
397             }
398         }
399     },
400
401     <div id="method-Ext.grid.RowSelectionModel-deselectRange"></div>/**
402      * Deselects a range of rows if the selection model
403      * {@link Ext.grid.AbstractSelectionModel#isLocked is not locked}.  
404      * All rows in between startRow and endRow are also deselected.
405      * @param {Number} startRow The index of the first row in the range
406      * @param {Number} endRow The index of the last row in the range
407      */
408     deselectRange : function(startRow, endRow, preventViewNotify){
409         if(this.isLocked()){
410             return;
411         }
412         for(var i = startRow; i <= endRow; i++){
413             this.deselectRow(i, preventViewNotify);
414         }
415     },
416
417     <div id="method-Ext.grid.RowSelectionModel-selectRow"></div>/**
418      * Selects a row.  Before selecting a row, checks if the selection model
419      * {@link Ext.grid.AbstractSelectionModel#isLocked is locked} and fires the
420      * {@link #beforerowselect} event.  If these checks are satisfied the row
421      * will be selected and followed up by  firing the {@link #rowselect} and
422      * {@link #selectionchange} events.
423      * @param {Number} row The index of the row to select
424      * @param {Boolean} keepExisting (optional) <tt>true</tt> to keep existing selections
425      * @param {Boolean} preventViewNotify (optional) Specify <tt>true</tt> to
426      * prevent notifying the view (disables updating the selected appearance)
427      */
428     selectRow : function(index, keepExisting, preventViewNotify){
429         if(this.isLocked() || (index < 0 || index >= this.grid.store.getCount()) || (keepExisting && this.isSelected(index))){
430             return;
431         }
432         var r = this.grid.store.getAt(index);
433         if(r && this.fireEvent('beforerowselect', this, index, keepExisting, r) !== false){
434             if(!keepExisting || this.singleSelect){
435                 this.clearSelections();
436             }
437             this.selections.add(r);
438             this.last = this.lastActive = index;
439             if(!preventViewNotify){
440                 this.grid.getView().onRowSelect(index);
441             }
442             this.fireEvent('rowselect', this, index, r);
443             this.fireEvent('selectionchange', this);
444         }
445     },
446
447     <div id="method-Ext.grid.RowSelectionModel-deselectRow"></div>/**
448      * Deselects a row.  Before deselecting a row, checks if the selection model
449      * {@link Ext.grid.AbstractSelectionModel#isLocked is locked}.
450      * If this check is satisfied the row will be deselected and followed up by
451      * firing the {@link #rowdeselect} and {@link #selectionchange} events.
452      * @param {Number} row The index of the row to deselect
453      * @param {Boolean} preventViewNotify (optional) Specify <tt>true</tt> to
454      * prevent notifying the view (disables updating the selected appearance)
455      */
456     deselectRow : function(index, preventViewNotify){
457         if(this.isLocked()){
458             return;
459         }
460         if(this.last == index){
461             this.last = false;
462         }
463         if(this.lastActive == index){
464             this.lastActive = false;
465         }
466         var r = this.grid.store.getAt(index);
467         if(r){
468             this.selections.remove(r);
469             if(!preventViewNotify){
470                 this.grid.getView().onRowDeselect(index);
471             }
472             this.fireEvent('rowdeselect', this, index, r);
473             this.fireEvent('selectionchange', this);
474         }
475     },
476
477     // private
478     restoreLast : function(){
479         if(this._last){
480             this.last = this._last;
481         }
482     },
483
484     // private
485     acceptsNav : function(row, col, cm){
486         return !cm.isHidden(col) && cm.isCellEditable(col, row);
487     },
488
489     // private
490     onEditorKey : function(field, e){
491         var k = e.getKey(), 
492             newCell, 
493             g = this.grid, 
494             last = g.lastEdit,
495             ed = g.activeEditor,
496             ae, last, r, c;
497         var shift = e.shiftKey;
498         if(k == e.TAB){
499             e.stopEvent();
500             ed.completeEdit();
501             if(shift){
502                 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
503             }else{
504                 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
505             }
506         }else if(k == e.ENTER){
507             if(this.moveEditorOnEnter !== false){
508                 if(shift){
509                     newCell = g.walkCells(last.row - 1, last.col, -1, this.acceptsNav, this);
510                 }else{
511                     newCell = g.walkCells(last.row + 1, last.col, 1, this.acceptsNav, this);
512                 }
513             }
514         }
515         if(newCell){
516             r = newCell[0];
517             c = newCell[1];
518
519             if(last.row != r){
520                 this.selectRow(r); // *** highlight newly-selected cell and update selection
521             }
522
523             if(g.isEditor && g.editing){ // *** handle tabbing while editorgrid is in edit mode
524                 ae = g.activeEditor;
525                 if(ae && ae.field.triggerBlur){
526                     // *** if activeEditor is a TriggerField, explicitly call its triggerBlur() method
527                     ae.field.triggerBlur();
528                 }
529             }
530             g.startEditing(r, c);
531         }
532     },
533     
534     destroy : function(){
535         if(this.rowNav){
536             this.rowNav.disable();
537             this.rowNav = null;
538         }
539         Ext.grid.RowSelectionModel.superclass.destroy.call(this);
540     }
541 });</pre>    \r
542 </body>\r
543 </html>