Upgrade to ExtJS 4.0.2 - Released 06/09/2011
[extjs.git] / src / selection / CellModel.js
1 /*
2
3 This file is part of Ext JS 4
4
5 Copyright (c) 2011 Sencha Inc
6
7 Contact:  http://www.sencha.com/contact
8
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
11
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
13
14 */
15 /**
16  * @class Ext.selection.CellModel
17  * @extends Ext.selection.Model
18  * @private
19  */
20 Ext.define('Ext.selection.CellModel', {
21     extend: 'Ext.selection.Model',
22     alias: 'selection.cellmodel',
23     requires: ['Ext.util.KeyNav'],
24     
25     /**
26      * @cfg {Boolean} enableKeyNav
27      * Turns on/off keyboard navigation within the grid. Defaults to true.
28      */
29     enableKeyNav: true,
30     
31     /**
32      * @cfg {Boolean} preventWrap
33      * Set this configuration to true to prevent wrapping around of selection as
34      * a user navigates to the first or last column. Defaults to false.
35      */
36     preventWrap: false,
37
38     constructor: function(){
39         this.addEvents(
40             /**
41              * @event deselect
42              * Fired after a cell is deselected
43              * @param {Ext.selection.CellModel} this
44              * @param {Ext.data.Model} record The record of the deselected cell
45              * @param {Number} row The row index deselected
46              * @param {Number} column The column index deselected
47              */
48             'deselect',
49             
50             /**
51              * @event select
52              * Fired after a cell is selected
53              * @param {Ext.selection.CellModel} this
54              * @param {Ext.data.Model} record The record of the selected cell
55              * @param {Number} row The row index selected
56              * @param {Number} column The column index selected
57              */
58             'select'
59         );
60         this.callParent(arguments);    
61     },
62
63     bindComponent: function(view) {
64         var me = this;
65         me.primaryView = view;
66         me.views = me.views || [];
67         me.views.push(view);
68         me.bind(view.getStore(), true);
69
70         view.on({
71             cellmousedown: me.onMouseDown,
72             refresh: me.onViewRefresh,
73             scope: me
74         });
75
76         if (me.enableKeyNav) {
77             me.initKeyNav(view);
78         }
79     },
80
81     initKeyNav: function(view) {
82         var me = this;
83         
84         if (!view.rendered) {
85             view.on('render', Ext.Function.bind(me.initKeyNav, me, [view], 0), me, {single: true});
86             return;
87         }
88
89         view.el.set({
90             tabIndex: -1
91         });
92
93         // view.el has tabIndex -1 to allow for
94         // keyboard events to be passed to it.
95         me.keyNav = Ext.create('Ext.util.KeyNav', view.el, {
96             up: me.onKeyUp,
97             down: me.onKeyDown,
98             right: me.onKeyRight,
99             left: me.onKeyLeft,
100             tab: me.onKeyTab,
101             scope: me
102         });
103     },
104     
105     getHeaderCt: function() {
106         return this.primaryView.headerCt;
107     },
108
109     onKeyUp: function(e, t) {
110         this.move('up', e);
111     },
112
113     onKeyDown: function(e, t) {
114         this.move('down', e);
115     },
116
117     onKeyLeft: function(e, t) {
118         this.move('left', e);
119     },
120     
121     onKeyRight: function(e, t) {
122         this.move('right', e);
123     },
124     
125     move: function(dir, e) {
126         var me = this,
127             pos = me.primaryView.walkCells(me.getCurrentPosition(), dir, e, me.preventWrap);
128         if (pos) {
129             me.setCurrentPosition(pos);
130         }
131         return pos;
132     },
133
134     /**
135      * Returns the current position in the format {row: row, column: column}
136      */
137     getCurrentPosition: function() {
138         return this.position;
139     },
140     
141     /**
142      * Sets the current position
143      * @param {Object} position The position to set.
144      */
145     setCurrentPosition: function(pos) {
146         var me = this;
147         
148         if (me.position) {
149             me.onCellDeselect(me.position);
150         }
151         if (pos) {
152             me.onCellSelect(pos);
153         }
154         me.position = pos;
155     },
156
157     /**
158      * Set the current position based on where the user clicks.
159      * @private
160      */
161     onMouseDown: function(view, cell, cellIndex, record, row, rowIndex, e) {
162         this.setCurrentPosition({
163             row: rowIndex,
164             column: cellIndex
165         });
166     },
167
168     // notify the view that the cell has been selected to update the ui
169     // appropriately and bring the cell into focus
170     onCellSelect: function(position) {
171         var me = this,
172             store = me.view.getStore(),
173             record = store.getAt(position.row);
174
175         me.doSelect(record);
176         me.primaryView.onCellSelect(position);
177         // TODO: Remove temporary cellFocus call here.
178         me.primaryView.onCellFocus(position);
179         me.fireEvent('select', me, record, position.row, position.column);
180     },
181
182     // notify view that the cell has been deselected to update the ui
183     // appropriately
184     onCellDeselect: function(position) {
185         var me = this,
186             store = me.view.getStore(),
187             record = store.getAt(position.row);
188
189         me.doDeselect(record);
190         me.primaryView.onCellDeselect(position);
191         me.fireEvent('deselect', me, record, position.row, position.column);
192     },
193
194     onKeyTab: function(e, t) {
195         var me = this,
196             direction = e.shiftKey ? 'left' : 'right',
197             editingPlugin = me.view.editingPlugin,
198             position = me.move(direction, e);
199
200         if (editingPlugin && position && me.wasEditing) {
201             editingPlugin.startEditByPosition(position);
202         }
203         delete me.wasEditing;
204     },
205
206     onEditorTab: function(editingPlugin, e) {
207         var me = this,
208             direction = e.shiftKey ? 'left' : 'right',
209             position  = me.move(direction, e);
210
211         if (position) {
212             editingPlugin.startEditByPosition(position);
213             me.wasEditing = true;
214         }
215     },
216
217     refresh: function() {
218         var pos = this.getCurrentPosition();
219         if (pos) {
220             this.onCellSelect(pos);
221         }
222     },
223
224     onViewRefresh: function() {
225         var pos = this.getCurrentPosition();
226         if (pos) {
227             this.onCellDeselect(pos);
228             this.setCurrentPosition(null);
229         }
230     },
231
232     selectByPosition: function(position) {
233         this.setCurrentPosition(position);
234     }
235 });