4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
12 * @extends Roo.grid.AbstractSelectionModel
13 * @class Roo.grid.RowSelectionModel
14 * The default SelectionModel used by {@link Roo.grid.Grid}.
15 * It supports multiple selections and keyboard selection/navigation.
17 * @param {Object} config
19 Roo.grid.RowSelectionModel = function(config){
20 Roo.apply(this, config);
21 this.selections = new Roo.util.MixedCollection(false, function(o){
26 this.lastActive = false;
30 * @event selectionchange
31 * Fires when the selection changes
32 * @param {SelectionModel} this
34 "selectionchange" : true,
36 * @event afterselectionchange
37 * Fires after the selection changes (eg. by key press or clicking)
38 * @param {SelectionModel} this
40 "afterselectionchange" : true,
42 * @event beforerowselect
43 * Fires when a row is selected being selected, return false to cancel.
44 * @param {SelectionModel} this
45 * @param {Number} rowIndex The selected index
46 * @param {Boolean} keepExisting False if other selections will be cleared
48 "beforerowselect" : true,
51 * Fires when a row is selected.
52 * @param {SelectionModel} this
53 * @param {Number} rowIndex The selected index
54 * @param {Roo.data.Record} r The record
59 * Fires when a row is deselected.
60 * @param {SelectionModel} this
61 * @param {Number} rowIndex The selected index
65 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
69 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
71 * @cfg {Boolean} singleSelect
72 * True to allow selection of only one row at a time (defaults to false)
77 initEvents : function(){
79 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
80 this.grid.on("mousedown", this.handleMouseDown, this);
81 }else{ // allow click to work like normal
82 this.grid.on("rowclick", this.handleDragableRowClick, this);
85 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
88 this.selectPrevious(e.shiftKey);
89 }else if(this.last !== false && this.lastActive !== false){
91 this.selectRange(this.last, this.lastActive-1);
92 this.grid.getView().focusRow(this.lastActive);
97 this.selectFirstRow();
99 this.fireEvent("afterselectionchange", this);
101 "down" : function(e){
103 this.selectNext(e.shiftKey);
104 }else if(this.last !== false && this.lastActive !== false){
105 var last = this.last;
106 this.selectRange(this.last, this.lastActive+1);
107 this.grid.getView().focusRow(this.lastActive);
112 this.selectFirstRow();
114 this.fireEvent("afterselectionchange", this);
119 var view = this.grid.view;
120 view.on("refresh", this.onRefresh, this);
121 view.on("rowupdated", this.onRowUpdated, this);
122 view.on("rowremoved", this.onRemove, this);
126 onRefresh : function(){
127 Roo.log('calling on refresh!!!!!!!!!!!!!!!!!!!!!!!!');
128 var ds = this.grid.dataSource, i, v = this.grid.view;
129 var s = this.selections;
131 if((i = ds.indexOfId(r.id)) != -1){
133 s.add(ds.getAt(i)); // updating the selection relate data
141 onRemove : function(v, index, r){
142 this.selections.remove(r);
146 onRowUpdated : function(v, index, r){
147 if(this.isSelected(r)){
148 v.onRowSelect(index);
154 * @param {Array} records The records to select
155 * @param {Boolean} keepExisting (optional) True to keep existing selections
157 selectRecords : function(records, keepExisting){
159 this.clearSelections();
161 var ds = this.grid.dataSource;
162 for(var i = 0, len = records.length; i < len; i++){
163 this.selectRow(ds.indexOf(records[i]), true);
168 * Gets the number of selected rows.
171 getCount : function(){
172 return this.selections.length;
176 * Selects the first row in the grid.
178 selectFirstRow : function(){
183 * Select the last row.
184 * @param {Boolean} keepExisting (optional) True to keep existing selections
186 selectLastRow : function(keepExisting){
187 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
191 * Selects the row immediately following the last selected row.
192 * @param {Boolean} keepExisting (optional) True to keep existing selections
194 selectNext : function(keepExisting){
195 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
196 this.selectRow(this.last+1, keepExisting);
197 this.grid.getView().focusRow(this.last);
202 * Selects the row that precedes the last selected row.
203 * @param {Boolean} keepExisting (optional) True to keep existing selections
205 selectPrevious : function(keepExisting){
207 this.selectRow(this.last-1, keepExisting);
208 this.grid.getView().focusRow(this.last);
213 * Returns the selected records
214 * @return {Array} Array of selected records
216 getSelections : function(){
217 return [].concat(this.selections.items);
221 * Returns the first selected record.
224 getSelected : function(){
225 return this.selections.itemAt(0);
230 * Clears all selections.
232 clearSelections : function(fast){
233 if(this.locked) return;
235 var ds = this.grid.dataSource;
236 var s = this.selections;
238 this.deselectRow(ds.indexOfId(r.id));
242 this.selections.clear();
251 selectAll : function(){
252 if(this.locked) return;
253 this.selections.clear();
254 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
255 this.selectRow(i, true);
260 * Returns True if there is a selection.
263 hasSelection : function(){
264 return this.selections.length > 0;
268 * Returns True if the specified row is selected.
269 * @param {Number/Record} record The record or index of the record to check
272 isSelected : function(index){
273 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
274 return (r && this.selections.key(r.id) ? true : false);
278 * Returns True if the specified record id is selected.
279 * @param {String} id The id of record to check
282 isIdSelected : function(id){
283 return (this.selections.key(id) ? true : false);
287 handleMouseDown : function(e, t){
288 var view = this.grid.getView(), rowIndex;
289 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
292 if(e.shiftKey && this.last !== false){
293 var last = this.last;
294 this.selectRange(last, rowIndex, e.ctrlKey);
295 this.last = last; // reset the last
296 view.focusRow(rowIndex);
298 var isSelected = this.isSelected(rowIndex);
299 if(e.button !== 0 && isSelected){
300 view.focusRow(rowIndex);
301 }else if(e.ctrlKey && isSelected){
302 this.deselectRow(rowIndex);
303 }else if(!isSelected){
304 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
305 view.focusRow(rowIndex);
308 this.fireEvent("afterselectionchange", this);
311 handleDragableRowClick : function(grid, rowIndex, e)
313 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
314 this.selectRow(rowIndex, false);
315 grid.view.focusRow(rowIndex);
316 this.fireEvent("afterselectionchange", this);
321 * Selects multiple rows.
322 * @param {Array} rows Array of the indexes of the row to select
323 * @param {Boolean} keepExisting (optional) True to keep existing selections
325 selectRows : function(rows, keepExisting){
327 this.clearSelections();
329 for(var i = 0, len = rows.length; i < len; i++){
330 this.selectRow(rows[i], true);
335 * Selects a range of rows. All rows in between startRow and endRow are also selected.
336 * @param {Number} startRow The index of the first row in the range
337 * @param {Number} endRow The index of the last row in the range
338 * @param {Boolean} keepExisting (optional) True to retain existing selections
340 selectRange : function(startRow, endRow, keepExisting){
341 if(this.locked) return;
343 this.clearSelections();
345 if(startRow <= endRow){
346 for(var i = startRow; i <= endRow; i++){
347 this.selectRow(i, true);
350 for(var i = startRow; i >= endRow; i--){
351 this.selectRow(i, true);
357 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
358 * @param {Number} startRow The index of the first row in the range
359 * @param {Number} endRow The index of the last row in the range
361 deselectRange : function(startRow, endRow, preventViewNotify){
362 if(this.locked) return;
363 for(var i = startRow; i <= endRow; i++){
364 this.deselectRow(i, preventViewNotify);
370 * @param {Number} row The index of the row to select
371 * @param {Boolean} keepExisting (optional) True to keep existing selections
373 selectRow : function(index, keepExisting, preventViewNotify){
374 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
375 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
376 if(!keepExisting || this.singleSelect){
377 this.clearSelections();
379 var r = this.grid.dataSource.getAt(index);
380 Roo.log('running select row!!!!!!!!!!!!!!!!!!!!!!!!');
383 this.selections.add(r);
384 this.last = this.lastActive = index;
385 if(!preventViewNotify){
386 this.grid.getView().onRowSelect(index);
388 this.fireEvent("rowselect", this, index, r);
389 this.fireEvent("selectionchange", this);
395 * @param {Number} row The index of the row to deselect
397 deselectRow : function(index, preventViewNotify){
398 if(this.locked) return;
399 if(this.last == index){
402 if(this.lastActive == index){
403 this.lastActive = false;
405 var r = this.grid.dataSource.getAt(index);
406 this.selections.remove(r);
407 if(!preventViewNotify){
408 this.grid.getView().onRowDeselect(index);
410 this.fireEvent("rowdeselect", this, index);
411 this.fireEvent("selectionchange", this);
415 restoreLast : function(){
417 this.last = this._last;
422 acceptsNav : function(row, col, cm){
423 return !cm.isHidden(col) && cm.isCellEditable(col, row);
427 onEditorKey : function(field, e){
428 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
433 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
435 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
437 }else if(k == e.ENTER && !e.ctrlKey){
441 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
443 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
445 }else if(k == e.ESC){
449 g.startEditing(newCell[0], newCell[1]);