try and get ctrl-enter to add a clear all
[roojs1] / Roo / grid / CellSelectionModel.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11 /**
12  * @class Roo.grid.CellSelectionModel
13  * @extends Roo.grid.AbstractSelectionModel
14  * This class provides the basic implementation for cell selection in a grid.
15  * @constructor
16  * @param {Object} config The object containing the configuration of this model.
17  * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
18  */
19 Roo.grid.CellSelectionModel = function(config){
20     Roo.apply(this, config);
21
22     this.selection = null;
23
24     this.addEvents({
25         /**
26              * @event beforerowselect
27              * Fires before a cell is selected.
28              * @param {SelectionModel} this
29              * @param {Number} rowIndex The selected row index
30              * @param {Number} colIndex The selected cell index
31              */
32             "beforecellselect" : true,
33         /**
34              * @event cellselect
35              * Fires when a cell is selected.
36              * @param {SelectionModel} this
37              * @param {Number} rowIndex The selected row index
38              * @param {Number} colIndex The selected cell index
39              */
40             "cellselect" : true,
41         /**
42              * @event selectionchange
43              * Fires when the active selection changes.
44              * @param {SelectionModel} this
45              * @param {Object} selection null for no selection or an object (o) with two properties
46                 <ul>
47                 <li>o.record: the record object for the row the selection is in</li>
48                 <li>o.cell: An array of [rowIndex, columnIndex]</li>
49                 </ul>
50              */
51             "selectionchange" : true,
52         /**
53              * @event tabend
54              * Fires when the tab (or enter) was pressed on the last editable cell
55              * You can use this to trigger add new row.
56              * @param {SelectionModel} this
57              */
58             "tabend" : true,
59          /**
60              * @event beforeeditnext
61              * Fires before the next editable sell is made active
62              * You can use this to skip to another cell or fire the tabend
63              *    if you set cell to false
64              * @param {Object} eventdata object : { cell : [ row, col ] } 
65              */
66             "beforeeditnext" : true
67     });
68     Roo.grid.CellSelectionModel.superclass.constructor.call(this);
69 };
70
71 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel,  {
72     
73     enter_is_tab: false,
74
75     /** @ignore */
76     initEvents : function(){
77         this.grid.on("mousedown", this.handleMouseDown, this);
78         this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
79         var view = this.grid.view;
80         view.on("refresh", this.onViewChange, this);
81         view.on("rowupdated", this.onRowUpdated, this);
82         view.on("beforerowremoved", this.clearSelections, this);
83         view.on("beforerowsinserted", this.clearSelections, this);
84         if(this.grid.isEditor){
85             this.grid.on("beforeedit", this.beforeEdit,  this);
86         }
87     },
88
89         //private
90     beforeEdit : function(e){
91         this.select(e.row, e.column, false, true, e.record);
92     },
93
94         //private
95     onRowUpdated : function(v, index, r){
96         if(this.selection && this.selection.record == r){
97             v.onCellSelect(index, this.selection.cell[1]);
98         }
99     },
100
101         //private
102     onViewChange : function(){
103         this.clearSelections(true);
104     },
105
106         /**
107          * Returns the currently selected cell,.
108          * @return {Array} The selected cell (row, column) or null if none selected.
109          */
110     getSelectedCell : function(){
111         return this.selection ? this.selection.cell : null;
112     },
113
114     /**
115      * Clears all selections.
116      * @param {Boolean} true to prevent the gridview from being notified about the change.
117      */
118     clearSelections : function(preventNotify){
119         var s = this.selection;
120         if(s){
121             if(preventNotify !== true){
122                 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
123             }
124             this.selection = null;
125             this.fireEvent("selectionchange", this, null);
126         }
127     },
128
129     /**
130      * Returns true if there is a selection.
131      * @return {Boolean}
132      */
133     hasSelection : function(){
134         return this.selection ? true : false;
135     },
136
137     /** @ignore */
138     handleMouseDown : function(e, t){
139         var v = this.grid.getView();
140         if(this.isLocked()){
141             return;
142         };
143         var row = v.findRowIndex(t);
144         var cell = v.findCellIndex(t);
145         if(row !== false && cell !== false){
146             this.select(row, cell);
147         }
148     },
149
150     /**
151      * Selects a cell.
152      * @param {Number} rowIndex
153      * @param {Number} collIndex
154      */
155     select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
156         if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
157             this.clearSelections();
158             r = r || this.grid.dataSource.getAt(rowIndex);
159             this.selection = {
160                 record : r,
161                 cell : [rowIndex, colIndex]
162             };
163             if(!preventViewNotify){
164                 var v = this.grid.getView();
165                 v.onCellSelect(rowIndex, colIndex);
166                 if(preventFocus !== true){
167                     v.focusCell(rowIndex, colIndex);
168                 }
169             }
170             this.fireEvent("cellselect", this, rowIndex, colIndex);
171             this.fireEvent("selectionchange", this, this.selection);
172         }
173     },
174
175         //private
176     isSelectable : function(rowIndex, colIndex, cm){
177         return !cm.isHidden(colIndex);
178     },
179
180     /** @ignore */
181     handleKeyDown : function(e){
182         //Roo.log('Cell Sel Model handleKeyDown');
183         if(!e.isNavKeyPress()){
184             return;
185         }
186         var g = this.grid, s = this.selection;
187         if(!s){
188             e.stopEvent();
189             var cell = g.walkCells(0, 0, 1, this.isSelectable,  this);
190             if(cell){
191                 this.select(cell[0], cell[1]);
192             }
193             return;
194         }
195         var sm = this;
196         var walk = function(row, col, step){
197             return g.walkCells(row, col, step, sm.isSelectable,  sm);
198         };
199         var k = e.getKey(), r = s.cell[0], c = s.cell[1];
200         var newCell;
201
202       
203
204         switch(k){
205             case e.TAB:
206                 // handled by onEditorKey
207                 if (g.isEditor && g.editing) {
208                     return;
209                 }
210                 if(e.shiftKey) {
211                     newCell = walk(r, c-1, -1);
212                 } else {
213                     newCell = walk(r, c+1, 1);
214                 }
215                 break;
216             
217             case e.DOWN:
218                newCell = walk(r+1, c, 1);
219                 break;
220             
221             case e.UP:
222                 newCell = walk(r-1, c, -1);
223                 break;
224             
225             case e.RIGHT:
226                 newCell = walk(r, c+1, 1);
227                 break;
228             
229             case e.LEFT:
230                 newCell = walk(r, c-1, -1);
231                 break;
232             
233             case e.ENTER:
234                 
235                 if(g.isEditor && !g.editing){
236                    g.startEditing(r, c);
237                    e.stopEvent();
238                    return;
239                 }
240                 
241                 
242              break;
243         };
244         if(newCell){
245             this.select(newCell[0], newCell[1]);
246             e.stopEvent();
247             
248         }
249     },
250
251     acceptsNav : function(row, col, cm){
252         return !cm.isHidden(col) && cm.isCellEditable(col, row);
253     },
254     /**
255      * Selects a cell.
256      * @param {Number} field (not used) - as it's normally used as a listener
257      * @param {Number} e - event - fake it by using
258      *
259      * var e = Roo.EventObjectImpl.prototype;
260      * e.keyCode = e.TAB
261      *
262      * 
263      */
264     onEditorKey : function(field, e){
265         
266         var k = e.getKey(),
267             newCell,
268             g = this.grid,
269             ed = g.activeEditor,
270             forward = false;
271         ///Roo.log('onEditorKey' + k);
272         
273         
274         if (this.enter_is_tab && k == e.ENTER) {
275             k = e.TAB;
276         }
277         
278         if(k == e.TAB){
279             if(e.shiftKey){
280                 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
281             }else{
282                 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
283                 forward = true;
284             }
285             
286             e.stopEvent();
287             
288         } else if(k == e.ENTER &&  !e.ctrlKey){
289             ed.completeEdit();
290             e.stopEvent();
291             newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
292         
293                 } else if(k == e.ESC){
294             ed.cancelEdit();
295         }
296                 
297         if (newCell) {
298             var ecall = { cell : newCell, forward : forward };
299             this.fireEvent('beforeeditnext', ecall );
300             newCell = ecall.cell;
301                         forward = ecall.forward;
302         }
303                 
304         if(newCell){
305             //Roo.log('next cell after edit');
306             g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
307         } else if (forward) {
308             // tabbed past last
309             this.fireEvent.defer(100, this, ['tabend',this]);
310         }
311     }
312 });