|
1 var columns_simpletree = |
|
2 [ |
|
3 { name: "name", label: "Name", key: true, properties: "one two" }, |
|
4 { name: "address", label: "Address" } |
|
5 ]; |
|
6 |
|
7 var columns_hiertree = |
|
8 [ |
|
9 { name: "name", label: "Name", primary: true, key: true, properties: "one two" }, |
|
10 { name: "address", label: "Address" }, |
|
11 { name: "planet", label: "Planet" }, |
|
12 { name: "gender", label: "Gender", cycler: true } |
|
13 ]; |
|
14 |
|
15 // XXXndeakin still to add some tests for: |
|
16 // cycler columns, checkbox cells, progressmeter cells |
|
17 |
|
18 // this test function expects a tree to have 8 rows in it when it isn't |
|
19 // expanded. The tree should only display four rows at a time. If editable, |
|
20 // the cell at row 1 and column 0 must be editable, and the cell at row 2 and |
|
21 // column 1 must not be editable. |
|
22 function testtag_tree(treeid, treerowinfoid, seltype, columnstype, testid) |
|
23 { |
|
24 // Stop keystrokes that aren't handled by the tree from leaking out and |
|
25 // scrolling the main Mochitests window! |
|
26 function preventDefault(event) { |
|
27 event.preventDefault(); |
|
28 } |
|
29 document.addEventListener("keypress", preventDefault, false); |
|
30 |
|
31 var multiple = (seltype == "multiple"); |
|
32 |
|
33 var tree = document.getElementById(treeid); |
|
34 var treerowinfo = document.getElementById(treerowinfoid); |
|
35 var rowInfo; |
|
36 if (testid =="tree view") |
|
37 rowInfo = getCustomTreeViewCellInfo(); |
|
38 else |
|
39 rowInfo = convertDOMtoTreeRowInfo(treerowinfo, 0, { value: -1 }); |
|
40 var columnInfo = (columnstype == "simple") ? columns_simpletree : columns_hiertree; |
|
41 |
|
42 is(tree.view.selection.currentColumn, null, testid + " initial currentColumn"); |
|
43 is(tree.selType, seltype == "multiple" ? "" : seltype, testid + " seltype"); |
|
44 |
|
45 // note: the functions below should be in this order due to changes made in later tests |
|
46 |
|
47 // select the first column in cell selection mode so that the selection |
|
48 // functions can be tested |
|
49 if (seltype == "cell") |
|
50 tree.view.selection.currentColumn = tree.columns[0]; |
|
51 |
|
52 testtag_tree_columns(tree, columnInfo, testid); |
|
53 testtag_tree_TreeSelection(tree, testid, multiple); |
|
54 testtag_tree_TreeSelection_UI(tree, testid, multiple); |
|
55 if (seltype == "cell") |
|
56 testtag_tree_TreeSelection_UI_cell(tree, testid, rowInfo); |
|
57 |
|
58 testtag_tree_TreeView(tree, testid, rowInfo); |
|
59 |
|
60 is(tree.editable, false, "tree should not be editable"); |
|
61 // currently, the editable flag means that tree editing cannot be invoked |
|
62 // by the user. However, editing can still be started with a script. |
|
63 is(tree.editingRow, -1, testid + " initial editingRow"); |
|
64 is(tree.editingColumn, null, testid + " initial editingColumn"); |
|
65 |
|
66 testtag_tree_UI_editing(tree, testid, rowInfo); |
|
67 |
|
68 is(tree.editable, false, "tree should not be editable after testtag_tree_UI_editing"); |
|
69 // currently, the editable flag means that tree editing cannot be invoked |
|
70 // by the user. However, editing can still be started with a script. |
|
71 is(tree.editingRow, -1, testid + " initial editingRow (continued)"); |
|
72 is(tree.editingColumn, null, testid + " initial editingColumn (continued)"); |
|
73 |
|
74 var ecolumn = tree.columns[0]; |
|
75 ok(!tree.startEditing(1, ecolumn), "non-editable trees shouldn't start editing"); |
|
76 is(tree.editingRow, -1, testid + " failed startEditing shouldn't set editingRow"); |
|
77 is(tree.editingColumn, null, testid + " failed startEditing shouldn't set editingColumn"); |
|
78 |
|
79 tree.editable = true; |
|
80 |
|
81 ok(tree.startEditing(1, ecolumn), "startEditing should have returned true"); |
|
82 is(tree.editingRow, 1, testid + " startEditing editingRow"); |
|
83 is(tree.editingColumn, ecolumn, testid + " startEditing editingColumn"); |
|
84 is(tree.getAttribute("editing"), "true", testid + " startEditing editing attribute"); |
|
85 |
|
86 tree.stopEditing(true); |
|
87 is(tree.editingRow, -1, testid + " stopEditing editingRow"); |
|
88 is(tree.editingColumn, null, testid + " stopEditing editingColumn"); |
|
89 is(tree.hasAttribute("editing"), false, testid + " stopEditing editing attribute"); |
|
90 |
|
91 tree.startEditing(-1, ecolumn); |
|
92 is(tree.editingRow == -1 && tree.editingColumn == null, true, testid + " startEditing -1 editingRow"); |
|
93 tree.startEditing(15, ecolumn); |
|
94 is(tree.editingRow == -1 && tree.editingColumn == null, true, testid + " startEditing 15 editingRow"); |
|
95 tree.startEditing(1, null); |
|
96 is(tree.editingRow == -1 && tree.editingColumn == null, true, testid + " startEditing null column editingRow"); |
|
97 tree.startEditing(2, tree.columns[1]); |
|
98 is(tree.editingRow == -1 && tree.editingColumn == null, true, testid + " startEditing non editable cell editingRow"); |
|
99 |
|
100 tree.startEditing(1, ecolumn); |
|
101 var inputField = tree.inputField; |
|
102 is(inputField instanceof Components.interfaces.nsIDOMXULTextBoxElement, true, testid + "inputField"); |
|
103 inputField.value = "Changed Value"; |
|
104 tree.stopEditing(true); |
|
105 is(tree.view.getCellText(1, ecolumn), "Changed Value", testid + "edit cell accept"); |
|
106 |
|
107 // this cell can be edited, but stopEditing(false) means don't accept the change. |
|
108 tree.startEditing(1, ecolumn); |
|
109 inputField.value = "Second Value"; |
|
110 tree.stopEditing(false); |
|
111 is(tree.view.getCellText(1, ecolumn), "Changed Value", testid + "edit cell no accept"); |
|
112 |
|
113 tree.editable = false; |
|
114 |
|
115 // do the sorting tests last as it will cause the rows to rearrange |
|
116 // skip them for the custom tree view |
|
117 if (testid !="tree view") |
|
118 testtag_tree_TreeView_rows_sort(tree, testid, rowInfo); |
|
119 |
|
120 testtag_tree_wheel(tree); |
|
121 |
|
122 document.removeEventListener("keypress", preventDefault, false); |
|
123 |
|
124 SimpleTest.finish(); |
|
125 } |
|
126 |
|
127 function testtag_tree_columns(tree, expectedColumns, testid) |
|
128 { |
|
129 testid += " "; |
|
130 |
|
131 var columns = tree.columns; |
|
132 |
|
133 is(columns instanceof TreeColumns, true, testid + "columns is a TreeColumns"); |
|
134 is(columns.count, expectedColumns.length, testid + "TreeColumns count"); |
|
135 is(columns.length, expectedColumns.length, testid + "TreeColumns length"); |
|
136 |
|
137 var treecols = tree.getElementsByTagName("treecols")[0]; |
|
138 var treecol = treecols.getElementsByTagName("treecol"); |
|
139 |
|
140 var x = 0; |
|
141 var primary = null, sorted = null, key = null; |
|
142 for (var c = 0; c < expectedColumns.length; c++) { |
|
143 var adjtestid = testid + " column " + c + " "; |
|
144 var column = columns[c]; |
|
145 var expectedColumn = expectedColumns[c]; |
|
146 is(columns.getColumnAt(c), column, adjtestid + "getColumnAt"); |
|
147 is(columns.getNamedColumn(expectedColumn.name), column, adjtestid + "getNamedColumn"); |
|
148 is(columns.getColumnFor(treecol[c]), column, adjtestid + "getColumnFor"); |
|
149 if (expectedColumn.primary) |
|
150 primary = column; |
|
151 if (expectedColumn.sorted) |
|
152 sorted = column; |
|
153 if (expectedColumn.key) |
|
154 key = column; |
|
155 |
|
156 // XXXndeakin on Windows and Linux, some columns are one pixel to the |
|
157 // left of where they should be. Could just be a rounding issue. |
|
158 var adj = 1; |
|
159 is(column.x + adj >= x, true, adjtestid + "position is after last column " + |
|
160 column.x + "," + column.width + "," + x); |
|
161 is(column.width > 0, true, adjtestid + "width is greater than 0"); |
|
162 x = column.x + column.width; |
|
163 |
|
164 // now check the TreeColumn properties |
|
165 is(column instanceof TreeColumn, true, adjtestid + "is a TreeColumn"); |
|
166 is(column.element, treecol[c], adjtestid + "element is treecol"); |
|
167 is(column.columns, columns, adjtestid + "columns is TreeColumns"); |
|
168 is(column.id, expectedColumn.name, adjtestid + "name"); |
|
169 is(column.index, c, adjtestid + "index"); |
|
170 is(column.primary, primary == column, adjtestid + "column is primary"); |
|
171 |
|
172 is(column.cycler, "cycler" in expectedColumn && expectedColumn.cycler, |
|
173 adjtestid + "column is cycler"); |
|
174 is(column.selectable, true, adjtestid + "column is selectable"); |
|
175 is(column.editable, "editable" in expectedColumn && expectedColumn.editable, |
|
176 adjtestid + "column is editable"); |
|
177 |
|
178 is(column.type, "type" in expectedColumn ? expectedColumn.type : 1, adjtestid + "type"); |
|
179 |
|
180 is(column.getPrevious(), c > 0 ? columns[c - 1] : null, adjtestid + "getPrevious"); |
|
181 is(column.getNext(), c < columns.length - 1 ? columns[c + 1] : null, adjtestid + "getNext"); |
|
182 |
|
183 // check the view's getColumnProperties method |
|
184 var properties = tree.view.getColumnProperties(column); |
|
185 var expectedProperties = expectedColumn.properties; |
|
186 is(properties, expectedProperties ? expectedProperties : "", adjtestid + "getColumnProperties"); |
|
187 } |
|
188 |
|
189 is(columns.getFirstColumn(), columns[0], testid + "getFirstColumn"); |
|
190 is(columns.getLastColumn(), columns[columns.length - 1], testid + "getLastColumn"); |
|
191 is(columns.getPrimaryColumn(), primary, testid + "getPrimaryColumn"); |
|
192 is(columns.getSortedColumn(), sorted, testid + "getSortedColumn"); |
|
193 is(columns.getKeyColumn(), key, testid + "getKeyColumn"); |
|
194 |
|
195 is(columns.getColumnAt(-1), null, testid + "getColumnAt under"); |
|
196 is(columns.getColumnAt(columns.length), null, testid + "getColumnAt over"); |
|
197 is(columns.getNamedColumn(""), null, testid + "getNamedColumn null"); |
|
198 is(columns.getNamedColumn("unknown"), null, testid + "getNamedColumn unknown"); |
|
199 is(columns.getColumnFor(null), null, testid + "getColumnFor null"); |
|
200 is(columns.getColumnFor(tree), null, testid + "getColumnFor other"); |
|
201 } |
|
202 |
|
203 function testtag_tree_TreeSelection(tree, testid, multiple) |
|
204 { |
|
205 testid += " selection "; |
|
206 |
|
207 var selection = tree.view.selection; |
|
208 is(selection instanceof Components.interfaces.nsITreeSelection, true, |
|
209 testid + "selection is a TreeSelection"); |
|
210 is(selection.single, !multiple, testid + "single"); |
|
211 |
|
212 testtag_tree_TreeSelection_State(tree, testid + "initial", -1, []); |
|
213 is(selection.shiftSelectPivot, -1, testid + "initial shiftSelectPivot"); |
|
214 |
|
215 selection.currentIndex = 2; |
|
216 testtag_tree_TreeSelection_State(tree, testid + "set currentIndex", 2, []); |
|
217 tree.currentIndex = 3; |
|
218 testtag_tree_TreeSelection_State(tree, testid + "set tree.currentIndex", 3, []); |
|
219 |
|
220 // test the select() method, which should deselect all rows and select |
|
221 // a single row |
|
222 selection.select(1); |
|
223 testtag_tree_TreeSelection_State(tree, testid + "select 1", 1, [1]); |
|
224 selection.select(3); |
|
225 testtag_tree_TreeSelection_State(tree, testid + "select 2", 3, [3]); |
|
226 selection.select(3); |
|
227 testtag_tree_TreeSelection_State(tree, testid + "select same", 3, [3]); |
|
228 |
|
229 selection.currentIndex = 1; |
|
230 testtag_tree_TreeSelection_State(tree, testid + "set currentIndex with single selection", 1, [3]); |
|
231 |
|
232 tree.currentIndex = 2; |
|
233 testtag_tree_TreeSelection_State(tree, testid + "set tree.currentIndex with single selection", 2, [3]); |
|
234 |
|
235 // check the toggleSelect method. In single selection mode, it only toggles on when |
|
236 // there isn't currently a selection. |
|
237 selection.toggleSelect(2); |
|
238 testtag_tree_TreeSelection_State(tree, testid + "toggleSelect 1", 2, multiple ? [2, 3] : [3]); |
|
239 selection.toggleSelect(2); |
|
240 selection.toggleSelect(3); |
|
241 testtag_tree_TreeSelection_State(tree, testid + "toggleSelect 2", 3, []); |
|
242 |
|
243 // the current index doesn't change after a selectAll, so it should still be set to 1 |
|
244 // selectAll has no effect on single selection trees |
|
245 selection.currentIndex = 1; |
|
246 selection.selectAll(); |
|
247 testtag_tree_TreeSelection_State(tree, testid + "selectAll 1", 1, multiple ? [0, 1, 2, 3, 4, 5, 6 , 7] : []); |
|
248 selection.toggleSelect(2); |
|
249 testtag_tree_TreeSelection_State(tree, testid + "toggleSelect after selectAll", 2, |
|
250 multiple ? [0, 1, 3, 4, 5, 6, 7] : [2]); |
|
251 selection.clearSelection(); |
|
252 testtag_tree_TreeSelection_State(tree, testid + "clearSelection", 2, []); |
|
253 selection.toggleSelect(3); |
|
254 selection.toggleSelect(1); |
|
255 if (multiple) { |
|
256 selection.selectAll(); |
|
257 testtag_tree_TreeSelection_State(tree, testid + "selectAll 2", 1, [0, 1, 2, 3, 4, 5, 6, 7]); |
|
258 } |
|
259 selection.currentIndex = 2; |
|
260 selection.clearSelection(); |
|
261 testtag_tree_TreeSelection_State(tree, testid + "clearSelection after selectAll", 2, []); |
|
262 |
|
263 // XXXndeakin invertSelection isn't implemented |
|
264 // selection.invertSelection(); |
|
265 |
|
266 is(selection.shiftSelectPivot, -1, testid + "shiftSelectPivot set to -1"); |
|
267 |
|
268 // rangedSelect and clearRange set the currentIndex to the endIndex. The |
|
269 // shiftSelectPivot property will be set to startIndex. |
|
270 selection.rangedSelect(1, 3, false); |
|
271 testtag_tree_TreeSelection_State(tree, testid + "rangedSelect no augment", |
|
272 multiple ? 3 : 2, multiple ? [1, 2, 3] : []); |
|
273 is(selection.shiftSelectPivot, multiple ? 1 : -1, |
|
274 testid + "shiftSelectPivot after rangedSelect no augment"); |
|
275 if (multiple) { |
|
276 selection.select(1); |
|
277 selection.rangedSelect(0, 2, true); |
|
278 testtag_tree_TreeSelection_State(tree, testid + "rangedSelect augment", 2, [0, 1, 2]); |
|
279 is(selection.shiftSelectPivot, 0, testid + "shiftSelectPivot after rangedSelect augment"); |
|
280 |
|
281 selection.clearRange(1, 3); |
|
282 testtag_tree_TreeSelection_State(tree, testid + "rangedSelect augment", 3, [0]); |
|
283 |
|
284 // check that rangedSelect can take a start value higher than end |
|
285 selection.rangedSelect(3, 1, false); |
|
286 testtag_tree_TreeSelection_State(tree, testid + "rangedSelect reverse", 1, [1, 2, 3]); |
|
287 is(selection.shiftSelectPivot, 3, testid + "shiftSelectPivot after rangedSelect reverse"); |
|
288 |
|
289 // check that setting the current index doesn't change the selection |
|
290 selection.currentIndex = 0; |
|
291 testtag_tree_TreeSelection_State(tree, testid + "currentIndex with range selection", 0, [1, 2, 3]); |
|
292 } |
|
293 |
|
294 // both values of rangedSelect may be the same |
|
295 selection.rangedSelect(2, 2, false); |
|
296 testtag_tree_TreeSelection_State(tree, testid + "rangedSelect one row", 2, [2]); |
|
297 is(selection.shiftSelectPivot, 2, testid + "shiftSelectPivot after selecting one row"); |
|
298 |
|
299 if (multiple) { |
|
300 selection.rangedSelect(2, 3, true); |
|
301 |
|
302 // a start index of -1 means from the last point |
|
303 selection.rangedSelect(-1, 0, true); |
|
304 testtag_tree_TreeSelection_State(tree, testid + "rangedSelect -1 existing selection", 0, [0, 1, 2, 3]); |
|
305 is(selection.shiftSelectPivot, 2, testid + "shiftSelectPivot after -1 existing selection"); |
|
306 |
|
307 selection.currentIndex = 2; |
|
308 selection.rangedSelect(-1, 0, false); |
|
309 testtag_tree_TreeSelection_State(tree, testid + "rangedSelect -1 from currentIndex", 0, [0, 1, 2]); |
|
310 is(selection.shiftSelectPivot, 2, testid + "shiftSelectPivot -1 from currentIndex"); |
|
311 } |
|
312 |
|
313 // XXXndeakin need to test out of range values but these don't work properly |
|
314 /* |
|
315 selection.select(-1); |
|
316 testtag_tree_TreeSelection_State(tree, testid + "rangedSelect augment -1", -1, []); |
|
317 |
|
318 selection.select(8); |
|
319 testtag_tree_TreeSelection_State(tree, testid + "rangedSelect augment 8", 3, [0]); |
|
320 */ |
|
321 } |
|
322 |
|
323 function testtag_tree_TreeSelection_UI(tree, testid, multiple) |
|
324 { |
|
325 testid += " selection UI "; |
|
326 |
|
327 var selection = tree.view.selection; |
|
328 selection.clearSelection(); |
|
329 selection.currentIndex = 0; |
|
330 tree.focus(); |
|
331 |
|
332 var keydownFired = 0; |
|
333 var keypressFired = 0; |
|
334 function keydownListener(event) |
|
335 { |
|
336 keydownFired++; |
|
337 } |
|
338 function keypressListener(event) { |
|
339 keypressFired++; |
|
340 } |
|
341 |
|
342 // check that cursor up and down keys navigate up and down |
|
343 // select event fires after a delay so don't expect it. The reason it fires after a delay |
|
344 // is so that cursor navigation allows quicking skimming over a set of items without |
|
345 // actually firing events in-between, improving performance. The select event will only |
|
346 // be fired on the row where the cursor stops. |
|
347 window.addEventListener("keydown", keydownListener, false); |
|
348 window.addEventListener("keypress", keypressListener, false); |
|
349 |
|
350 synthesizeKeyExpectEvent("VK_DOWN", {}, tree, "!select", "key down"); |
|
351 testtag_tree_TreeSelection_State(tree, testid + "key down", 1, [1], 0); |
|
352 |
|
353 synthesizeKeyExpectEvent("VK_UP", {}, tree, "!select", "key up"); |
|
354 testtag_tree_TreeSelection_State(tree, testid + "key up", 0, [0], 0); |
|
355 |
|
356 synthesizeKeyExpectEvent("VK_UP", {}, tree, "!select", "key up at start"); |
|
357 testtag_tree_TreeSelection_State(tree, testid + "key up at start", 0, [0], 0); |
|
358 |
|
359 // pressing down while the last row is selected should not fire a select event, |
|
360 // as the selection won't have changed. Also the view is not scrolled in this case. |
|
361 selection.select(7); |
|
362 synthesizeKeyExpectEvent("VK_DOWN", {}, tree, "!select", "key down at end"); |
|
363 testtag_tree_TreeSelection_State(tree, testid + "key down at end", 7, [7], 0); |
|
364 |
|
365 // pressing keys while at the edge of the visible rows should scroll the list |
|
366 tree.treeBoxObject.scrollToRow(4); |
|
367 selection.select(4); |
|
368 synthesizeKeyExpectEvent("VK_UP", {}, tree, "!select", "key up with scroll"); |
|
369 is(tree.treeBoxObject.getFirstVisibleRow(), 3, testid + "key up with scroll"); |
|
370 |
|
371 tree.treeBoxObject.scrollToRow(0); |
|
372 selection.select(3); |
|
373 synthesizeKeyExpectEvent("VK_DOWN", {}, tree, "!select", "key down with scroll"); |
|
374 is(tree.treeBoxObject.getFirstVisibleRow(), 1, testid + "key down with scroll"); |
|
375 |
|
376 // accel key and cursor movement adjust currentIndex but should not change |
|
377 // the selection. In single selection mode, the selection will not change, |
|
378 // but instead will just scroll up or down a line |
|
379 tree.treeBoxObject.scrollToRow(0); |
|
380 selection.select(1); |
|
381 synthesizeKeyExpectEvent("VK_DOWN", { accelKey: true }, tree, "!select", "key down with accel"); |
|
382 testtag_tree_TreeSelection_State(tree, testid + "key down with accel", multiple ? 2 : 1, [1]); |
|
383 if (!multiple) |
|
384 is(tree.treeBoxObject.getFirstVisibleRow(), 1, testid + "key down with accel and scroll"); |
|
385 |
|
386 tree.treeBoxObject.scrollToRow(4); |
|
387 selection.select(4); |
|
388 synthesizeKeyExpectEvent("VK_UP", { accelKey: true }, tree, "!select", "key up with accel"); |
|
389 testtag_tree_TreeSelection_State(tree, testid + "key up with accel", multiple ? 3 : 4, [4]); |
|
390 if (!multiple) |
|
391 is(tree.treeBoxObject.getFirstVisibleRow(), 3, testid + "key up with accel and scroll"); |
|
392 |
|
393 // do this three times, one for each state of pageUpOrDownMovesSelection, |
|
394 // and then once with the accel key pressed |
|
395 for (var t = 0; t < 3; t++) { |
|
396 var testidmod = (t == 2) ? " with accel" : (t == 1) ? " rev" : ""; |
|
397 var keymod = (t == 2) ? { accelKey: true } : { }; |
|
398 |
|
399 var moveselection = tree.pageUpOrDownMovesSelection; |
|
400 if (t == 2) |
|
401 moveselection = !moveselection; |
|
402 |
|
403 tree.treeBoxObject.scrollToRow(4); |
|
404 selection.currentIndex = 6; |
|
405 selection.select(6); |
|
406 var expected = moveselection ? 4 : 6; |
|
407 synthesizeKeyExpectEvent("VK_PAGE_UP", keymod, tree, "!select", "key page up"); |
|
408 testtag_tree_TreeSelection_State(tree, testid + "key page up" + testidmod, |
|
409 expected, [expected], moveselection ? 4 : 0); |
|
410 |
|
411 expected = moveselection ? 0 : 6; |
|
412 synthesizeKeyExpectEvent("VK_PAGE_UP", keymod, tree, "!select", "key page up again"); |
|
413 testtag_tree_TreeSelection_State(tree, testid + "key page up again" + testidmod, |
|
414 expected, [expected], 0); |
|
415 |
|
416 expected = moveselection ? 0 : 6; |
|
417 synthesizeKeyExpectEvent("VK_PAGE_UP", keymod, tree, "!select", "key page up at start"); |
|
418 testtag_tree_TreeSelection_State(tree, testid + "key page up at start" + testidmod, |
|
419 expected, [expected], 0); |
|
420 |
|
421 tree.treeBoxObject.scrollToRow(0); |
|
422 selection.currentIndex = 1; |
|
423 selection.select(1); |
|
424 expected = moveselection ? 3 : 1; |
|
425 synthesizeKeyExpectEvent("VK_PAGE_DOWN", keymod, tree, "!select", "key page down"); |
|
426 testtag_tree_TreeSelection_State(tree, testid + "key page down" + testidmod, |
|
427 expected, [expected], moveselection ? 0 : 4); |
|
428 |
|
429 expected = moveselection ? 7 : 1; |
|
430 synthesizeKeyExpectEvent("VK_PAGE_DOWN", keymod, tree, "!select", "key page down again"); |
|
431 testtag_tree_TreeSelection_State(tree, testid + "key page down again" + testidmod, |
|
432 expected, [expected], 4); |
|
433 |
|
434 expected = moveselection ? 7 : 1; |
|
435 synthesizeKeyExpectEvent("VK_PAGE_DOWN", keymod, tree, "!select", "key page down at start"); |
|
436 testtag_tree_TreeSelection_State(tree, testid + "key page down at start" + testidmod, |
|
437 expected, [expected], 4); |
|
438 |
|
439 if (t < 2) |
|
440 tree.pageUpOrDownMovesSelection = !tree.pageUpOrDownMovesSelection; |
|
441 } |
|
442 |
|
443 tree.treeBoxObject.scrollToRow(4); |
|
444 selection.select(6); |
|
445 synthesizeKeyExpectEvent("VK_HOME", {}, tree, "!select", "key home"); |
|
446 testtag_tree_TreeSelection_State(tree, testid + "key home", 0, [0], 0); |
|
447 |
|
448 tree.treeBoxObject.scrollToRow(0); |
|
449 selection.select(1); |
|
450 synthesizeKeyExpectEvent("VK_END", {}, tree, "!select", "key end"); |
|
451 testtag_tree_TreeSelection_State(tree, testid + "key end", 7, [7], 4); |
|
452 |
|
453 // in single selection mode, the selection doesn't change in this case |
|
454 tree.treeBoxObject.scrollToRow(4); |
|
455 selection.select(6); |
|
456 synthesizeKeyExpectEvent("VK_HOME", { accelKey: true }, tree, "!select", "key home with accel"); |
|
457 testtag_tree_TreeSelection_State(tree, testid + "key home with accel", multiple ? 0 : 6, [6], 0); |
|
458 |
|
459 tree.treeBoxObject.scrollToRow(0); |
|
460 selection.select(1); |
|
461 synthesizeKeyExpectEvent("VK_END", { accelKey: true }, tree, "!select", "key end with accel"); |
|
462 testtag_tree_TreeSelection_State(tree, testid + "key end with accel", multiple ? 7 : 1, [1], 4); |
|
463 |
|
464 // next, test cursor navigation with selection. Here the select event will be fired |
|
465 selection.select(1); |
|
466 var eventExpected = multiple ? "select" : "!select"; |
|
467 synthesizeKeyExpectEvent("VK_DOWN", { shiftKey: true }, tree, eventExpected, "key shift down to select"); |
|
468 testtag_tree_TreeSelection_State(tree, testid + "key shift down to select", |
|
469 multiple ? 2 : 1, multiple ? [1, 2] : [1]); |
|
470 is(selection.shiftSelectPivot, multiple ? 1 : -1, |
|
471 testid + "key shift down to select shiftSelectPivot"); |
|
472 synthesizeKeyExpectEvent("VK_UP", { shiftKey: true }, tree, eventExpected, "key shift up to unselect"); |
|
473 testtag_tree_TreeSelection_State(tree, testid + "key shift up to unselect", 1, [1]); |
|
474 is(selection.shiftSelectPivot, multiple ? 1 : -1, |
|
475 testid + "key shift up to unselect shiftSelectPivot"); |
|
476 if (multiple) { |
|
477 synthesizeKeyExpectEvent("VK_UP", { shiftKey: true }, tree, "select", "key shift up to select"); |
|
478 testtag_tree_TreeSelection_State(tree, testid + "key shift up to select", 0, [0, 1]); |
|
479 is(selection.shiftSelectPivot, 1, testid + "key shift up to select shiftSelectPivot"); |
|
480 synthesizeKeyExpectEvent("VK_DOWN", { shiftKey: true }, tree, "select", "key shift down to unselect"); |
|
481 testtag_tree_TreeSelection_State(tree, testid + "key shift down to unselect", 1, [1]); |
|
482 is(selection.shiftSelectPivot, 1, testid + "key shift down to unselect shiftSelectPivot"); |
|
483 } |
|
484 |
|
485 // do this twice, one for each state of pageUpOrDownMovesSelection, however |
|
486 // when selecting with the shift key, pageUpOrDownMovesSelection is ignored |
|
487 // and the selection always changes |
|
488 var lastidx = tree.view.rowCount - 1; |
|
489 for (var t = 0; t < 2; t++) { |
|
490 var testidmod = (t == 0) ? "" : " rev"; |
|
491 |
|
492 // If the top or bottom visible row is the current row, pressing shift and |
|
493 // page down / page up selects one page up or one page down. Otherwise, the |
|
494 // selection is made to the top or bottom of the visible area. |
|
495 tree.treeBoxObject.scrollToRow(lastidx - 3); |
|
496 selection.currentIndex = 6; |
|
497 selection.select(6); |
|
498 synthesizeKeyExpectEvent("VK_PAGE_UP", { shiftKey: true }, tree, eventExpected, "key shift page up"); |
|
499 testtag_tree_TreeSelection_State(tree, testid + "key shift page up" + testidmod, |
|
500 multiple ? 4 : 6, multiple ? [4, 5, 6] : [6]); |
|
501 if (multiple) { |
|
502 synthesizeKeyExpectEvent("VK_PAGE_UP", { shiftKey: true }, tree, "select", "key shift page up again"); |
|
503 testtag_tree_TreeSelection_State(tree, testid + "key shift page up again" + testidmod, |
|
504 0, [0, 1, 2, 3, 4, 5, 6]); |
|
505 // no change in the selection, so no select event should be fired |
|
506 synthesizeKeyExpectEvent("VK_PAGE_UP", { shiftKey: true }, tree, "!select", "key shift page up at start"); |
|
507 testtag_tree_TreeSelection_State(tree, testid + "key shift page up at start" + testidmod, |
|
508 0, [0, 1, 2, 3, 4, 5, 6]); |
|
509 // deselect by paging down again |
|
510 synthesizeKeyExpectEvent("VK_PAGE_DOWN", { shiftKey: true }, tree, "select", "key shift page down deselect"); |
|
511 testtag_tree_TreeSelection_State(tree, testid + "key shift page down deselect" + testidmod, |
|
512 3, [3, 4, 5, 6]); |
|
513 } |
|
514 |
|
515 tree.treeBoxObject.scrollToRow(1); |
|
516 selection.currentIndex = 2; |
|
517 selection.select(2); |
|
518 synthesizeKeyExpectEvent("VK_PAGE_DOWN", { shiftKey: true }, tree, eventExpected, "key shift page down"); |
|
519 testtag_tree_TreeSelection_State(tree, testid + "key shift page down" + testidmod, |
|
520 multiple ? 4 : 2, multiple ? [2, 3, 4] : [2]); |
|
521 if (multiple) { |
|
522 synthesizeKeyExpectEvent("VK_PAGE_DOWN", { shiftKey: true }, tree, "select", "key shift page down again"); |
|
523 testtag_tree_TreeSelection_State(tree, testid + "key shift page down again" + testidmod, |
|
524 7, [2, 3, 4, 5, 6, 7]); |
|
525 synthesizeKeyExpectEvent("VK_PAGE_DOWN", { shiftKey: true }, tree, "!select", "key shift page down at start"); |
|
526 testtag_tree_TreeSelection_State(tree, testid + "key shift page down at start" + testidmod, |
|
527 7, [2, 3, 4, 5, 6, 7]); |
|
528 synthesizeKeyExpectEvent("VK_PAGE_UP", { shiftKey: true }, tree, "select", "key shift page up deselect"); |
|
529 testtag_tree_TreeSelection_State(tree, testid + "key shift page up deselect" + testidmod, |
|
530 4, [2, 3, 4]); |
|
531 } |
|
532 |
|
533 // test when page down / page up is pressed when the view is scrolled such |
|
534 // that the selection is not visible |
|
535 if (multiple) { |
|
536 tree.treeBoxObject.scrollToRow(3); |
|
537 selection.currentIndex = 1; |
|
538 selection.select(1); |
|
539 synthesizeKeyExpectEvent("VK_PAGE_DOWN", { shiftKey: true }, tree, eventExpected, |
|
540 "key shift page down with view scrolled down"); |
|
541 testtag_tree_TreeSelection_State(tree, testid + "key shift page down with view scrolled down" + testidmod, |
|
542 6, [1, 2, 3, 4, 5, 6], 3); |
|
543 |
|
544 tree.treeBoxObject.scrollToRow(2); |
|
545 selection.currentIndex = 6; |
|
546 selection.select(6); |
|
547 synthesizeKeyExpectEvent("VK_PAGE_UP", { shiftKey: true }, tree, eventExpected, |
|
548 "key shift page up with view scrolled up"); |
|
549 testtag_tree_TreeSelection_State(tree, testid + "key shift page up with view scrolled up" + testidmod, |
|
550 2, [2, 3, 4, 5, 6], 2); |
|
551 |
|
552 tree.treeBoxObject.scrollToRow(2); |
|
553 selection.currentIndex = 0; |
|
554 selection.select(0); |
|
555 // don't expect the select event, as the selection won't have changed |
|
556 synthesizeKeyExpectEvent("VK_PAGE_UP", { shiftKey: true }, tree, "!select", |
|
557 "key shift page up at start with view scrolled down"); |
|
558 testtag_tree_TreeSelection_State(tree, testid + "key shift page up at start with view scrolled down" + testidmod, |
|
559 0, [0], 0); |
|
560 |
|
561 tree.treeBoxObject.scrollToRow(0); |
|
562 selection.currentIndex = 7; |
|
563 selection.select(7); |
|
564 // don't expect the select event, as the selection won't have changed |
|
565 synthesizeKeyExpectEvent("VK_PAGE_DOWN", { shiftKey: true }, tree, "!select", |
|
566 "key shift page down at end with view scrolled up"); |
|
567 testtag_tree_TreeSelection_State(tree, testid + "key shift page down at end with view scrolled up" + testidmod, |
|
568 7, [7], 4); |
|
569 } |
|
570 |
|
571 tree.pageUpOrDownMovesSelection = !tree.pageUpOrDownMovesSelection; |
|
572 } |
|
573 |
|
574 tree.treeBoxObject.scrollToRow(4); |
|
575 selection.select(5); |
|
576 synthesizeKeyExpectEvent("VK_HOME", { shiftKey: true }, tree, eventExpected, "key shift home"); |
|
577 testtag_tree_TreeSelection_State(tree, testid + "key shift home", |
|
578 multiple ? 0 : 5, multiple ? [0, 1, 2, 3, 4, 5] : [5], multiple ? 0 : 4); |
|
579 |
|
580 tree.treeBoxObject.scrollToRow(0); |
|
581 selection.select(3); |
|
582 synthesizeKeyExpectEvent("VK_END", { shiftKey: true }, tree, eventExpected, "key shift end"); |
|
583 testtag_tree_TreeSelection_State(tree, testid + "key shift end", |
|
584 multiple ? 7 : 3, multiple ? [3, 4, 5, 6, 7] : [3], multiple ? 4 : 0); |
|
585 |
|
586 // pressing space selects a row, pressing accel + space unselects a row |
|
587 selection.select(2); |
|
588 selection.currentIndex = 4; |
|
589 synthesizeKeyExpectEvent(" ", {}, tree, "select", "key space on"); |
|
590 // in single selection mode, space shouldn't do anything |
|
591 testtag_tree_TreeSelection_State(tree, testid + "key space on", 4, multiple ? [2, 4] : [2]); |
|
592 |
|
593 if (multiple) { |
|
594 synthesizeKeyExpectEvent(" ", { accelKey: true }, tree, "select", "key space off"); |
|
595 testtag_tree_TreeSelection_State(tree, testid + "key space off", 4, [2]); |
|
596 } |
|
597 |
|
598 // check that clicking on a row selects it |
|
599 tree.treeBoxObject.scrollToRow(0); |
|
600 selection.select(2); |
|
601 selection.currentIndex = 2; |
|
602 if (0) { // XXXndeakin disable these tests for now |
|
603 mouseOnCell(tree, 1, tree.columns[1], "mouse on row"); |
|
604 testtag_tree_TreeSelection_State(tree, testid + "mouse on row", 1, [1], 0, |
|
605 tree.selType == "cell" ? tree.columns[1] : null); |
|
606 } |
|
607 |
|
608 // restore the scroll position to the start of the page |
|
609 sendKey("HOME"); |
|
610 |
|
611 window.removeEventListener("keydown", keydownListener, false); |
|
612 window.removeEventListener("keypress", keypressListener, false); |
|
613 is(keydownFired, multiple ? 63 : 40, "keydown event wasn't fired properly"); |
|
614 is(keypressFired, multiple ? 2 : 1, "keypress event wasn't fired properly"); |
|
615 } |
|
616 |
|
617 function testtag_tree_UI_editing(tree, testid, rowInfo) |
|
618 { |
|
619 testid += " editing UI "; |
|
620 |
|
621 // check editing UI |
|
622 var ecolumn = tree.columns[0]; |
|
623 var rowIndex = 2; |
|
624 var inputField = tree.inputField; |
|
625 |
|
626 // temporary make the tree editable to test mouse double click |
|
627 var wasEditable = tree.editable; |
|
628 if (!wasEditable) |
|
629 tree.editable = true; |
|
630 |
|
631 // if this is a container save its current open status |
|
632 var row = rowInfo.rows[rowIndex]; |
|
633 var wasOpen = null; |
|
634 if (tree.view.isContainer(row)) |
|
635 wasOpen = tree.view.isContainerOpen(row); |
|
636 |
|
637 // Test whether a keystroke can enter text entry, and another can exit. |
|
638 if (tree.selType == "cell") |
|
639 { |
|
640 tree.stopEditing(false); |
|
641 ok(!tree.editingColumn, "Should not be editing tree cell now"); |
|
642 tree.view.selection.currentColumn = ecolumn; |
|
643 tree.currentIndex = rowIndex; |
|
644 |
|
645 const isMac = (navigator.platform.indexOf("Mac") >= 0); |
|
646 const StartEditingKey = isMac ? "RETURN" : "F2"; |
|
647 sendKey(StartEditingKey); |
|
648 is(tree.editingColumn, ecolumn, "Should be editing tree cell now"); |
|
649 sendKey("ESCAPE"); |
|
650 ok(!tree.editingColumn, "Should not be editing tree cell now"); |
|
651 is(tree.currentIndex, rowIndex, "Current index should not have changed"); |
|
652 is(tree.view.selection.currentColumn, ecolumn, "Current column should not have changed"); |
|
653 } |
|
654 |
|
655 mouseDblClickOnCell(tree, rowIndex, ecolumn, testid + "edit on double click"); |
|
656 is(tree.editingColumn, ecolumn, testid + "editing column"); |
|
657 is(tree.editingRow, rowIndex, testid + "editing row"); |
|
658 |
|
659 // ensure that we don't expand an expandable container on edit |
|
660 if (wasOpen != null) |
|
661 is(tree.view.isContainerOpen(row), wasOpen, testid + "opened container node on edit"); |
|
662 |
|
663 // ensure to restore editable attribute |
|
664 if (!wasEditable) |
|
665 tree.editable = false; |
|
666 |
|
667 var ci = tree.currentIndex; |
|
668 |
|
669 // cursor navigation should not change the selection while editing |
|
670 var testKey = function(key) { |
|
671 synthesizeKeyExpectEvent(key, {}, tree, "!select", "key " + key + " with editing"); |
|
672 is(tree.editingRow == rowIndex && tree.editingColumn == ecolumn && tree.currentIndex == ci, |
|
673 true, testid + "key " + key + " while editing"); |
|
674 } |
|
675 |
|
676 testKey("VK_DOWN"); |
|
677 testKey("VK_UP"); |
|
678 testKey("VK_PAGE_DOWN"); |
|
679 testKey("VK_PAGE_UP"); |
|
680 testKey("VK_HOME"); |
|
681 testKey("VK_END"); |
|
682 |
|
683 // XXXndeakin figure out how to send characters to the textbox |
|
684 // inputField.inputField.focus() |
|
685 // synthesizeKeyExpectEvent(inputField.inputField, "b", null, ""); |
|
686 // tree.stopEditing(true); |
|
687 // is(tree.view.getCellText(0, ecolumn), "b", testid + "edit cell"); |
|
688 |
|
689 // Restore initial state. |
|
690 tree.stopEditing(false); |
|
691 } |
|
692 |
|
693 function testtag_tree_TreeSelection_UI_cell(tree, testid, rowInfo) |
|
694 { |
|
695 testid += " selection UI cell "; |
|
696 |
|
697 var columns = tree.columns; |
|
698 var firstcolumn = columns[0]; |
|
699 var secondcolumn = columns[1]; |
|
700 var lastcolumn = columns[columns.length - 1]; |
|
701 var secondlastcolumn = columns[columns.length - 2]; |
|
702 var selection = tree.view.selection; |
|
703 |
|
704 selection.clearSelection(); |
|
705 selection.currentIndex = -1; |
|
706 selection.currentColumn = firstcolumn; |
|
707 is(selection.currentColumn, firstcolumn, testid + " first currentColumn"); |
|
708 |
|
709 // no selection yet so nothing should happen when the left and right cursor keys are pressed |
|
710 synthesizeKeyExpectEvent("VK_RIGHT", {}, tree, "!select", "key right no selection"); |
|
711 testtag_tree_TreeSelection_State(tree, testid + "key right no selection", -1, [], null, firstcolumn); |
|
712 |
|
713 selection.currentColumn = secondcolumn; |
|
714 synthesizeKeyExpectEvent("VK_LEFT", {}, tree, "!select", "key left no selection"); |
|
715 testtag_tree_TreeSelection_State(tree, testid + "key left no selection", -1, [], null, secondcolumn); |
|
716 |
|
717 selection.select(2); |
|
718 selection.currentIndex = 2; |
|
719 if (0) { // XXXndeakin disable these tests for now |
|
720 mouseOnCell(tree, 1, secondlastcolumn, "mouse on cell"); |
|
721 testtag_tree_TreeSelection_State(tree, testid + "mouse on cell", 1, [1], null, secondlastcolumn); |
|
722 } |
|
723 |
|
724 tree.focus(); |
|
725 |
|
726 // selection is set, so it should move when the left and right cursor keys are pressed |
|
727 tree.treeBoxObject.scrollToRow(0); |
|
728 selection.select(1); |
|
729 selection.currentIndex = 1; |
|
730 selection.currentColumn = secondcolumn; |
|
731 synthesizeKeyExpectEvent("VK_LEFT", {}, tree, "!select", "key left in second column"); |
|
732 testtag_tree_TreeSelection_State(tree, testid + "key left in second column", 1, [1], 0, firstcolumn); |
|
733 |
|
734 synthesizeKeyExpectEvent("VK_LEFT", {}, tree, "!select", "key left in first column"); |
|
735 testtag_tree_TreeSelection_State(tree, testid + "key left in first column", 1, [1], 0, firstcolumn); |
|
736 |
|
737 selection.currentColumn = secondlastcolumn; |
|
738 synthesizeKeyExpectEvent("VK_RIGHT", {}, tree, "!select", "key right in second last column"); |
|
739 testtag_tree_TreeSelection_State(tree, testid + "key right in second last column", 1, [1], 0, lastcolumn); |
|
740 |
|
741 synthesizeKeyExpectEvent("VK_RIGHT", {}, tree, "!select", "key right in last column"); |
|
742 testtag_tree_TreeSelection_State(tree, testid + "key right in last column", 1, [1], 0, lastcolumn); |
|
743 |
|
744 synthesizeKeyExpectEvent("VK_UP", {}, tree, "!select", "key up in second row"); |
|
745 testtag_tree_TreeSelection_State(tree, testid + "key up in second row", 0, [0], 0, lastcolumn); |
|
746 |
|
747 synthesizeKeyExpectEvent("VK_UP", {}, tree, "!select", "key up in first row"); |
|
748 testtag_tree_TreeSelection_State(tree, testid + "key up in first row", 0, [0], 0, lastcolumn); |
|
749 |
|
750 synthesizeKeyExpectEvent("VK_DOWN", {}, tree, "!select", "key down in first row"); |
|
751 testtag_tree_TreeSelection_State(tree, testid + "key down in first row", 1, [1], 0, lastcolumn); |
|
752 |
|
753 var lastidx = tree.view.rowCount - 1; |
|
754 tree.treeBoxObject.scrollToRow(lastidx - 3); |
|
755 selection.select(lastidx); |
|
756 selection.currentIndex = lastidx; |
|
757 synthesizeKeyExpectEvent("VK_DOWN", {}, tree, "!select", "key down in last row"); |
|
758 testtag_tree_TreeSelection_State(tree, testid + "key down in last row", lastidx, [lastidx], lastidx - 3, lastcolumn); |
|
759 |
|
760 synthesizeKeyExpectEvent("VK_HOME", {}, tree, "!select", "key home"); |
|
761 testtag_tree_TreeSelection_State(tree, testid + "key home", 0, [0], 0, lastcolumn); |
|
762 |
|
763 synthesizeKeyExpectEvent("VK_END", {}, tree, "!select", "key end"); |
|
764 testtag_tree_TreeSelection_State(tree, testid + "key end", lastidx, [lastidx], lastidx - 3, lastcolumn); |
|
765 |
|
766 for (var t = 0; t < 2; t++) { |
|
767 var testidmod = (t == 0) ? "" : " rev"; |
|
768 |
|
769 // scroll to the end, subtract 3 because we want lastidx to appear |
|
770 // at the end of view |
|
771 tree.treeBoxObject.scrollToRow(lastidx - 3); |
|
772 selection.select(lastidx); |
|
773 selection.currentIndex = lastidx; |
|
774 var expectedrow = tree.pageUpOrDownMovesSelection ? lastidx - 3 : lastidx; |
|
775 synthesizeKeyExpectEvent("VK_PAGE_UP", {}, tree, "!select", "key page up"); |
|
776 testtag_tree_TreeSelection_State(tree, testid + "key page up" + testidmod, |
|
777 expectedrow, [expectedrow], |
|
778 tree.pageUpOrDownMovesSelection ? lastidx - 3 : 0, lastcolumn); |
|
779 |
|
780 tree.treeBoxObject.scrollToRow(1); |
|
781 selection.select(1); |
|
782 selection.currentIndex = 1; |
|
783 var expectedrow = tree.pageUpOrDownMovesSelection ? 4 : 1; |
|
784 synthesizeKeyExpectEvent("VK_PAGE_DOWN", {}, tree, "!select", "key page down"); |
|
785 testtag_tree_TreeSelection_State(tree, testid + "key page down" + testidmod, |
|
786 expectedrow, [expectedrow], |
|
787 tree.pageUpOrDownMovesSelection ? 1 : lastidx - 3, lastcolumn); |
|
788 |
|
789 tree.pageUpOrDownMovesSelection = !tree.pageUpOrDownMovesSelection; |
|
790 } |
|
791 |
|
792 // now check navigation when there is unselctable column |
|
793 secondcolumn.element.setAttribute("selectable", "false"); |
|
794 secondcolumn.invalidate(); |
|
795 is(secondcolumn.selectable, false, testid + "set selectable attribute"); |
|
796 |
|
797 if (columns.length >= 3) { |
|
798 selection.select(3); |
|
799 selection.currentIndex = 3; |
|
800 // check whether unselectable columns are skipped over |
|
801 selection.currentColumn = firstcolumn; |
|
802 synthesizeKeyExpectEvent("VK_RIGHT", {}, tree, "!select", "key right unselectable column"); |
|
803 testtag_tree_TreeSelection_State(tree, testid + "key right unselectable column", |
|
804 3, [3], null, secondcolumn.getNext()); |
|
805 |
|
806 synthesizeKeyExpectEvent("VK_LEFT", {}, tree, "!select", "key left unselectable column"); |
|
807 testtag_tree_TreeSelection_State(tree, testid + "key left unselectable column", |
|
808 3, [3], null, firstcolumn); |
|
809 } |
|
810 |
|
811 secondcolumn.element.removeAttribute("selectable"); |
|
812 secondcolumn.invalidate(); |
|
813 is(secondcolumn.selectable, true, testid + "clear selectable attribute"); |
|
814 |
|
815 // check to ensure that navigation isn't allowed if the first column is not selectable |
|
816 selection.currentColumn = secondcolumn; |
|
817 firstcolumn.element.setAttribute("selectable", "false"); |
|
818 firstcolumn.invalidate(); |
|
819 synthesizeKeyExpectEvent("VK_LEFT", {}, tree, "!select", "key left unselectable first column"); |
|
820 testtag_tree_TreeSelection_State(tree, testid + "key left unselectable first column", |
|
821 3, [3], null, secondcolumn); |
|
822 firstcolumn.element.removeAttribute("selectable"); |
|
823 firstcolumn.invalidate(); |
|
824 |
|
825 // check to ensure that navigation isn't allowed if the last column is not selectable |
|
826 selection.currentColumn = secondlastcolumn; |
|
827 lastcolumn.element.setAttribute("selectable", "false"); |
|
828 lastcolumn.invalidate(); |
|
829 synthesizeKeyExpectEvent("VK_RIGHT", {}, tree, "!select", "key right unselectable last column"); |
|
830 testtag_tree_TreeSelection_State(tree, testid + "key right unselectable last column", |
|
831 3, [3], null, secondlastcolumn); |
|
832 lastcolumn.element.removeAttribute("selectable"); |
|
833 lastcolumn.invalidate(); |
|
834 |
|
835 // now check for cells with selectable false |
|
836 if (!rowInfo.rows[4].cells[1].selectable && columns.length >= 3) { |
|
837 // check whether unselectable cells are skipped over |
|
838 selection.select(4); |
|
839 selection.currentIndex = 4; |
|
840 |
|
841 selection.currentColumn = firstcolumn; |
|
842 synthesizeKeyExpectEvent("VK_RIGHT", {}, tree, "!select", "key right unselectable cell"); |
|
843 testtag_tree_TreeSelection_State(tree, testid + "key right unselectable cell", |
|
844 4, [4], null, secondcolumn.getNext()); |
|
845 |
|
846 synthesizeKeyExpectEvent("VK_LEFT", {}, tree, "!select", "key left unselectable cell"); |
|
847 testtag_tree_TreeSelection_State(tree, testid + "key left unselectable cell", |
|
848 4, [4], null, firstcolumn); |
|
849 |
|
850 tree.treeBoxObject.scrollToRow(1); |
|
851 selection.select(3); |
|
852 selection.currentIndex = 3; |
|
853 selection.currentColumn = secondcolumn; |
|
854 |
|
855 synthesizeKeyExpectEvent("VK_DOWN", {}, tree, "!select", "key down unselectable cell"); |
|
856 testtag_tree_TreeSelection_State(tree, testid + "key down unselectable cell", |
|
857 5, [5], 2, secondcolumn); |
|
858 |
|
859 tree.treeBoxObject.scrollToRow(4); |
|
860 synthesizeKeyExpectEvent("VK_UP", {}, tree, "!select", "key up unselectable cell"); |
|
861 testtag_tree_TreeSelection_State(tree, testid + "key up unselectable cell", |
|
862 3, [3], 3, secondcolumn); |
|
863 } |
|
864 |
|
865 // restore the scroll position to the start of the page |
|
866 sendKey("HOME"); |
|
867 } |
|
868 |
|
869 function testtag_tree_TreeView(tree, testid, rowInfo) |
|
870 { |
|
871 testid += " view "; |
|
872 |
|
873 var columns = tree.columns; |
|
874 var view = tree.view; |
|
875 |
|
876 is(view instanceof Components.interfaces.nsITreeView, true, testid + "view is a TreeView"); |
|
877 is(view.rowCount, rowInfo.rows.length, testid + "rowCount"); |
|
878 |
|
879 testtag_tree_TreeView_rows(tree, testid, rowInfo, 0); |
|
880 |
|
881 // note that this will only work for content trees currently |
|
882 view.setCellText(0, columns[1], "Changed Value"); |
|
883 is(view.getCellText(0, columns[1]), "Changed Value", "setCellText"); |
|
884 |
|
885 view.setCellValue(1, columns[0], "Another Changed Value"); |
|
886 is(view.getCellValue(1, columns[0]), "Another Changed Value", "setCellText"); |
|
887 } |
|
888 |
|
889 function testtag_tree_TreeView_rows(tree, testid, rowInfo, startRow) |
|
890 { |
|
891 var r; |
|
892 var columns = tree.columns; |
|
893 var view = tree.view; |
|
894 var length = rowInfo.rows.length; |
|
895 |
|
896 // methods to test along with the functions which determine the expected value |
|
897 var checkRowMethods = |
|
898 { |
|
899 isContainer: function(row) { return row.container }, |
|
900 isContainerOpen: function(row) { return false }, |
|
901 isContainerEmpty: function(row) { return (row.children != null && row.children.rows.length == 0) }, |
|
902 isSeparator: function(row) { return row.separator }, |
|
903 getRowProperties: function(row) { return row.properties }, |
|
904 getLevel: function(row) { return row.level }, |
|
905 getParentIndex: function(row) { return row.parent }, |
|
906 hasNextSibling: function(row) { return r < startRow + length - 1; } |
|
907 }; |
|
908 |
|
909 var checkCellMethods = |
|
910 { |
|
911 getCellText: function(row, cell) { return cell.label }, |
|
912 getCellValue: function(row, cell) { return cell.value }, |
|
913 getCellProperties: function(row, cell) { return cell.properties }, |
|
914 isEditable: function(row, cell) { return cell.editable }, |
|
915 isSelectable: function(row, cell) { return cell.selectable }, |
|
916 getImageSrc: function(row, cell) { return cell.image }, |
|
917 getProgressMode: function(row, cell) { return cell.mode } |
|
918 }; |
|
919 |
|
920 var failedMethods = { }; |
|
921 var checkMethod, actual, expected; |
|
922 var containerInfo = null; |
|
923 var toggleOpenStateOK = true; |
|
924 |
|
925 for (r = startRow; r < length; r++) { |
|
926 var row = rowInfo.rows[r]; |
|
927 for (var c = 0; c < row.cells.length; c++) { |
|
928 var cell = row.cells[c]; |
|
929 |
|
930 for (checkMethod in checkCellMethods) { |
|
931 expected = checkCellMethods[checkMethod](row, cell); |
|
932 actual = view[checkMethod](r, columns[c]); |
|
933 if (actual !== expected) { |
|
934 failedMethods[checkMethod] = true; |
|
935 is(actual, expected, testid + "row " + r + " column " + c + " " + checkMethod + " is incorrect"); |
|
936 } |
|
937 } |
|
938 } |
|
939 |
|
940 // compare row properties |
|
941 for (checkMethod in checkRowMethods) { |
|
942 expected = checkRowMethods[checkMethod](row, r); |
|
943 if (checkMethod == "hasNextSibling") { |
|
944 actual = view[checkMethod](r, r); |
|
945 } |
|
946 else { |
|
947 actual = view[checkMethod](r); |
|
948 } |
|
949 if (actual !== expected) { |
|
950 failedMethods[checkMethod] = true; |
|
951 is(actual, expected, testid + "row " + r + " " + checkMethod + " is incorrect"); |
|
952 } |
|
953 } |
|
954 /* |
|
955 // open and recurse into containers |
|
956 if (row.container) { |
|
957 view.toggleOpenState(r); |
|
958 if (!view.isContainerOpen(r)) { |
|
959 toggleOpenStateOK = false; |
|
960 is(view.isContainerOpen(r), true, testid + "row " + r + " toggleOpenState open"); |
|
961 } |
|
962 testtag_tree_TreeView_rows(tree, testid + "container " + r + " ", row.children, r + 1); |
|
963 view.toggleOpenState(r); |
|
964 if (view.isContainerOpen(r)) { |
|
965 toggleOpenStateOK = false; |
|
966 is(view.isContainerOpen(r), false, testid + "row " + r + " toggleOpenState close"); |
|
967 } |
|
968 } |
|
969 */ |
|
970 } |
|
971 |
|
972 for (var failedMethod in failedMethods) { |
|
973 if (failedMethod in checkRowMethods) |
|
974 delete checkRowMethods[failedMethod]; |
|
975 if (failedMethod in checkCellMethods) |
|
976 delete checkCellMethods[failedMethod]; |
|
977 } |
|
978 |
|
979 for (checkMethod in checkRowMethods) |
|
980 is(checkMethod + " ok", checkMethod + " ok", testid + checkMethod); |
|
981 for (checkMethod in checkCellMethods) |
|
982 is(checkMethod + " ok", checkMethod + " ok", testid + checkMethod); |
|
983 if (toggleOpenStateOK) |
|
984 is("toggleOpenState ok", "toggleOpenState ok", testid + "toggleOpenState"); |
|
985 } |
|
986 |
|
987 function testtag_tree_TreeView_rows_sort(tree, testid, rowInfo) |
|
988 { |
|
989 // check if cycleHeader sorts the columns |
|
990 var columnIndex = 0; |
|
991 var view = tree.view; |
|
992 var column = tree.columns[columnIndex]; |
|
993 var columnElement = column.element; |
|
994 var sortkey = columnElement.getAttribute("sort"); |
|
995 if (sortkey) { |
|
996 view.cycleHeader(column); |
|
997 is(tree.getAttribute("sort"), sortkey, "cycleHeader sort"); |
|
998 is(tree.getAttribute("sortDirection"), "ascending", "cycleHeader sortDirection ascending"); |
|
999 is(columnElement.getAttribute("sortDirection"), "ascending", "cycleHeader column sortDirection"); |
|
1000 is(columnElement.getAttribute("sortActive"), "true", "cycleHeader column sortActive"); |
|
1001 view.cycleHeader(column); |
|
1002 is(tree.getAttribute("sortDirection"), "descending", "cycleHeader sortDirection descending"); |
|
1003 is(columnElement.getAttribute("sortDirection"), "descending", "cycleHeader column sortDirection descending"); |
|
1004 view.cycleHeader(column); |
|
1005 is(tree.getAttribute("sortDirection"), "", "cycleHeader sortDirection natural"); |
|
1006 is(columnElement.getAttribute("sortDirection"), "", "cycleHeader column sortDirection natural"); |
|
1007 // XXXndeakin content view isSorted needs to be tested |
|
1008 } |
|
1009 |
|
1010 // Check that clicking on column header sorts the column. |
|
1011 var columns = getSortedColumnArray(tree); |
|
1012 is(columnElement.getAttribute("sortDirection"), "", |
|
1013 "cycleHeader column sortDirection"); |
|
1014 |
|
1015 // Click once on column header and check sorting has cycled once. |
|
1016 mouseClickOnColumnHeader(columns, columnIndex, 0, 1); |
|
1017 is(columnElement.getAttribute("sortDirection"), "ascending", |
|
1018 "single click cycleHeader column sortDirection ascending"); |
|
1019 |
|
1020 // Now simulate a double click. |
|
1021 mouseClickOnColumnHeader(columns, columnIndex, 0, 2); |
|
1022 if (navigator.platform.indexOf("Win") == 0) { |
|
1023 // Windows cycles only once on double click. |
|
1024 is(columnElement.getAttribute("sortDirection"), "descending", |
|
1025 "double click cycleHeader column sortDirection descending"); |
|
1026 // 1 single clicks should restore natural sorting. |
|
1027 mouseClickOnColumnHeader(columns, columnIndex, 0, 1); |
|
1028 } |
|
1029 |
|
1030 // Check we have gone back to natural sorting. |
|
1031 is(columnElement.getAttribute("sortDirection"), "", |
|
1032 "cycleHeader column sortDirection"); |
|
1033 |
|
1034 columnElement.setAttribute("sorthints", "twostate"); |
|
1035 view.cycleHeader(column); |
|
1036 is(tree.getAttribute("sortDirection"), "ascending", "cycleHeader sortDirection ascending twostate"); |
|
1037 view.cycleHeader(column); |
|
1038 is(tree.getAttribute("sortDirection"), "descending", "cycleHeader sortDirection ascending twostate"); |
|
1039 view.cycleHeader(column); |
|
1040 is(tree.getAttribute("sortDirection"), "ascending", "cycleHeader sortDirection ascending twostate again"); |
|
1041 columnElement.removeAttribute("sorthints"); |
|
1042 view.cycleHeader(column); |
|
1043 view.cycleHeader(column); |
|
1044 |
|
1045 is(columnElement.getAttribute("sortDirection"), "", |
|
1046 "cycleHeader column sortDirection reset"); |
|
1047 } |
|
1048 |
|
1049 // checks if the current and selected rows are correct |
|
1050 // current is the index of the current row |
|
1051 // selected is an array of the indicies of the selected rows |
|
1052 // column is the selected column |
|
1053 // viewidx is the row that should be visible at the top of the tree |
|
1054 function testtag_tree_TreeSelection_State(tree, testid, current, selected, viewidx, column) |
|
1055 { |
|
1056 var selection = tree.view.selection; |
|
1057 |
|
1058 if (!column) |
|
1059 column = (tree.selType == "cell") ? tree.columns[0] : null; |
|
1060 |
|
1061 is(selection.count, selected.length, testid + " count"); |
|
1062 is(tree.currentIndex, current, testid + " currentIndex"); |
|
1063 is(selection.currentIndex, current, testid + " TreeSelection currentIndex"); |
|
1064 is(selection.currentColumn, column, testid + " currentColumn"); |
|
1065 if (viewidx !== null && viewidx !== undefined) |
|
1066 is(tree.treeBoxObject.getFirstVisibleRow(), viewidx, testid + " first visible row"); |
|
1067 |
|
1068 var actualSelected = []; |
|
1069 var count = tree.view.rowCount; |
|
1070 for (var s = 0; s < count; s++) { |
|
1071 if (selection.isSelected(s)) |
|
1072 actualSelected.push(s); |
|
1073 } |
|
1074 |
|
1075 is(compareArrays(selected, actualSelected), true, testid + " selection [" + selected + "]"); |
|
1076 |
|
1077 actualSelected = []; |
|
1078 var rangecount = selection.getRangeCount(); |
|
1079 for (var r = 0; r < rangecount; r++) { |
|
1080 var start = {}, end = {}; |
|
1081 selection.getRangeAt(r, start, end); |
|
1082 for (var rs = start.value; rs <= end.value; rs++) |
|
1083 actualSelected.push(rs); |
|
1084 } |
|
1085 |
|
1086 is(compareArrays(selected, actualSelected), true, testid + " range selection [" + selected + "]"); |
|
1087 } |
|
1088 |
|
1089 function testtag_tree_column_reorder() |
|
1090 { |
|
1091 // Make sure the tree is scrolled into the view, otherwise the test will |
|
1092 // fail |
|
1093 var testframe = window.parent.document.getElementById("testframe"); |
|
1094 if (testframe) { |
|
1095 testframe.scrollIntoView(); |
|
1096 } |
|
1097 |
|
1098 var tree = document.getElementById("tree-column-reorder"); |
|
1099 var numColumns = tree.columns.count; |
|
1100 |
|
1101 var reference = []; |
|
1102 for (var i = 0; i < numColumns; i++) { |
|
1103 reference.push("col_" + i); |
|
1104 } |
|
1105 |
|
1106 // Drag the first column to each position |
|
1107 for (var i = 0; i < numColumns - 1; i++) { |
|
1108 synthesizeColumnDrag(tree, i, i + 1, true); |
|
1109 arrayMove(reference, i, i + 1, true); |
|
1110 checkColumns(tree, reference, "drag first column right"); |
|
1111 } |
|
1112 |
|
1113 // And back |
|
1114 for (var i = numColumns - 1; i >= 1; i--) { |
|
1115 synthesizeColumnDrag(tree, i, i - 1, false); |
|
1116 arrayMove(reference, i, i - 1, false); |
|
1117 checkColumns(tree, reference, "drag last column left"); |
|
1118 } |
|
1119 |
|
1120 // Drag each column one column left |
|
1121 for (var i = 1; i < numColumns; i++) { |
|
1122 synthesizeColumnDrag(tree, i, i - 1, false); |
|
1123 arrayMove(reference, i, i - 1, false); |
|
1124 checkColumns(tree, reference, "drag each column left"); |
|
1125 } |
|
1126 |
|
1127 // And back |
|
1128 for (var i = numColumns - 2; i >= 0; i--) { |
|
1129 synthesizeColumnDrag(tree, i, i + 1, true); |
|
1130 arrayMove(reference, i, i + 1, true); |
|
1131 checkColumns(tree, reference, "drag each column right"); |
|
1132 } |
|
1133 |
|
1134 // Drag each column 5 to the right |
|
1135 for (var i = 0; i < numColumns - 5; i++) { |
|
1136 synthesizeColumnDrag(tree, i, i + 5, true); |
|
1137 arrayMove(reference, i, i + 5, true); |
|
1138 checkColumns(tree, reference, "drag each column 5 to the right"); |
|
1139 } |
|
1140 |
|
1141 // And to the left |
|
1142 for (var i = numColumns - 6; i >= 5; i--) { |
|
1143 synthesizeColumnDrag(tree, i, i - 5, false); |
|
1144 arrayMove(reference, i, i - 5, false); |
|
1145 checkColumns(tree, reference, "drag each column 5 to the left"); |
|
1146 } |
|
1147 |
|
1148 // Test that moving a column after itself does not move anything |
|
1149 synthesizeColumnDrag(tree, 0, 0, true); |
|
1150 checkColumns(tree, reference, "drag to itself"); |
|
1151 is(document.treecolDragging, null, "drag to itself completed"); |
|
1152 |
|
1153 // XXX roc should this be here??? |
|
1154 SimpleTest.finish(); |
|
1155 } |
|
1156 |
|
1157 function testtag_tree_wheel(aTree) |
|
1158 { |
|
1159 const deltaModes = [ |
|
1160 WheelEvent.DOM_DELTA_PIXEL, // 0 |
|
1161 WheelEvent.DOM_DELTA_LINE, // 1 |
|
1162 WheelEvent.DOM_DELTA_PAGE // 2 |
|
1163 ]; |
|
1164 function helper(aStart, aDelta, aIntDelta, aDeltaMode) |
|
1165 { |
|
1166 aTree.treeBoxObject.scrollToRow(aStart); |
|
1167 var expected = !aIntDelta ? aStart : |
|
1168 aDeltaMode != WheelEvent.DOM_DELTA_PAGE ? aStart + aIntDelta : |
|
1169 aIntDelta > 0 ? aStart + aTree.treeBoxObject.getPageLength() : |
|
1170 aStart - aTree.treeBoxObject.getPageLength(); |
|
1171 if (expected < 0) { |
|
1172 expected = 0; |
|
1173 } |
|
1174 if (expected > aTree.view.rowCount - aTree.treeBoxObject.getPageLength()) { |
|
1175 expected = aTree.view.rowCount - aTree.treeBoxObject.getPageLength(); |
|
1176 } |
|
1177 synthesizeWheel(aTree.body, 1, 1, |
|
1178 { deltaMode: aDeltaMode, deltaY: aDelta, |
|
1179 lineOrPageDeltaY: aIntDelta }); |
|
1180 is(aTree.treeBoxObject.getFirstVisibleRow(), expected, |
|
1181 "testtag_tree_wheel: vertical, starting " + aStart + |
|
1182 " delta " + aDelta + " lineOrPageDelta " + aIntDelta + |
|
1183 " aDeltaMode " + aDeltaMode); |
|
1184 |
|
1185 aTree.treeBoxObject.scrollToRow(aStart); |
|
1186 // Check that horizontal scrolling has no effect |
|
1187 synthesizeWheel(aTree.body, 1, 1, |
|
1188 { deltaMode: aDeltaMode, deltaX: aDelta, |
|
1189 lineOrPageDeltaX: aIntDelta }); |
|
1190 is(aTree.treeBoxObject.getFirstVisibleRow(), aStart, |
|
1191 "testtag_tree_wheel: horizontal, starting " + aStart + |
|
1192 " delta " + aDelta + " lineOrPageDelta " + aIntDelta + |
|
1193 " aDeltaMode " + aDeltaMode); |
|
1194 } |
|
1195 |
|
1196 var defaultPrevented = 0; |
|
1197 |
|
1198 function wheelListener(event) { |
|
1199 defaultPrevented++; |
|
1200 } |
|
1201 window.addEventListener("wheel", wheelListener, false); |
|
1202 |
|
1203 deltaModes.forEach(function(aDeltaMode) { |
|
1204 var delta = (aDeltaMode == WheelEvent.DOM_DELTA_PIXEL) ? 5.0 : 0.3; |
|
1205 helper(2, -delta, 0, aDeltaMode); |
|
1206 helper(2, -delta, -1, aDeltaMode); |
|
1207 helper(2, delta, 0, aDeltaMode); |
|
1208 helper(2, delta, 1, aDeltaMode); |
|
1209 helper(2, -2 * delta, 0, aDeltaMode); |
|
1210 helper(2, -2 * delta, -1, aDeltaMode); |
|
1211 helper(2, 2 * delta, 0, aDeltaMode); |
|
1212 helper(2, 2 * delta, 1, aDeltaMode); |
|
1213 }); |
|
1214 |
|
1215 window.removeEventListener("wheel", wheelListener, false); |
|
1216 is(defaultPrevented, 48, "wheel event default prevented"); |
|
1217 } |
|
1218 |
|
1219 function synthesizeColumnDrag(aTree, aMouseDownColumnNumber, aMouseUpColumnNumber, aAfter) |
|
1220 { |
|
1221 var columns = getSortedColumnArray(aTree); |
|
1222 |
|
1223 var down = columns[aMouseDownColumnNumber].element; |
|
1224 var up = columns[aMouseUpColumnNumber].element; |
|
1225 |
|
1226 // Target the initial mousedown in the middle of the column header so we |
|
1227 // avoid the extra hit test space given to the splitter |
|
1228 var columnWidth = down.boxObject.width; |
|
1229 var splitterHitWidth = columnWidth / 2; |
|
1230 synthesizeMouse(down, splitterHitWidth, 3, { type: "mousedown"}); |
|
1231 |
|
1232 var offsetX = 0; |
|
1233 if (aAfter) { |
|
1234 offsetX = columnWidth; |
|
1235 } |
|
1236 |
|
1237 if (aMouseUpColumnNumber > aMouseDownColumnNumber) { |
|
1238 for (var i = aMouseDownColumnNumber; i <= aMouseUpColumnNumber; i++) { |
|
1239 var move = columns[i].element; |
|
1240 synthesizeMouse(move, offsetX, 3, { type: "mousemove"}); |
|
1241 } |
|
1242 } |
|
1243 else { |
|
1244 for (var i = aMouseDownColumnNumber; i >= aMouseUpColumnNumber; i--) { |
|
1245 var move = columns[i].element; |
|
1246 synthesizeMouse(move, offsetX, 3, { type: "mousemove"}); |
|
1247 } |
|
1248 } |
|
1249 |
|
1250 synthesizeMouse(up, offsetX, 3, { type: "mouseup"}); |
|
1251 } |
|
1252 |
|
1253 function arrayMove(aArray, aFrom, aTo, aAfter) |
|
1254 { |
|
1255 var o = aArray.splice(aFrom, 1)[0]; |
|
1256 if (aTo > aFrom) { |
|
1257 aTo--; |
|
1258 } |
|
1259 |
|
1260 if (aAfter) { |
|
1261 aTo++; |
|
1262 } |
|
1263 |
|
1264 aArray.splice(aTo, 0, o); |
|
1265 } |
|
1266 |
|
1267 function getSortedColumnArray(aTree) |
|
1268 { |
|
1269 var columns = aTree.columns; |
|
1270 var a = []; |
|
1271 for (var i = 0; i < columns.length; i++) { |
|
1272 a.push(columns.getColumnAt(i)); |
|
1273 } |
|
1274 |
|
1275 a.sort(function(a, b) { |
|
1276 var o1 = parseInt(a.element.getAttribute("ordinal")); |
|
1277 var o2 = parseInt(b.element.getAttribute("ordinal")); |
|
1278 return o1 - o2; |
|
1279 }); |
|
1280 return a; |
|
1281 } |
|
1282 |
|
1283 function checkColumns(aTree, aReference, aMessage) |
|
1284 { |
|
1285 var columns = getSortedColumnArray(aTree); |
|
1286 var ids = []; |
|
1287 columns.forEach(function(e) { |
|
1288 ids.push(e.element.id); |
|
1289 }); |
|
1290 is(compareArrays(ids, aReference), true, aMessage); |
|
1291 } |
|
1292 |
|
1293 function mouseOnCell(tree, row, column, testname) |
|
1294 { |
|
1295 var x = {}, y = {}, width = {}, height = {}; |
|
1296 tree.boxObject.getCoordsForCellItem(row, column, "text", x, y, width, height); |
|
1297 |
|
1298 synthesizeMouseExpectEvent(tree.body, x.value, y.value, {}, tree, "select", testname); |
|
1299 } |
|
1300 |
|
1301 function mouseClickOnColumnHeader(aColumns, aColumnIndex, aButton, aClickCount) |
|
1302 { |
|
1303 var columnHeader = aColumns[aColumnIndex].element; |
|
1304 var columnHeaderRect = columnHeader.getBoundingClientRect(); |
|
1305 var columnWidth = columnHeaderRect.right - columnHeaderRect.left; |
|
1306 // For multiple click we send separate click events, with increasing |
|
1307 // clickCount. This simulates the common behavior of multiple clicks. |
|
1308 for (var i = 1; i <= aClickCount; i++) { |
|
1309 // Target the middle of the column header. |
|
1310 synthesizeMouse(columnHeader, columnWidth / 2, 3, |
|
1311 { button: aButton, |
|
1312 clickCount: i }, null); |
|
1313 } |
|
1314 } |
|
1315 |
|
1316 function mouseDblClickOnCell(tree, row, column, testname) |
|
1317 { |
|
1318 // select the row we will edit |
|
1319 var selection = tree.view.selection; |
|
1320 selection.select(row); |
|
1321 tree.treeBoxObject.ensureRowIsVisible(row); |
|
1322 |
|
1323 // get cell coordinates |
|
1324 var x = {}, y = {}, width = {}, height = {}; |
|
1325 tree.treeBoxObject.getCoordsForCellItem(row, column, "text", x, y, width, height); |
|
1326 |
|
1327 synthesizeMouse(tree.body, x.value, y.value, { clickCount: 2 }, null); |
|
1328 } |
|
1329 |
|
1330 function compareArrays(arr1, arr2) |
|
1331 { |
|
1332 if (arr1.length != arr2.length) |
|
1333 return false; |
|
1334 |
|
1335 for (var i = 0; i < arr1.length; i++) { |
|
1336 if (arr1[i] != arr2[i]) |
|
1337 return false; |
|
1338 } |
|
1339 |
|
1340 return true; |
|
1341 } |
|
1342 |
|
1343 function convertProperties(arr) |
|
1344 { |
|
1345 var results = []; |
|
1346 var count = arr.Count(); |
|
1347 for (var i = 0; i < count; i++) |
|
1348 results.push(arr.GetElementAt(i).QueryInterface(Components.interfaces.nsIAtom).toString()); |
|
1349 |
|
1350 results.sort(); |
|
1351 return results.join(" "); |
|
1352 } |
|
1353 |
|
1354 function convertDOMtoTreeRowInfo(treechildren, level, rowidx) |
|
1355 { |
|
1356 var obj = { rows: [] }; |
|
1357 |
|
1358 var parentidx = rowidx.value; |
|
1359 |
|
1360 treechildren = treechildren.childNodes; |
|
1361 for (var r = 0; r < treechildren.length; r++) { |
|
1362 rowidx.value++; |
|
1363 |
|
1364 var treeitem = treechildren[r]; |
|
1365 if (treeitem.hasChildNodes()) { |
|
1366 var treerow = treeitem.firstChild; |
|
1367 var cellInfo = []; |
|
1368 for (var c = 0; c < treerow.childNodes.length; c++) { |
|
1369 var cell = treerow.childNodes[c]; |
|
1370 cellInfo.push({ label: "" + cell.getAttribute("label"), |
|
1371 value: cell.getAttribute("value"), |
|
1372 properties: cell.getAttribute("properties"), |
|
1373 editable: cell.getAttribute("editable") != "false", |
|
1374 selectable: cell.getAttribute("selectable") != "false", |
|
1375 image: cell.getAttribute("src"), |
|
1376 mode: cell.hasAttribute("mode") ? parseInt(cell.getAttribute("mode")) : 3 }); |
|
1377 } |
|
1378 |
|
1379 var descendants = treeitem.lastChild; |
|
1380 var children = (treerow == descendants) ? null : |
|
1381 convertDOMtoTreeRowInfo(descendants, level + 1, rowidx); |
|
1382 obj.rows.push({ cells: cellInfo, |
|
1383 properties: treerow.getAttribute("properties"), |
|
1384 container: treeitem.getAttribute("container") == "true", |
|
1385 separator: treeitem.localName == "treeseparator", |
|
1386 children: children, |
|
1387 level: level, |
|
1388 parent: parentidx }); |
|
1389 } |
|
1390 } |
|
1391 |
|
1392 return obj; |
|
1393 } |