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