]> git.proxmox.com Git - extjs.git/blame - extjs/classic/classic/src/grid/selection/Cells.js
add extjs 6.0.1 sources
[extjs.git] / extjs / classic / classic / src / grid / selection / Cells.js
CommitLineData
6527f429
DM
1/**\r
2 * A class which encapsulates a range of cells defining a selection in a grid.\r
3 *\r
4 * Note that when range start and end points are represented by an array, the\r
5 * order is traditional `x, y` order, that is column index followed by row index.\r
6 * @since 5.1.0\r
7 */\r
8Ext.define('Ext.grid.selection.Cells', {\r
9 extend: 'Ext.grid.selection.Selection',\r
10\r
11 type: 'cells',\r
12\r
13 /**\r
14 * @property {Boolean} isCells\r
15 * This property indicates the this selection represents selected cells.\r
16 * @readonly\r
17 */\r
18 isCells: true,\r
19\r
20 //-------------------------------------------------------------------------\r
21 // Base Selection API\r
22\r
23 clone: function() {\r
24 var me = this,\r
25 result = new me.self(me.view);\r
26\r
27 if (me.startCell) {\r
28 result.startCell = me.startCell.clone();\r
29 result.endCell = me.endCell.clone();\r
30 }\r
31 return result;\r
32 },\r
33\r
34 /**\r
35 * Returns `true` if the passed {@link Ext.grid.CellContext cell context} is selected.\r
36 * @param {Ext.grid.CellContext} cellContext The cell context to test.\r
37 * @return {Boolean} `true` if the passed {@link Ext.grid.CellContext cell context} is selected.\r
38 */\r
39 contains: function(cellContext) {\r
40 var range;\r
41\r
42 if (!cellContext || !cellContext.isCellContext) {\r
43 return false;\r
44 }\r
45\r
46 if (this.startCell) {\r
47 // get start and end rows in the range\r
48 range = this.getRowRange();\r
49\r
50 if (cellContext.rowIdx >= range[0] && cellContext.rowIdx <= range[1]) {\r
51 // get start and end columns in the range\r
52 range = this.getColumnRange();\r
53 return (cellContext.colIdx >= range[0] && cellContext.colIdx <= range[1]);\r
54 }\r
55 }\r
56\r
57 return false;\r
58 },\r
59\r
60 eachRow: function(fn, scope) {\r
61 var me = this,\r
62 rowRange = me.getRowRange(),\r
63 context = new Ext.grid.CellContext(me.view),\r
64 rowIdx;\r
65\r
66 for (rowIdx = rowRange[0]; rowIdx <= rowRange[1]; rowIdx++) {\r
67 context.setRow(rowIdx);\r
68 if (fn.call(scope || me, context.record) === false) {\r
69 return;\r
70 }\r
71 }\r
72 },\r
73\r
74 eachColumn: function(fn, scope) {\r
75 var me = this,\r
76 colRange = me.getColumnRange(),\r
77 context = new Ext.grid.CellContext(me.view),\r
78 colIdx;\r
79\r
80 for (colIdx = colRange[0]; colIdx <= colRange[1]; colIdx++) {\r
81 context.setColumn(colIdx);\r
82 if (fn.call(scope || me, context.column, colIdx) === false) {\r
83 return;\r
84 }\r
85 }\r
86 },\r
87\r
88 eachCell: function(fn, scope) {\r
89 var me = this,\r
90 rowRange = me.getRowRange(),\r
91 colRange = me.getColumnRange(),\r
92 context = new Ext.grid.CellContext(me.view),\r
93 rowIdx, colIdx;\r
94\r
95 for (rowIdx = rowRange[0]; rowIdx <= rowRange[1]; rowIdx++) {\r
96 context.setRow(rowIdx);\r
97 for (colIdx = colRange[0]; colIdx <= colRange[1]; colIdx++) {\r
98 context.setColumn(colIdx);\r
99 if (fn.call(scope || me, context, colIdx, rowIdx) === false) {\r
100 return;\r
101 }\r
102 }\r
103 }\r
104 },\r
105\r
106 /**\r
107 * @return {Number} The row index of the first row in the range or zero if no range.\r
108 */\r
109 getFirstRowIndex: function() {\r
110 return this.startCell ? Math.min(this.startCell.rowIdx, this.endCell.rowIdx) : 0;\r
111 },\r
112\r
113 /**\r
114 * @return {Number} The row index of the last row in the range or -1 if no range.\r
115 */\r
116 getLastRowIndex: function() {\r
117 return this.startCell ? Math.max(this.startCell.rowIdx, this.endCell.rowIdx) : -1;\r
118 },\r
119\r
120 /**\r
121 * @return {Number} The column index of the first column in the range or zero if no range.\r
122 */\r
123 getFirstColumnIndex: function() {\r
124 return this.startCell ? Math.min(this.startCell.colIdx, this.endCell.colIdx) : 0;\r
125 },\r
126\r
127 /**\r
128 * @return {Number} The column index of the last column in the range or -1 if no range.\r
129 */\r
130 getLastColumnIndex: function() {\r
131 return this.startCell ? Math.max(this.startCell.colIdx, this.endCell.colIdx) : -1;\r
132 },\r
133\r
134 //-------------------------------------------------------------------------\r
135\r
136 privates: {\r
137 /**\r
138 * @private\r
139 */\r
140 clear: function() {\r
141 var me = this,\r
142 view = me.view;\r
143\r
144 me.eachCell(function(cellContext) {\r
145 view.onCellDeselect(cellContext);\r
146 });\r
147 me.startCell = me.endCell = null;\r
148 },\r
149\r
150 /**\r
151 * Used during drag/shift+downarrow range selection on start.\r
152 * @param {Ext.grid.CellContext} startCell The start cell of the cell drag selection.\r
153 * @private\r
154 */\r
155 setRangeStart: function (startCell, endCell) {\r
156 // Must clone them. Users might use one instance and reconfigure it to navigate.\r
157 this.startCell = (this.endCell = startCell.clone()).clone();\r
158 this.view.onCellSelect(startCell);\r
159 },\r
160\r
161 /**\r
162 * Used during drag/shift+downarrow range selection on drag.\r
163 * @param {Ext.grid.CellContext} endCell The end cell of the cell drag selection.\r
164 * @private\r
165 */\r
166 setRangeEnd: function (endCell) {\r
167 var me = this,\r
168 range,\r
169 lastRange,\r
170 rowStart,\r
171 rowEnd,\r
172 colStart,\r
173 colEnd,\r
174 rowIdx,\r
175 colIdx,\r
176 view = me.view,\r
177 rows = view.all,\r
178 cell = new Ext.grid.CellContext(view),\r
179 maxColIdx = view.getVisibleColumnManager().getColumns().length - 1;\r
180\r
181 me.endCell = endCell.clone();\r
182 range = me.getRange();\r
183 lastRange = me.lastRange || range;\r
184\r
185 rowStart = Math.max(Math.min(range[0][1], lastRange[0][1]), rows.startIndex);\r
186 rowEnd = Math.min(Math.max(range[1][1], lastRange[1][1]), rows.endIndex);\r
187\r
188 colStart = Math.min(range[0][0], lastRange[0][0]);\r
189 colEnd = Math.min(Math.max(range[1][0], lastRange[1][0]), maxColIdx);\r
190\r
191 // Loop through the union of last range and current range\r
192 for (rowIdx = rowStart; rowIdx <= rowEnd; rowIdx++) {\r
193 for (colIdx = colStart; colIdx <= colEnd; colIdx++) {\r
194 cell.setPosition(rowIdx, colIdx);\r
195\r
196 // If we are outside the current range, deselect\r
197 if (rowIdx < range[0][1] || rowIdx > range[1][1] || colIdx < range[0][0] || colIdx > range[1][0]) {\r
198 view.onCellDeselect(cell);\r
199 } else {\r
200 view.onCellSelect(cell);\r
201 }\r
202 }\r
203 }\r
204 me.lastRange = range;\r
205 },\r
206\r
207 extendRange: function(extensionVector) {\r
208 var me = this,\r
209 newEndCell;\r
210\r
211 if (extensionVector[extensionVector.type] < 0) {\r
212 newEndCell = me.endCell.clone().setPosition(me.getLastRowIndex(), me.getLastColumnIndex());\r
213 me.startCell = extensionVector.start.clone();\r
214 me.setRangeEnd(newEndCell);\r
215 me.view.getNavigationModel().setPosition(extensionVector.start);\r
216 } else {\r
217 me.startCell = me.startCell.setPosition(me.getFirstRowIndex(), me.getFirstColumnIndex());\r
218 me.setRangeEnd(extensionVector.end);\r
219 me.view.getNavigationModel().setPosition(extensionVector.end);\r
220 }\r
221 },\r
222\r
223 /**\r
224 * Returns the `[[x, y],[x,y]]` coordinates in top-left to bottom-right order\r
225 * of the current selection.\r
226 *\r
227 * If no selection, returns [[0, 0],[-1, -1]] so that an incrementing iteration\r
228 * will not execute.\r
229 *\r
230 * @return {Number[][]}\r
231 * @private\r
232 */\r
233 getRange: function() {\r
234 return [[this.getFirstColumnIndex(), this.getFirstRowIndex()], [this.getLastColumnIndex(), this.getLastRowIndex()]];\r
235 },\r
236\r
237 /**\r
238 * Returns the size of the selection rectangle.\r
239 * @return {Number}\r
240 * @private\r
241 */\r
242 getRangeSize: function() {\r
243 return this.getCount();\r
244 },\r
245\r
246 /**\r
247 * Returns the number of cells selected.\r
248 * @return {Number} The nuimber of cells selected\r
249 * @private\r
250 */\r
251 getCount: function() {\r
252 var range = this.getRange();\r
253\r
254 return (range[1][0] - range[0][0] + 1) * (range[1][1] - range[0][1] + 1);\r
255 },\r
256\r
257 /**\r
258 * @private\r
259 */\r
260 selectAll: function() {\r
261 var me = this,\r
262 view = me.view;\r
263\r
264 me.clear();\r
265 me.setRangeStart(new Ext.grid.CellContext(view).setPosition(0, 0));\r
266 me.setRangeEnd(new Ext.grid.CellContext(view).setPosition(view.dataSource.getCount() - 1, view.getVisibleColumnManager().getColumns().length - 1));\r
267 },\r
268\r
269 /**\r
270 * @return {Boolean}\r
271 * @private\r
272 */\r
273 isAllSelected: function() {\r
274 var start = this.rangeStart,\r
275 end = this.rangeEnd;\r
276\r
277 // All selected only if we encompass the entire store and every visible column\r
278 if (start) {\r
279 if (!start.colIdx && !start.rowIdx) {\r
280 return end.colIdx === end.view.getVisibleColumnManager().getColumns().length - 1 && end.rowIdx === end.view.dataSource.getCount - 1;\r
281 }\r
282 }\r
283 return false;\r
284 },\r
285\r
286 /**\r
287 * @return {Number[]} The column range which encapsulates the range.\r
288 * @private\r
289 */\r
290 getColumnRange: function() {\r
291 return [this.getFirstColumnIndex(), this.getLastColumnIndex()];\r
292 },\r
293\r
294 /**\r
295 * Returns the row range which encapsulates the range - the view range that needs\r
296 * updating.\r
297 * @return {Number[]}\r
298 * @private\r
299 */\r
300 getRowRange: function() {\r
301 return [this.getFirstRowIndex(), this.getLastRowIndex()];\r
302 },\r
303\r
304 onSelectionFinish: function() {\r
305 var me = this;\r
306\r
307 if (me.getCount()) {\r
308 me.view.getSelectionModel().onSelectionFinish(me,\r
309 new Ext.grid.CellContext(me.view).setPosition(me.getFirstRowIndex(), me.getFirstColumnIndex()),\r
310 new Ext.grid.CellContext(me.view).setPosition(me.getLastRowIndex(), me.getLastColumnIndex()));\r
311 } else {\r
312 me.view.getSelectionModel().onSelectionFinish(me);\r
313 }\r
314 }\r
315 }\r
316});\r