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