1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/content/tests/widgets/tree_shared.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1393 @@ 1.4 +var columns_simpletree = 1.5 +[ 1.6 + { name: "name", label: "Name", key: true, properties: "one two" }, 1.7 + { name: "address", label: "Address" } 1.8 +]; 1.9 + 1.10 +var columns_hiertree = 1.11 +[ 1.12 + { name: "name", label: "Name", primary: true, key: true, properties: "one two" }, 1.13 + { name: "address", label: "Address" }, 1.14 + { name: "planet", label: "Planet" }, 1.15 + { name: "gender", label: "Gender", cycler: true } 1.16 +]; 1.17 + 1.18 +// XXXndeakin still to add some tests for: 1.19 +// cycler columns, checkbox cells, progressmeter cells 1.20 + 1.21 +// this test function expects a tree to have 8 rows in it when it isn't 1.22 +// expanded. The tree should only display four rows at a time. If editable, 1.23 +// the cell at row 1 and column 0 must be editable, and the cell at row 2 and 1.24 +// column 1 must not be editable. 1.25 +function testtag_tree(treeid, treerowinfoid, seltype, columnstype, testid) 1.26 +{ 1.27 + // Stop keystrokes that aren't handled by the tree from leaking out and 1.28 + // scrolling the main Mochitests window! 1.29 + function preventDefault(event) { 1.30 + event.preventDefault(); 1.31 + } 1.32 + document.addEventListener("keypress", preventDefault, false); 1.33 + 1.34 + var multiple = (seltype == "multiple"); 1.35 + 1.36 + var tree = document.getElementById(treeid); 1.37 + var treerowinfo = document.getElementById(treerowinfoid); 1.38 + var rowInfo; 1.39 + if (testid =="tree view") 1.40 + rowInfo = getCustomTreeViewCellInfo(); 1.41 + else 1.42 + rowInfo = convertDOMtoTreeRowInfo(treerowinfo, 0, { value: -1 }); 1.43 + var columnInfo = (columnstype == "simple") ? columns_simpletree : columns_hiertree; 1.44 + 1.45 + is(tree.view.selection.currentColumn, null, testid + " initial currentColumn"); 1.46 + is(tree.selType, seltype == "multiple" ? "" : seltype, testid + " seltype"); 1.47 + 1.48 + // note: the functions below should be in this order due to changes made in later tests 1.49 + 1.50 + // select the first column in cell selection mode so that the selection 1.51 + // functions can be tested 1.52 + if (seltype == "cell") 1.53 + tree.view.selection.currentColumn = tree.columns[0]; 1.54 + 1.55 + testtag_tree_columns(tree, columnInfo, testid); 1.56 + testtag_tree_TreeSelection(tree, testid, multiple); 1.57 + testtag_tree_TreeSelection_UI(tree, testid, multiple); 1.58 + if (seltype == "cell") 1.59 + testtag_tree_TreeSelection_UI_cell(tree, testid, rowInfo); 1.60 + 1.61 + testtag_tree_TreeView(tree, testid, rowInfo); 1.62 + 1.63 + is(tree.editable, false, "tree should not be editable"); 1.64 + // currently, the editable flag means that tree editing cannot be invoked 1.65 + // by the user. However, editing can still be started with a script. 1.66 + is(tree.editingRow, -1, testid + " initial editingRow"); 1.67 + is(tree.editingColumn, null, testid + " initial editingColumn"); 1.68 + 1.69 + testtag_tree_UI_editing(tree, testid, rowInfo); 1.70 + 1.71 + is(tree.editable, false, "tree should not be editable after testtag_tree_UI_editing"); 1.72 + // currently, the editable flag means that tree editing cannot be invoked 1.73 + // by the user. However, editing can still be started with a script. 1.74 + is(tree.editingRow, -1, testid + " initial editingRow (continued)"); 1.75 + is(tree.editingColumn, null, testid + " initial editingColumn (continued)"); 1.76 + 1.77 + var ecolumn = tree.columns[0]; 1.78 + ok(!tree.startEditing(1, ecolumn), "non-editable trees shouldn't start editing"); 1.79 + is(tree.editingRow, -1, testid + " failed startEditing shouldn't set editingRow"); 1.80 + is(tree.editingColumn, null, testid + " failed startEditing shouldn't set editingColumn"); 1.81 + 1.82 + tree.editable = true; 1.83 + 1.84 + ok(tree.startEditing(1, ecolumn), "startEditing should have returned true"); 1.85 + is(tree.editingRow, 1, testid + " startEditing editingRow"); 1.86 + is(tree.editingColumn, ecolumn, testid + " startEditing editingColumn"); 1.87 + is(tree.getAttribute("editing"), "true", testid + " startEditing editing attribute"); 1.88 + 1.89 + tree.stopEditing(true); 1.90 + is(tree.editingRow, -1, testid + " stopEditing editingRow"); 1.91 + is(tree.editingColumn, null, testid + " stopEditing editingColumn"); 1.92 + is(tree.hasAttribute("editing"), false, testid + " stopEditing editing attribute"); 1.93 + 1.94 + tree.startEditing(-1, ecolumn); 1.95 + is(tree.editingRow == -1 && tree.editingColumn == null, true, testid + " startEditing -1 editingRow"); 1.96 + tree.startEditing(15, ecolumn); 1.97 + is(tree.editingRow == -1 && tree.editingColumn == null, true, testid + " startEditing 15 editingRow"); 1.98 + tree.startEditing(1, null); 1.99 + is(tree.editingRow == -1 && tree.editingColumn == null, true, testid + " startEditing null column editingRow"); 1.100 + tree.startEditing(2, tree.columns[1]); 1.101 + is(tree.editingRow == -1 && tree.editingColumn == null, true, testid + " startEditing non editable cell editingRow"); 1.102 + 1.103 + tree.startEditing(1, ecolumn); 1.104 + var inputField = tree.inputField; 1.105 + is(inputField instanceof Components.interfaces.nsIDOMXULTextBoxElement, true, testid + "inputField"); 1.106 + inputField.value = "Changed Value"; 1.107 + tree.stopEditing(true); 1.108 + is(tree.view.getCellText(1, ecolumn), "Changed Value", testid + "edit cell accept"); 1.109 + 1.110 + // this cell can be edited, but stopEditing(false) means don't accept the change. 1.111 + tree.startEditing(1, ecolumn); 1.112 + inputField.value = "Second Value"; 1.113 + tree.stopEditing(false); 1.114 + is(tree.view.getCellText(1, ecolumn), "Changed Value", testid + "edit cell no accept"); 1.115 + 1.116 + tree.editable = false; 1.117 + 1.118 + // do the sorting tests last as it will cause the rows to rearrange 1.119 + // skip them for the custom tree view 1.120 + if (testid !="tree view") 1.121 + testtag_tree_TreeView_rows_sort(tree, testid, rowInfo); 1.122 + 1.123 + testtag_tree_wheel(tree); 1.124 + 1.125 + document.removeEventListener("keypress", preventDefault, false); 1.126 + 1.127 + SimpleTest.finish(); 1.128 +} 1.129 + 1.130 +function testtag_tree_columns(tree, expectedColumns, testid) 1.131 +{ 1.132 + testid += " "; 1.133 + 1.134 + var columns = tree.columns; 1.135 + 1.136 + is(columns instanceof TreeColumns, true, testid + "columns is a TreeColumns"); 1.137 + is(columns.count, expectedColumns.length, testid + "TreeColumns count"); 1.138 + is(columns.length, expectedColumns.length, testid + "TreeColumns length"); 1.139 + 1.140 + var treecols = tree.getElementsByTagName("treecols")[0]; 1.141 + var treecol = treecols.getElementsByTagName("treecol"); 1.142 + 1.143 + var x = 0; 1.144 + var primary = null, sorted = null, key = null; 1.145 + for (var c = 0; c < expectedColumns.length; c++) { 1.146 + var adjtestid = testid + " column " + c + " "; 1.147 + var column = columns[c]; 1.148 + var expectedColumn = expectedColumns[c]; 1.149 + is(columns.getColumnAt(c), column, adjtestid + "getColumnAt"); 1.150 + is(columns.getNamedColumn(expectedColumn.name), column, adjtestid + "getNamedColumn"); 1.151 + is(columns.getColumnFor(treecol[c]), column, adjtestid + "getColumnFor"); 1.152 + if (expectedColumn.primary) 1.153 + primary = column; 1.154 + if (expectedColumn.sorted) 1.155 + sorted = column; 1.156 + if (expectedColumn.key) 1.157 + key = column; 1.158 + 1.159 + // XXXndeakin on Windows and Linux, some columns are one pixel to the 1.160 + // left of where they should be. Could just be a rounding issue. 1.161 + var adj = 1; 1.162 + is(column.x + adj >= x, true, adjtestid + "position is after last column " + 1.163 + column.x + "," + column.width + "," + x); 1.164 + is(column.width > 0, true, adjtestid + "width is greater than 0"); 1.165 + x = column.x + column.width; 1.166 + 1.167 + // now check the TreeColumn properties 1.168 + is(column instanceof TreeColumn, true, adjtestid + "is a TreeColumn"); 1.169 + is(column.element, treecol[c], adjtestid + "element is treecol"); 1.170 + is(column.columns, columns, adjtestid + "columns is TreeColumns"); 1.171 + is(column.id, expectedColumn.name, adjtestid + "name"); 1.172 + is(column.index, c, adjtestid + "index"); 1.173 + is(column.primary, primary == column, adjtestid + "column is primary"); 1.174 + 1.175 + is(column.cycler, "cycler" in expectedColumn && expectedColumn.cycler, 1.176 + adjtestid + "column is cycler"); 1.177 + is(column.selectable, true, adjtestid + "column is selectable"); 1.178 + is(column.editable, "editable" in expectedColumn && expectedColumn.editable, 1.179 + adjtestid + "column is editable"); 1.180 + 1.181 + is(column.type, "type" in expectedColumn ? expectedColumn.type : 1, adjtestid + "type"); 1.182 + 1.183 + is(column.getPrevious(), c > 0 ? columns[c - 1] : null, adjtestid + "getPrevious"); 1.184 + is(column.getNext(), c < columns.length - 1 ? columns[c + 1] : null, adjtestid + "getNext"); 1.185 + 1.186 + // check the view's getColumnProperties method 1.187 + var properties = tree.view.getColumnProperties(column); 1.188 + var expectedProperties = expectedColumn.properties; 1.189 + is(properties, expectedProperties ? expectedProperties : "", adjtestid + "getColumnProperties"); 1.190 + } 1.191 + 1.192 + is(columns.getFirstColumn(), columns[0], testid + "getFirstColumn"); 1.193 + is(columns.getLastColumn(), columns[columns.length - 1], testid + "getLastColumn"); 1.194 + is(columns.getPrimaryColumn(), primary, testid + "getPrimaryColumn"); 1.195 + is(columns.getSortedColumn(), sorted, testid + "getSortedColumn"); 1.196 + is(columns.getKeyColumn(), key, testid + "getKeyColumn"); 1.197 + 1.198 + is(columns.getColumnAt(-1), null, testid + "getColumnAt under"); 1.199 + is(columns.getColumnAt(columns.length), null, testid + "getColumnAt over"); 1.200 + is(columns.getNamedColumn(""), null, testid + "getNamedColumn null"); 1.201 + is(columns.getNamedColumn("unknown"), null, testid + "getNamedColumn unknown"); 1.202 + is(columns.getColumnFor(null), null, testid + "getColumnFor null"); 1.203 + is(columns.getColumnFor(tree), null, testid + "getColumnFor other"); 1.204 +} 1.205 + 1.206 +function testtag_tree_TreeSelection(tree, testid, multiple) 1.207 +{ 1.208 + testid += " selection "; 1.209 + 1.210 + var selection = tree.view.selection; 1.211 + is(selection instanceof Components.interfaces.nsITreeSelection, true, 1.212 + testid + "selection is a TreeSelection"); 1.213 + is(selection.single, !multiple, testid + "single"); 1.214 + 1.215 + testtag_tree_TreeSelection_State(tree, testid + "initial", -1, []); 1.216 + is(selection.shiftSelectPivot, -1, testid + "initial shiftSelectPivot"); 1.217 + 1.218 + selection.currentIndex = 2; 1.219 + testtag_tree_TreeSelection_State(tree, testid + "set currentIndex", 2, []); 1.220 + tree.currentIndex = 3; 1.221 + testtag_tree_TreeSelection_State(tree, testid + "set tree.currentIndex", 3, []); 1.222 + 1.223 + // test the select() method, which should deselect all rows and select 1.224 + // a single row 1.225 + selection.select(1); 1.226 + testtag_tree_TreeSelection_State(tree, testid + "select 1", 1, [1]); 1.227 + selection.select(3); 1.228 + testtag_tree_TreeSelection_State(tree, testid + "select 2", 3, [3]); 1.229 + selection.select(3); 1.230 + testtag_tree_TreeSelection_State(tree, testid + "select same", 3, [3]); 1.231 + 1.232 + selection.currentIndex = 1; 1.233 + testtag_tree_TreeSelection_State(tree, testid + "set currentIndex with single selection", 1, [3]); 1.234 + 1.235 + tree.currentIndex = 2; 1.236 + testtag_tree_TreeSelection_State(tree, testid + "set tree.currentIndex with single selection", 2, [3]); 1.237 + 1.238 + // check the toggleSelect method. In single selection mode, it only toggles on when 1.239 + // there isn't currently a selection. 1.240 + selection.toggleSelect(2); 1.241 + testtag_tree_TreeSelection_State(tree, testid + "toggleSelect 1", 2, multiple ? [2, 3] : [3]); 1.242 + selection.toggleSelect(2); 1.243 + selection.toggleSelect(3); 1.244 + testtag_tree_TreeSelection_State(tree, testid + "toggleSelect 2", 3, []); 1.245 + 1.246 + // the current index doesn't change after a selectAll, so it should still be set to 1 1.247 + // selectAll has no effect on single selection trees 1.248 + selection.currentIndex = 1; 1.249 + selection.selectAll(); 1.250 + testtag_tree_TreeSelection_State(tree, testid + "selectAll 1", 1, multiple ? [0, 1, 2, 3, 4, 5, 6 , 7] : []); 1.251 + selection.toggleSelect(2); 1.252 + testtag_tree_TreeSelection_State(tree, testid + "toggleSelect after selectAll", 2, 1.253 + multiple ? [0, 1, 3, 4, 5, 6, 7] : [2]); 1.254 + selection.clearSelection(); 1.255 + testtag_tree_TreeSelection_State(tree, testid + "clearSelection", 2, []); 1.256 + selection.toggleSelect(3); 1.257 + selection.toggleSelect(1); 1.258 + if (multiple) { 1.259 + selection.selectAll(); 1.260 + testtag_tree_TreeSelection_State(tree, testid + "selectAll 2", 1, [0, 1, 2, 3, 4, 5, 6, 7]); 1.261 + } 1.262 + selection.currentIndex = 2; 1.263 + selection.clearSelection(); 1.264 + testtag_tree_TreeSelection_State(tree, testid + "clearSelection after selectAll", 2, []); 1.265 + 1.266 + // XXXndeakin invertSelection isn't implemented 1.267 + // selection.invertSelection(); 1.268 + 1.269 + is(selection.shiftSelectPivot, -1, testid + "shiftSelectPivot set to -1"); 1.270 + 1.271 + // rangedSelect and clearRange set the currentIndex to the endIndex. The 1.272 + // shiftSelectPivot property will be set to startIndex. 1.273 + selection.rangedSelect(1, 3, false); 1.274 + testtag_tree_TreeSelection_State(tree, testid + "rangedSelect no augment", 1.275 + multiple ? 3 : 2, multiple ? [1, 2, 3] : []); 1.276 + is(selection.shiftSelectPivot, multiple ? 1 : -1, 1.277 + testid + "shiftSelectPivot after rangedSelect no augment"); 1.278 + if (multiple) { 1.279 + selection.select(1); 1.280 + selection.rangedSelect(0, 2, true); 1.281 + testtag_tree_TreeSelection_State(tree, testid + "rangedSelect augment", 2, [0, 1, 2]); 1.282 + is(selection.shiftSelectPivot, 0, testid + "shiftSelectPivot after rangedSelect augment"); 1.283 + 1.284 + selection.clearRange(1, 3); 1.285 + testtag_tree_TreeSelection_State(tree, testid + "rangedSelect augment", 3, [0]); 1.286 + 1.287 + // check that rangedSelect can take a start value higher than end 1.288 + selection.rangedSelect(3, 1, false); 1.289 + testtag_tree_TreeSelection_State(tree, testid + "rangedSelect reverse", 1, [1, 2, 3]); 1.290 + is(selection.shiftSelectPivot, 3, testid + "shiftSelectPivot after rangedSelect reverse"); 1.291 + 1.292 + // check that setting the current index doesn't change the selection 1.293 + selection.currentIndex = 0; 1.294 + testtag_tree_TreeSelection_State(tree, testid + "currentIndex with range selection", 0, [1, 2, 3]); 1.295 + } 1.296 + 1.297 + // both values of rangedSelect may be the same 1.298 + selection.rangedSelect(2, 2, false); 1.299 + testtag_tree_TreeSelection_State(tree, testid + "rangedSelect one row", 2, [2]); 1.300 + is(selection.shiftSelectPivot, 2, testid + "shiftSelectPivot after selecting one row"); 1.301 + 1.302 + if (multiple) { 1.303 + selection.rangedSelect(2, 3, true); 1.304 + 1.305 + // a start index of -1 means from the last point 1.306 + selection.rangedSelect(-1, 0, true); 1.307 + testtag_tree_TreeSelection_State(tree, testid + "rangedSelect -1 existing selection", 0, [0, 1, 2, 3]); 1.308 + is(selection.shiftSelectPivot, 2, testid + "shiftSelectPivot after -1 existing selection"); 1.309 + 1.310 + selection.currentIndex = 2; 1.311 + selection.rangedSelect(-1, 0, false); 1.312 + testtag_tree_TreeSelection_State(tree, testid + "rangedSelect -1 from currentIndex", 0, [0, 1, 2]); 1.313 + is(selection.shiftSelectPivot, 2, testid + "shiftSelectPivot -1 from currentIndex"); 1.314 + } 1.315 + 1.316 + // XXXndeakin need to test out of range values but these don't work properly 1.317 +/* 1.318 + selection.select(-1); 1.319 + testtag_tree_TreeSelection_State(tree, testid + "rangedSelect augment -1", -1, []); 1.320 + 1.321 + selection.select(8); 1.322 + testtag_tree_TreeSelection_State(tree, testid + "rangedSelect augment 8", 3, [0]); 1.323 +*/ 1.324 +} 1.325 + 1.326 +function testtag_tree_TreeSelection_UI(tree, testid, multiple) 1.327 +{ 1.328 + testid += " selection UI "; 1.329 + 1.330 + var selection = tree.view.selection; 1.331 + selection.clearSelection(); 1.332 + selection.currentIndex = 0; 1.333 + tree.focus(); 1.334 + 1.335 + var keydownFired = 0; 1.336 + var keypressFired = 0; 1.337 + function keydownListener(event) 1.338 + { 1.339 + keydownFired++; 1.340 + } 1.341 + function keypressListener(event) { 1.342 + keypressFired++; 1.343 + } 1.344 + 1.345 + // check that cursor up and down keys navigate up and down 1.346 + // select event fires after a delay so don't expect it. The reason it fires after a delay 1.347 + // is so that cursor navigation allows quicking skimming over a set of items without 1.348 + // actually firing events in-between, improving performance. The select event will only 1.349 + // be fired on the row where the cursor stops. 1.350 + window.addEventListener("keydown", keydownListener, false); 1.351 + window.addEventListener("keypress", keypressListener, false); 1.352 + 1.353 + synthesizeKeyExpectEvent("VK_DOWN", {}, tree, "!select", "key down"); 1.354 + testtag_tree_TreeSelection_State(tree, testid + "key down", 1, [1], 0); 1.355 + 1.356 + synthesizeKeyExpectEvent("VK_UP", {}, tree, "!select", "key up"); 1.357 + testtag_tree_TreeSelection_State(tree, testid + "key up", 0, [0], 0); 1.358 + 1.359 + synthesizeKeyExpectEvent("VK_UP", {}, tree, "!select", "key up at start"); 1.360 + testtag_tree_TreeSelection_State(tree, testid + "key up at start", 0, [0], 0); 1.361 + 1.362 + // pressing down while the last row is selected should not fire a select event, 1.363 + // as the selection won't have changed. Also the view is not scrolled in this case. 1.364 + selection.select(7); 1.365 + synthesizeKeyExpectEvent("VK_DOWN", {}, tree, "!select", "key down at end"); 1.366 + testtag_tree_TreeSelection_State(tree, testid + "key down at end", 7, [7], 0); 1.367 + 1.368 + // pressing keys while at the edge of the visible rows should scroll the list 1.369 + tree.treeBoxObject.scrollToRow(4); 1.370 + selection.select(4); 1.371 + synthesizeKeyExpectEvent("VK_UP", {}, tree, "!select", "key up with scroll"); 1.372 + is(tree.treeBoxObject.getFirstVisibleRow(), 3, testid + "key up with scroll"); 1.373 + 1.374 + tree.treeBoxObject.scrollToRow(0); 1.375 + selection.select(3); 1.376 + synthesizeKeyExpectEvent("VK_DOWN", {}, tree, "!select", "key down with scroll"); 1.377 + is(tree.treeBoxObject.getFirstVisibleRow(), 1, testid + "key down with scroll"); 1.378 + 1.379 + // accel key and cursor movement adjust currentIndex but should not change 1.380 + // the selection. In single selection mode, the selection will not change, 1.381 + // but instead will just scroll up or down a line 1.382 + tree.treeBoxObject.scrollToRow(0); 1.383 + selection.select(1); 1.384 + synthesizeKeyExpectEvent("VK_DOWN", { accelKey: true }, tree, "!select", "key down with accel"); 1.385 + testtag_tree_TreeSelection_State(tree, testid + "key down with accel", multiple ? 2 : 1, [1]); 1.386 + if (!multiple) 1.387 + is(tree.treeBoxObject.getFirstVisibleRow(), 1, testid + "key down with accel and scroll"); 1.388 + 1.389 + tree.treeBoxObject.scrollToRow(4); 1.390 + selection.select(4); 1.391 + synthesizeKeyExpectEvent("VK_UP", { accelKey: true }, tree, "!select", "key up with accel"); 1.392 + testtag_tree_TreeSelection_State(tree, testid + "key up with accel", multiple ? 3 : 4, [4]); 1.393 + if (!multiple) 1.394 + is(tree.treeBoxObject.getFirstVisibleRow(), 3, testid + "key up with accel and scroll"); 1.395 + 1.396 + // do this three times, one for each state of pageUpOrDownMovesSelection, 1.397 + // and then once with the accel key pressed 1.398 + for (var t = 0; t < 3; t++) { 1.399 + var testidmod = (t == 2) ? " with accel" : (t == 1) ? " rev" : ""; 1.400 + var keymod = (t == 2) ? { accelKey: true } : { }; 1.401 + 1.402 + var moveselection = tree.pageUpOrDownMovesSelection; 1.403 + if (t == 2) 1.404 + moveselection = !moveselection; 1.405 + 1.406 + tree.treeBoxObject.scrollToRow(4); 1.407 + selection.currentIndex = 6; 1.408 + selection.select(6); 1.409 + var expected = moveselection ? 4 : 6; 1.410 + synthesizeKeyExpectEvent("VK_PAGE_UP", keymod, tree, "!select", "key page up"); 1.411 + testtag_tree_TreeSelection_State(tree, testid + "key page up" + testidmod, 1.412 + expected, [expected], moveselection ? 4 : 0); 1.413 + 1.414 + expected = moveselection ? 0 : 6; 1.415 + synthesizeKeyExpectEvent("VK_PAGE_UP", keymod, tree, "!select", "key page up again"); 1.416 + testtag_tree_TreeSelection_State(tree, testid + "key page up again" + testidmod, 1.417 + expected, [expected], 0); 1.418 + 1.419 + expected = moveselection ? 0 : 6; 1.420 + synthesizeKeyExpectEvent("VK_PAGE_UP", keymod, tree, "!select", "key page up at start"); 1.421 + testtag_tree_TreeSelection_State(tree, testid + "key page up at start" + testidmod, 1.422 + expected, [expected], 0); 1.423 + 1.424 + tree.treeBoxObject.scrollToRow(0); 1.425 + selection.currentIndex = 1; 1.426 + selection.select(1); 1.427 + expected = moveselection ? 3 : 1; 1.428 + synthesizeKeyExpectEvent("VK_PAGE_DOWN", keymod, tree, "!select", "key page down"); 1.429 + testtag_tree_TreeSelection_State(tree, testid + "key page down" + testidmod, 1.430 + expected, [expected], moveselection ? 0 : 4); 1.431 + 1.432 + expected = moveselection ? 7 : 1; 1.433 + synthesizeKeyExpectEvent("VK_PAGE_DOWN", keymod, tree, "!select", "key page down again"); 1.434 + testtag_tree_TreeSelection_State(tree, testid + "key page down again" + testidmod, 1.435 + expected, [expected], 4); 1.436 + 1.437 + expected = moveselection ? 7 : 1; 1.438 + synthesizeKeyExpectEvent("VK_PAGE_DOWN", keymod, tree, "!select", "key page down at start"); 1.439 + testtag_tree_TreeSelection_State(tree, testid + "key page down at start" + testidmod, 1.440 + expected, [expected], 4); 1.441 + 1.442 + if (t < 2) 1.443 + tree.pageUpOrDownMovesSelection = !tree.pageUpOrDownMovesSelection; 1.444 + } 1.445 + 1.446 + tree.treeBoxObject.scrollToRow(4); 1.447 + selection.select(6); 1.448 + synthesizeKeyExpectEvent("VK_HOME", {}, tree, "!select", "key home"); 1.449 + testtag_tree_TreeSelection_State(tree, testid + "key home", 0, [0], 0); 1.450 + 1.451 + tree.treeBoxObject.scrollToRow(0); 1.452 + selection.select(1); 1.453 + synthesizeKeyExpectEvent("VK_END", {}, tree, "!select", "key end"); 1.454 + testtag_tree_TreeSelection_State(tree, testid + "key end", 7, [7], 4); 1.455 + 1.456 + // in single selection mode, the selection doesn't change in this case 1.457 + tree.treeBoxObject.scrollToRow(4); 1.458 + selection.select(6); 1.459 + synthesizeKeyExpectEvent("VK_HOME", { accelKey: true }, tree, "!select", "key home with accel"); 1.460 + testtag_tree_TreeSelection_State(tree, testid + "key home with accel", multiple ? 0 : 6, [6], 0); 1.461 + 1.462 + tree.treeBoxObject.scrollToRow(0); 1.463 + selection.select(1); 1.464 + synthesizeKeyExpectEvent("VK_END", { accelKey: true }, tree, "!select", "key end with accel"); 1.465 + testtag_tree_TreeSelection_State(tree, testid + "key end with accel", multiple ? 7 : 1, [1], 4); 1.466 + 1.467 + // next, test cursor navigation with selection. Here the select event will be fired 1.468 + selection.select(1); 1.469 + var eventExpected = multiple ? "select" : "!select"; 1.470 + synthesizeKeyExpectEvent("VK_DOWN", { shiftKey: true }, tree, eventExpected, "key shift down to select"); 1.471 + testtag_tree_TreeSelection_State(tree, testid + "key shift down to select", 1.472 + multiple ? 2 : 1, multiple ? [1, 2] : [1]); 1.473 + is(selection.shiftSelectPivot, multiple ? 1 : -1, 1.474 + testid + "key shift down to select shiftSelectPivot"); 1.475 + synthesizeKeyExpectEvent("VK_UP", { shiftKey: true }, tree, eventExpected, "key shift up to unselect"); 1.476 + testtag_tree_TreeSelection_State(tree, testid + "key shift up to unselect", 1, [1]); 1.477 + is(selection.shiftSelectPivot, multiple ? 1 : -1, 1.478 + testid + "key shift up to unselect shiftSelectPivot"); 1.479 + if (multiple) { 1.480 + synthesizeKeyExpectEvent("VK_UP", { shiftKey: true }, tree, "select", "key shift up to select"); 1.481 + testtag_tree_TreeSelection_State(tree, testid + "key shift up to select", 0, [0, 1]); 1.482 + is(selection.shiftSelectPivot, 1, testid + "key shift up to select shiftSelectPivot"); 1.483 + synthesizeKeyExpectEvent("VK_DOWN", { shiftKey: true }, tree, "select", "key shift down to unselect"); 1.484 + testtag_tree_TreeSelection_State(tree, testid + "key shift down to unselect", 1, [1]); 1.485 + is(selection.shiftSelectPivot, 1, testid + "key shift down to unselect shiftSelectPivot"); 1.486 + } 1.487 + 1.488 + // do this twice, one for each state of pageUpOrDownMovesSelection, however 1.489 + // when selecting with the shift key, pageUpOrDownMovesSelection is ignored 1.490 + // and the selection always changes 1.491 + var lastidx = tree.view.rowCount - 1; 1.492 + for (var t = 0; t < 2; t++) { 1.493 + var testidmod = (t == 0) ? "" : " rev"; 1.494 + 1.495 + // If the top or bottom visible row is the current row, pressing shift and 1.496 + // page down / page up selects one page up or one page down. Otherwise, the 1.497 + // selection is made to the top or bottom of the visible area. 1.498 + tree.treeBoxObject.scrollToRow(lastidx - 3); 1.499 + selection.currentIndex = 6; 1.500 + selection.select(6); 1.501 + synthesizeKeyExpectEvent("VK_PAGE_UP", { shiftKey: true }, tree, eventExpected, "key shift page up"); 1.502 + testtag_tree_TreeSelection_State(tree, testid + "key shift page up" + testidmod, 1.503 + multiple ? 4 : 6, multiple ? [4, 5, 6] : [6]); 1.504 + if (multiple) { 1.505 + synthesizeKeyExpectEvent("VK_PAGE_UP", { shiftKey: true }, tree, "select", "key shift page up again"); 1.506 + testtag_tree_TreeSelection_State(tree, testid + "key shift page up again" + testidmod, 1.507 + 0, [0, 1, 2, 3, 4, 5, 6]); 1.508 + // no change in the selection, so no select event should be fired 1.509 + synthesizeKeyExpectEvent("VK_PAGE_UP", { shiftKey: true }, tree, "!select", "key shift page up at start"); 1.510 + testtag_tree_TreeSelection_State(tree, testid + "key shift page up at start" + testidmod, 1.511 + 0, [0, 1, 2, 3, 4, 5, 6]); 1.512 + // deselect by paging down again 1.513 + synthesizeKeyExpectEvent("VK_PAGE_DOWN", { shiftKey: true }, tree, "select", "key shift page down deselect"); 1.514 + testtag_tree_TreeSelection_State(tree, testid + "key shift page down deselect" + testidmod, 1.515 + 3, [3, 4, 5, 6]); 1.516 + } 1.517 + 1.518 + tree.treeBoxObject.scrollToRow(1); 1.519 + selection.currentIndex = 2; 1.520 + selection.select(2); 1.521 + synthesizeKeyExpectEvent("VK_PAGE_DOWN", { shiftKey: true }, tree, eventExpected, "key shift page down"); 1.522 + testtag_tree_TreeSelection_State(tree, testid + "key shift page down" + testidmod, 1.523 + multiple ? 4 : 2, multiple ? [2, 3, 4] : [2]); 1.524 + if (multiple) { 1.525 + synthesizeKeyExpectEvent("VK_PAGE_DOWN", { shiftKey: true }, tree, "select", "key shift page down again"); 1.526 + testtag_tree_TreeSelection_State(tree, testid + "key shift page down again" + testidmod, 1.527 + 7, [2, 3, 4, 5, 6, 7]); 1.528 + synthesizeKeyExpectEvent("VK_PAGE_DOWN", { shiftKey: true }, tree, "!select", "key shift page down at start"); 1.529 + testtag_tree_TreeSelection_State(tree, testid + "key shift page down at start" + testidmod, 1.530 + 7, [2, 3, 4, 5, 6, 7]); 1.531 + synthesizeKeyExpectEvent("VK_PAGE_UP", { shiftKey: true }, tree, "select", "key shift page up deselect"); 1.532 + testtag_tree_TreeSelection_State(tree, testid + "key shift page up deselect" + testidmod, 1.533 + 4, [2, 3, 4]); 1.534 + } 1.535 + 1.536 + // test when page down / page up is pressed when the view is scrolled such 1.537 + // that the selection is not visible 1.538 + if (multiple) { 1.539 + tree.treeBoxObject.scrollToRow(3); 1.540 + selection.currentIndex = 1; 1.541 + selection.select(1); 1.542 + synthesizeKeyExpectEvent("VK_PAGE_DOWN", { shiftKey: true }, tree, eventExpected, 1.543 + "key shift page down with view scrolled down"); 1.544 + testtag_tree_TreeSelection_State(tree, testid + "key shift page down with view scrolled down" + testidmod, 1.545 + 6, [1, 2, 3, 4, 5, 6], 3); 1.546 + 1.547 + tree.treeBoxObject.scrollToRow(2); 1.548 + selection.currentIndex = 6; 1.549 + selection.select(6); 1.550 + synthesizeKeyExpectEvent("VK_PAGE_UP", { shiftKey: true }, tree, eventExpected, 1.551 + "key shift page up with view scrolled up"); 1.552 + testtag_tree_TreeSelection_State(tree, testid + "key shift page up with view scrolled up" + testidmod, 1.553 + 2, [2, 3, 4, 5, 6], 2); 1.554 + 1.555 + tree.treeBoxObject.scrollToRow(2); 1.556 + selection.currentIndex = 0; 1.557 + selection.select(0); 1.558 + // don't expect the select event, as the selection won't have changed 1.559 + synthesizeKeyExpectEvent("VK_PAGE_UP", { shiftKey: true }, tree, "!select", 1.560 + "key shift page up at start with view scrolled down"); 1.561 + testtag_tree_TreeSelection_State(tree, testid + "key shift page up at start with view scrolled down" + testidmod, 1.562 + 0, [0], 0); 1.563 + 1.564 + tree.treeBoxObject.scrollToRow(0); 1.565 + selection.currentIndex = 7; 1.566 + selection.select(7); 1.567 + // don't expect the select event, as the selection won't have changed 1.568 + synthesizeKeyExpectEvent("VK_PAGE_DOWN", { shiftKey: true }, tree, "!select", 1.569 + "key shift page down at end with view scrolled up"); 1.570 + testtag_tree_TreeSelection_State(tree, testid + "key shift page down at end with view scrolled up" + testidmod, 1.571 + 7, [7], 4); 1.572 + } 1.573 + 1.574 + tree.pageUpOrDownMovesSelection = !tree.pageUpOrDownMovesSelection; 1.575 + } 1.576 + 1.577 + tree.treeBoxObject.scrollToRow(4); 1.578 + selection.select(5); 1.579 + synthesizeKeyExpectEvent("VK_HOME", { shiftKey: true }, tree, eventExpected, "key shift home"); 1.580 + testtag_tree_TreeSelection_State(tree, testid + "key shift home", 1.581 + multiple ? 0 : 5, multiple ? [0, 1, 2, 3, 4, 5] : [5], multiple ? 0 : 4); 1.582 + 1.583 + tree.treeBoxObject.scrollToRow(0); 1.584 + selection.select(3); 1.585 + synthesizeKeyExpectEvent("VK_END", { shiftKey: true }, tree, eventExpected, "key shift end"); 1.586 + testtag_tree_TreeSelection_State(tree, testid + "key shift end", 1.587 + multiple ? 7 : 3, multiple ? [3, 4, 5, 6, 7] : [3], multiple ? 4 : 0); 1.588 + 1.589 + // pressing space selects a row, pressing accel + space unselects a row 1.590 + selection.select(2); 1.591 + selection.currentIndex = 4; 1.592 + synthesizeKeyExpectEvent(" ", {}, tree, "select", "key space on"); 1.593 + // in single selection mode, space shouldn't do anything 1.594 + testtag_tree_TreeSelection_State(tree, testid + "key space on", 4, multiple ? [2, 4] : [2]); 1.595 + 1.596 + if (multiple) { 1.597 + synthesizeKeyExpectEvent(" ", { accelKey: true }, tree, "select", "key space off"); 1.598 + testtag_tree_TreeSelection_State(tree, testid + "key space off", 4, [2]); 1.599 + } 1.600 + 1.601 + // check that clicking on a row selects it 1.602 + tree.treeBoxObject.scrollToRow(0); 1.603 + selection.select(2); 1.604 + selection.currentIndex = 2; 1.605 + if (0) { // XXXndeakin disable these tests for now 1.606 + mouseOnCell(tree, 1, tree.columns[1], "mouse on row"); 1.607 + testtag_tree_TreeSelection_State(tree, testid + "mouse on row", 1, [1], 0, 1.608 + tree.selType == "cell" ? tree.columns[1] : null); 1.609 + } 1.610 + 1.611 + // restore the scroll position to the start of the page 1.612 + sendKey("HOME"); 1.613 + 1.614 + window.removeEventListener("keydown", keydownListener, false); 1.615 + window.removeEventListener("keypress", keypressListener, false); 1.616 + is(keydownFired, multiple ? 63 : 40, "keydown event wasn't fired properly"); 1.617 + is(keypressFired, multiple ? 2 : 1, "keypress event wasn't fired properly"); 1.618 +} 1.619 + 1.620 +function testtag_tree_UI_editing(tree, testid, rowInfo) 1.621 +{ 1.622 + testid += " editing UI "; 1.623 + 1.624 + // check editing UI 1.625 + var ecolumn = tree.columns[0]; 1.626 + var rowIndex = 2; 1.627 + var inputField = tree.inputField; 1.628 + 1.629 + // temporary make the tree editable to test mouse double click 1.630 + var wasEditable = tree.editable; 1.631 + if (!wasEditable) 1.632 + tree.editable = true; 1.633 + 1.634 + // if this is a container save its current open status 1.635 + var row = rowInfo.rows[rowIndex]; 1.636 + var wasOpen = null; 1.637 + if (tree.view.isContainer(row)) 1.638 + wasOpen = tree.view.isContainerOpen(row); 1.639 + 1.640 + // Test whether a keystroke can enter text entry, and another can exit. 1.641 + if (tree.selType == "cell") 1.642 + { 1.643 + tree.stopEditing(false); 1.644 + ok(!tree.editingColumn, "Should not be editing tree cell now"); 1.645 + tree.view.selection.currentColumn = ecolumn; 1.646 + tree.currentIndex = rowIndex; 1.647 + 1.648 + const isMac = (navigator.platform.indexOf("Mac") >= 0); 1.649 + const StartEditingKey = isMac ? "RETURN" : "F2"; 1.650 + sendKey(StartEditingKey); 1.651 + is(tree.editingColumn, ecolumn, "Should be editing tree cell now"); 1.652 + sendKey("ESCAPE"); 1.653 + ok(!tree.editingColumn, "Should not be editing tree cell now"); 1.654 + is(tree.currentIndex, rowIndex, "Current index should not have changed"); 1.655 + is(tree.view.selection.currentColumn, ecolumn, "Current column should not have changed"); 1.656 + } 1.657 + 1.658 + mouseDblClickOnCell(tree, rowIndex, ecolumn, testid + "edit on double click"); 1.659 + is(tree.editingColumn, ecolumn, testid + "editing column"); 1.660 + is(tree.editingRow, rowIndex, testid + "editing row"); 1.661 + 1.662 + // ensure that we don't expand an expandable container on edit 1.663 + if (wasOpen != null) 1.664 + is(tree.view.isContainerOpen(row), wasOpen, testid + "opened container node on edit"); 1.665 + 1.666 + // ensure to restore editable attribute 1.667 + if (!wasEditable) 1.668 + tree.editable = false; 1.669 + 1.670 + var ci = tree.currentIndex; 1.671 + 1.672 + // cursor navigation should not change the selection while editing 1.673 + var testKey = function(key) { 1.674 + synthesizeKeyExpectEvent(key, {}, tree, "!select", "key " + key + " with editing"); 1.675 + is(tree.editingRow == rowIndex && tree.editingColumn == ecolumn && tree.currentIndex == ci, 1.676 + true, testid + "key " + key + " while editing"); 1.677 + } 1.678 + 1.679 + testKey("VK_DOWN"); 1.680 + testKey("VK_UP"); 1.681 + testKey("VK_PAGE_DOWN"); 1.682 + testKey("VK_PAGE_UP"); 1.683 + testKey("VK_HOME"); 1.684 + testKey("VK_END"); 1.685 + 1.686 + // XXXndeakin figure out how to send characters to the textbox 1.687 + // inputField.inputField.focus() 1.688 + // synthesizeKeyExpectEvent(inputField.inputField, "b", null, ""); 1.689 + // tree.stopEditing(true); 1.690 + // is(tree.view.getCellText(0, ecolumn), "b", testid + "edit cell"); 1.691 + 1.692 + // Restore initial state. 1.693 + tree.stopEditing(false); 1.694 +} 1.695 + 1.696 +function testtag_tree_TreeSelection_UI_cell(tree, testid, rowInfo) 1.697 +{ 1.698 + testid += " selection UI cell "; 1.699 + 1.700 + var columns = tree.columns; 1.701 + var firstcolumn = columns[0]; 1.702 + var secondcolumn = columns[1]; 1.703 + var lastcolumn = columns[columns.length - 1]; 1.704 + var secondlastcolumn = columns[columns.length - 2]; 1.705 + var selection = tree.view.selection; 1.706 + 1.707 + selection.clearSelection(); 1.708 + selection.currentIndex = -1; 1.709 + selection.currentColumn = firstcolumn; 1.710 + is(selection.currentColumn, firstcolumn, testid + " first currentColumn"); 1.711 + 1.712 + // no selection yet so nothing should happen when the left and right cursor keys are pressed 1.713 + synthesizeKeyExpectEvent("VK_RIGHT", {}, tree, "!select", "key right no selection"); 1.714 + testtag_tree_TreeSelection_State(tree, testid + "key right no selection", -1, [], null, firstcolumn); 1.715 + 1.716 + selection.currentColumn = secondcolumn; 1.717 + synthesizeKeyExpectEvent("VK_LEFT", {}, tree, "!select", "key left no selection"); 1.718 + testtag_tree_TreeSelection_State(tree, testid + "key left no selection", -1, [], null, secondcolumn); 1.719 + 1.720 + selection.select(2); 1.721 + selection.currentIndex = 2; 1.722 + if (0) { // XXXndeakin disable these tests for now 1.723 + mouseOnCell(tree, 1, secondlastcolumn, "mouse on cell"); 1.724 + testtag_tree_TreeSelection_State(tree, testid + "mouse on cell", 1, [1], null, secondlastcolumn); 1.725 + } 1.726 + 1.727 + tree.focus(); 1.728 + 1.729 + // selection is set, so it should move when the left and right cursor keys are pressed 1.730 + tree.treeBoxObject.scrollToRow(0); 1.731 + selection.select(1); 1.732 + selection.currentIndex = 1; 1.733 + selection.currentColumn = secondcolumn; 1.734 + synthesizeKeyExpectEvent("VK_LEFT", {}, tree, "!select", "key left in second column"); 1.735 + testtag_tree_TreeSelection_State(tree, testid + "key left in second column", 1, [1], 0, firstcolumn); 1.736 + 1.737 + synthesizeKeyExpectEvent("VK_LEFT", {}, tree, "!select", "key left in first column"); 1.738 + testtag_tree_TreeSelection_State(tree, testid + "key left in first column", 1, [1], 0, firstcolumn); 1.739 + 1.740 + selection.currentColumn = secondlastcolumn; 1.741 + synthesizeKeyExpectEvent("VK_RIGHT", {}, tree, "!select", "key right in second last column"); 1.742 + testtag_tree_TreeSelection_State(tree, testid + "key right in second last column", 1, [1], 0, lastcolumn); 1.743 + 1.744 + synthesizeKeyExpectEvent("VK_RIGHT", {}, tree, "!select", "key right in last column"); 1.745 + testtag_tree_TreeSelection_State(tree, testid + "key right in last column", 1, [1], 0, lastcolumn); 1.746 + 1.747 + synthesizeKeyExpectEvent("VK_UP", {}, tree, "!select", "key up in second row"); 1.748 + testtag_tree_TreeSelection_State(tree, testid + "key up in second row", 0, [0], 0, lastcolumn); 1.749 + 1.750 + synthesizeKeyExpectEvent("VK_UP", {}, tree, "!select", "key up in first row"); 1.751 + testtag_tree_TreeSelection_State(tree, testid + "key up in first row", 0, [0], 0, lastcolumn); 1.752 + 1.753 + synthesizeKeyExpectEvent("VK_DOWN", {}, tree, "!select", "key down in first row"); 1.754 + testtag_tree_TreeSelection_State(tree, testid + "key down in first row", 1, [1], 0, lastcolumn); 1.755 + 1.756 + var lastidx = tree.view.rowCount - 1; 1.757 + tree.treeBoxObject.scrollToRow(lastidx - 3); 1.758 + selection.select(lastidx); 1.759 + selection.currentIndex = lastidx; 1.760 + synthesizeKeyExpectEvent("VK_DOWN", {}, tree, "!select", "key down in last row"); 1.761 + testtag_tree_TreeSelection_State(tree, testid + "key down in last row", lastidx, [lastidx], lastidx - 3, lastcolumn); 1.762 + 1.763 + synthesizeKeyExpectEvent("VK_HOME", {}, tree, "!select", "key home"); 1.764 + testtag_tree_TreeSelection_State(tree, testid + "key home", 0, [0], 0, lastcolumn); 1.765 + 1.766 + synthesizeKeyExpectEvent("VK_END", {}, tree, "!select", "key end"); 1.767 + testtag_tree_TreeSelection_State(tree, testid + "key end", lastidx, [lastidx], lastidx - 3, lastcolumn); 1.768 + 1.769 + for (var t = 0; t < 2; t++) { 1.770 + var testidmod = (t == 0) ? "" : " rev"; 1.771 + 1.772 + // scroll to the end, subtract 3 because we want lastidx to appear 1.773 + // at the end of view 1.774 + tree.treeBoxObject.scrollToRow(lastidx - 3); 1.775 + selection.select(lastidx); 1.776 + selection.currentIndex = lastidx; 1.777 + var expectedrow = tree.pageUpOrDownMovesSelection ? lastidx - 3 : lastidx; 1.778 + synthesizeKeyExpectEvent("VK_PAGE_UP", {}, tree, "!select", "key page up"); 1.779 + testtag_tree_TreeSelection_State(tree, testid + "key page up" + testidmod, 1.780 + expectedrow, [expectedrow], 1.781 + tree.pageUpOrDownMovesSelection ? lastidx - 3 : 0, lastcolumn); 1.782 + 1.783 + tree.treeBoxObject.scrollToRow(1); 1.784 + selection.select(1); 1.785 + selection.currentIndex = 1; 1.786 + var expectedrow = tree.pageUpOrDownMovesSelection ? 4 : 1; 1.787 + synthesizeKeyExpectEvent("VK_PAGE_DOWN", {}, tree, "!select", "key page down"); 1.788 + testtag_tree_TreeSelection_State(tree, testid + "key page down" + testidmod, 1.789 + expectedrow, [expectedrow], 1.790 + tree.pageUpOrDownMovesSelection ? 1 : lastidx - 3, lastcolumn); 1.791 + 1.792 + tree.pageUpOrDownMovesSelection = !tree.pageUpOrDownMovesSelection; 1.793 + } 1.794 + 1.795 + // now check navigation when there is unselctable column 1.796 + secondcolumn.element.setAttribute("selectable", "false"); 1.797 + secondcolumn.invalidate(); 1.798 + is(secondcolumn.selectable, false, testid + "set selectable attribute"); 1.799 + 1.800 + if (columns.length >= 3) { 1.801 + selection.select(3); 1.802 + selection.currentIndex = 3; 1.803 + // check whether unselectable columns are skipped over 1.804 + selection.currentColumn = firstcolumn; 1.805 + synthesizeKeyExpectEvent("VK_RIGHT", {}, tree, "!select", "key right unselectable column"); 1.806 + testtag_tree_TreeSelection_State(tree, testid + "key right unselectable column", 1.807 + 3, [3], null, secondcolumn.getNext()); 1.808 + 1.809 + synthesizeKeyExpectEvent("VK_LEFT", {}, tree, "!select", "key left unselectable column"); 1.810 + testtag_tree_TreeSelection_State(tree, testid + "key left unselectable column", 1.811 + 3, [3], null, firstcolumn); 1.812 + } 1.813 + 1.814 + secondcolumn.element.removeAttribute("selectable"); 1.815 + secondcolumn.invalidate(); 1.816 + is(secondcolumn.selectable, true, testid + "clear selectable attribute"); 1.817 + 1.818 + // check to ensure that navigation isn't allowed if the first column is not selectable 1.819 + selection.currentColumn = secondcolumn; 1.820 + firstcolumn.element.setAttribute("selectable", "false"); 1.821 + firstcolumn.invalidate(); 1.822 + synthesizeKeyExpectEvent("VK_LEFT", {}, tree, "!select", "key left unselectable first column"); 1.823 + testtag_tree_TreeSelection_State(tree, testid + "key left unselectable first column", 1.824 + 3, [3], null, secondcolumn); 1.825 + firstcolumn.element.removeAttribute("selectable"); 1.826 + firstcolumn.invalidate(); 1.827 + 1.828 + // check to ensure that navigation isn't allowed if the last column is not selectable 1.829 + selection.currentColumn = secondlastcolumn; 1.830 + lastcolumn.element.setAttribute("selectable", "false"); 1.831 + lastcolumn.invalidate(); 1.832 + synthesizeKeyExpectEvent("VK_RIGHT", {}, tree, "!select", "key right unselectable last column"); 1.833 + testtag_tree_TreeSelection_State(tree, testid + "key right unselectable last column", 1.834 + 3, [3], null, secondlastcolumn); 1.835 + lastcolumn.element.removeAttribute("selectable"); 1.836 + lastcolumn.invalidate(); 1.837 + 1.838 + // now check for cells with selectable false 1.839 + if (!rowInfo.rows[4].cells[1].selectable && columns.length >= 3) { 1.840 + // check whether unselectable cells are skipped over 1.841 + selection.select(4); 1.842 + selection.currentIndex = 4; 1.843 + 1.844 + selection.currentColumn = firstcolumn; 1.845 + synthesizeKeyExpectEvent("VK_RIGHT", {}, tree, "!select", "key right unselectable cell"); 1.846 + testtag_tree_TreeSelection_State(tree, testid + "key right unselectable cell", 1.847 + 4, [4], null, secondcolumn.getNext()); 1.848 + 1.849 + synthesizeKeyExpectEvent("VK_LEFT", {}, tree, "!select", "key left unselectable cell"); 1.850 + testtag_tree_TreeSelection_State(tree, testid + "key left unselectable cell", 1.851 + 4, [4], null, firstcolumn); 1.852 + 1.853 + tree.treeBoxObject.scrollToRow(1); 1.854 + selection.select(3); 1.855 + selection.currentIndex = 3; 1.856 + selection.currentColumn = secondcolumn; 1.857 + 1.858 + synthesizeKeyExpectEvent("VK_DOWN", {}, tree, "!select", "key down unselectable cell"); 1.859 + testtag_tree_TreeSelection_State(tree, testid + "key down unselectable cell", 1.860 + 5, [5], 2, secondcolumn); 1.861 + 1.862 + tree.treeBoxObject.scrollToRow(4); 1.863 + synthesizeKeyExpectEvent("VK_UP", {}, tree, "!select", "key up unselectable cell"); 1.864 + testtag_tree_TreeSelection_State(tree, testid + "key up unselectable cell", 1.865 + 3, [3], 3, secondcolumn); 1.866 + } 1.867 + 1.868 + // restore the scroll position to the start of the page 1.869 + sendKey("HOME"); 1.870 +} 1.871 + 1.872 +function testtag_tree_TreeView(tree, testid, rowInfo) 1.873 +{ 1.874 + testid += " view "; 1.875 + 1.876 + var columns = tree.columns; 1.877 + var view = tree.view; 1.878 + 1.879 + is(view instanceof Components.interfaces.nsITreeView, true, testid + "view is a TreeView"); 1.880 + is(view.rowCount, rowInfo.rows.length, testid + "rowCount"); 1.881 + 1.882 + testtag_tree_TreeView_rows(tree, testid, rowInfo, 0); 1.883 + 1.884 + // note that this will only work for content trees currently 1.885 + view.setCellText(0, columns[1], "Changed Value"); 1.886 + is(view.getCellText(0, columns[1]), "Changed Value", "setCellText"); 1.887 + 1.888 + view.setCellValue(1, columns[0], "Another Changed Value"); 1.889 + is(view.getCellValue(1, columns[0]), "Another Changed Value", "setCellText"); 1.890 +} 1.891 + 1.892 +function testtag_tree_TreeView_rows(tree, testid, rowInfo, startRow) 1.893 +{ 1.894 + var r; 1.895 + var columns = tree.columns; 1.896 + var view = tree.view; 1.897 + var length = rowInfo.rows.length; 1.898 + 1.899 + // methods to test along with the functions which determine the expected value 1.900 + var checkRowMethods = 1.901 + { 1.902 + isContainer: function(row) { return row.container }, 1.903 + isContainerOpen: function(row) { return false }, 1.904 + isContainerEmpty: function(row) { return (row.children != null && row.children.rows.length == 0) }, 1.905 + isSeparator: function(row) { return row.separator }, 1.906 + getRowProperties: function(row) { return row.properties }, 1.907 + getLevel: function(row) { return row.level }, 1.908 + getParentIndex: function(row) { return row.parent }, 1.909 + hasNextSibling: function(row) { return r < startRow + length - 1; } 1.910 + }; 1.911 + 1.912 + var checkCellMethods = 1.913 + { 1.914 + getCellText: function(row, cell) { return cell.label }, 1.915 + getCellValue: function(row, cell) { return cell.value }, 1.916 + getCellProperties: function(row, cell) { return cell.properties }, 1.917 + isEditable: function(row, cell) { return cell.editable }, 1.918 + isSelectable: function(row, cell) { return cell.selectable }, 1.919 + getImageSrc: function(row, cell) { return cell.image }, 1.920 + getProgressMode: function(row, cell) { return cell.mode } 1.921 + }; 1.922 + 1.923 + var failedMethods = { }; 1.924 + var checkMethod, actual, expected; 1.925 + var containerInfo = null; 1.926 + var toggleOpenStateOK = true; 1.927 + 1.928 + for (r = startRow; r < length; r++) { 1.929 + var row = rowInfo.rows[r]; 1.930 + for (var c = 0; c < row.cells.length; c++) { 1.931 + var cell = row.cells[c]; 1.932 + 1.933 + for (checkMethod in checkCellMethods) { 1.934 + expected = checkCellMethods[checkMethod](row, cell); 1.935 + actual = view[checkMethod](r, columns[c]); 1.936 + if (actual !== expected) { 1.937 + failedMethods[checkMethod] = true; 1.938 + is(actual, expected, testid + "row " + r + " column " + c + " " + checkMethod + " is incorrect"); 1.939 + } 1.940 + } 1.941 + } 1.942 + 1.943 + // compare row properties 1.944 + for (checkMethod in checkRowMethods) { 1.945 + expected = checkRowMethods[checkMethod](row, r); 1.946 + if (checkMethod == "hasNextSibling") { 1.947 + actual = view[checkMethod](r, r); 1.948 + } 1.949 + else { 1.950 + actual = view[checkMethod](r); 1.951 + } 1.952 + if (actual !== expected) { 1.953 + failedMethods[checkMethod] = true; 1.954 + is(actual, expected, testid + "row " + r + " " + checkMethod + " is incorrect"); 1.955 + } 1.956 + } 1.957 +/* 1.958 + // open and recurse into containers 1.959 + if (row.container) { 1.960 + view.toggleOpenState(r); 1.961 + if (!view.isContainerOpen(r)) { 1.962 + toggleOpenStateOK = false; 1.963 + is(view.isContainerOpen(r), true, testid + "row " + r + " toggleOpenState open"); 1.964 + } 1.965 + testtag_tree_TreeView_rows(tree, testid + "container " + r + " ", row.children, r + 1); 1.966 + view.toggleOpenState(r); 1.967 + if (view.isContainerOpen(r)) { 1.968 + toggleOpenStateOK = false; 1.969 + is(view.isContainerOpen(r), false, testid + "row " + r + " toggleOpenState close"); 1.970 + } 1.971 + } 1.972 +*/ 1.973 + } 1.974 + 1.975 + for (var failedMethod in failedMethods) { 1.976 + if (failedMethod in checkRowMethods) 1.977 + delete checkRowMethods[failedMethod]; 1.978 + if (failedMethod in checkCellMethods) 1.979 + delete checkCellMethods[failedMethod]; 1.980 + } 1.981 + 1.982 + for (checkMethod in checkRowMethods) 1.983 + is(checkMethod + " ok", checkMethod + " ok", testid + checkMethod); 1.984 + for (checkMethod in checkCellMethods) 1.985 + is(checkMethod + " ok", checkMethod + " ok", testid + checkMethod); 1.986 + if (toggleOpenStateOK) 1.987 + is("toggleOpenState ok", "toggleOpenState ok", testid + "toggleOpenState"); 1.988 +} 1.989 + 1.990 +function testtag_tree_TreeView_rows_sort(tree, testid, rowInfo) 1.991 +{ 1.992 + // check if cycleHeader sorts the columns 1.993 + var columnIndex = 0; 1.994 + var view = tree.view; 1.995 + var column = tree.columns[columnIndex]; 1.996 + var columnElement = column.element; 1.997 + var sortkey = columnElement.getAttribute("sort"); 1.998 + if (sortkey) { 1.999 + view.cycleHeader(column); 1.1000 + is(tree.getAttribute("sort"), sortkey, "cycleHeader sort"); 1.1001 + is(tree.getAttribute("sortDirection"), "ascending", "cycleHeader sortDirection ascending"); 1.1002 + is(columnElement.getAttribute("sortDirection"), "ascending", "cycleHeader column sortDirection"); 1.1003 + is(columnElement.getAttribute("sortActive"), "true", "cycleHeader column sortActive"); 1.1004 + view.cycleHeader(column); 1.1005 + is(tree.getAttribute("sortDirection"), "descending", "cycleHeader sortDirection descending"); 1.1006 + is(columnElement.getAttribute("sortDirection"), "descending", "cycleHeader column sortDirection descending"); 1.1007 + view.cycleHeader(column); 1.1008 + is(tree.getAttribute("sortDirection"), "", "cycleHeader sortDirection natural"); 1.1009 + is(columnElement.getAttribute("sortDirection"), "", "cycleHeader column sortDirection natural"); 1.1010 + // XXXndeakin content view isSorted needs to be tested 1.1011 + } 1.1012 + 1.1013 + // Check that clicking on column header sorts the column. 1.1014 + var columns = getSortedColumnArray(tree); 1.1015 + is(columnElement.getAttribute("sortDirection"), "", 1.1016 + "cycleHeader column sortDirection"); 1.1017 + 1.1018 + // Click once on column header and check sorting has cycled once. 1.1019 + mouseClickOnColumnHeader(columns, columnIndex, 0, 1); 1.1020 + is(columnElement.getAttribute("sortDirection"), "ascending", 1.1021 + "single click cycleHeader column sortDirection ascending"); 1.1022 + 1.1023 + // Now simulate a double click. 1.1024 + mouseClickOnColumnHeader(columns, columnIndex, 0, 2); 1.1025 + if (navigator.platform.indexOf("Win") == 0) { 1.1026 + // Windows cycles only once on double click. 1.1027 + is(columnElement.getAttribute("sortDirection"), "descending", 1.1028 + "double click cycleHeader column sortDirection descending"); 1.1029 + // 1 single clicks should restore natural sorting. 1.1030 + mouseClickOnColumnHeader(columns, columnIndex, 0, 1); 1.1031 + } 1.1032 + 1.1033 + // Check we have gone back to natural sorting. 1.1034 + is(columnElement.getAttribute("sortDirection"), "", 1.1035 + "cycleHeader column sortDirection"); 1.1036 + 1.1037 + columnElement.setAttribute("sorthints", "twostate"); 1.1038 + view.cycleHeader(column); 1.1039 + is(tree.getAttribute("sortDirection"), "ascending", "cycleHeader sortDirection ascending twostate"); 1.1040 + view.cycleHeader(column); 1.1041 + is(tree.getAttribute("sortDirection"), "descending", "cycleHeader sortDirection ascending twostate"); 1.1042 + view.cycleHeader(column); 1.1043 + is(tree.getAttribute("sortDirection"), "ascending", "cycleHeader sortDirection ascending twostate again"); 1.1044 + columnElement.removeAttribute("sorthints"); 1.1045 + view.cycleHeader(column); 1.1046 + view.cycleHeader(column); 1.1047 + 1.1048 + is(columnElement.getAttribute("sortDirection"), "", 1.1049 + "cycleHeader column sortDirection reset"); 1.1050 +} 1.1051 + 1.1052 +// checks if the current and selected rows are correct 1.1053 +// current is the index of the current row 1.1054 +// selected is an array of the indicies of the selected rows 1.1055 +// column is the selected column 1.1056 +// viewidx is the row that should be visible at the top of the tree 1.1057 +function testtag_tree_TreeSelection_State(tree, testid, current, selected, viewidx, column) 1.1058 +{ 1.1059 + var selection = tree.view.selection; 1.1060 + 1.1061 + if (!column) 1.1062 + column = (tree.selType == "cell") ? tree.columns[0] : null; 1.1063 + 1.1064 + is(selection.count, selected.length, testid + " count"); 1.1065 + is(tree.currentIndex, current, testid + " currentIndex"); 1.1066 + is(selection.currentIndex, current, testid + " TreeSelection currentIndex"); 1.1067 + is(selection.currentColumn, column, testid + " currentColumn"); 1.1068 + if (viewidx !== null && viewidx !== undefined) 1.1069 + is(tree.treeBoxObject.getFirstVisibleRow(), viewidx, testid + " first visible row"); 1.1070 + 1.1071 + var actualSelected = []; 1.1072 + var count = tree.view.rowCount; 1.1073 + for (var s = 0; s < count; s++) { 1.1074 + if (selection.isSelected(s)) 1.1075 + actualSelected.push(s); 1.1076 + } 1.1077 + 1.1078 + is(compareArrays(selected, actualSelected), true, testid + " selection [" + selected + "]"); 1.1079 + 1.1080 + actualSelected = []; 1.1081 + var rangecount = selection.getRangeCount(); 1.1082 + for (var r = 0; r < rangecount; r++) { 1.1083 + var start = {}, end = {}; 1.1084 + selection.getRangeAt(r, start, end); 1.1085 + for (var rs = start.value; rs <= end.value; rs++) 1.1086 + actualSelected.push(rs); 1.1087 + } 1.1088 + 1.1089 + is(compareArrays(selected, actualSelected), true, testid + " range selection [" + selected + "]"); 1.1090 +} 1.1091 + 1.1092 +function testtag_tree_column_reorder() 1.1093 +{ 1.1094 + // Make sure the tree is scrolled into the view, otherwise the test will 1.1095 + // fail 1.1096 + var testframe = window.parent.document.getElementById("testframe"); 1.1097 + if (testframe) { 1.1098 + testframe.scrollIntoView(); 1.1099 + } 1.1100 + 1.1101 + var tree = document.getElementById("tree-column-reorder"); 1.1102 + var numColumns = tree.columns.count; 1.1103 + 1.1104 + var reference = []; 1.1105 + for (var i = 0; i < numColumns; i++) { 1.1106 + reference.push("col_" + i); 1.1107 + } 1.1108 + 1.1109 + // Drag the first column to each position 1.1110 + for (var i = 0; i < numColumns - 1; i++) { 1.1111 + synthesizeColumnDrag(tree, i, i + 1, true); 1.1112 + arrayMove(reference, i, i + 1, true); 1.1113 + checkColumns(tree, reference, "drag first column right"); 1.1114 + } 1.1115 + 1.1116 + // And back 1.1117 + for (var i = numColumns - 1; i >= 1; i--) { 1.1118 + synthesizeColumnDrag(tree, i, i - 1, false); 1.1119 + arrayMove(reference, i, i - 1, false); 1.1120 + checkColumns(tree, reference, "drag last column left"); 1.1121 + } 1.1122 + 1.1123 + // Drag each column one column left 1.1124 + for (var i = 1; i < numColumns; i++) { 1.1125 + synthesizeColumnDrag(tree, i, i - 1, false); 1.1126 + arrayMove(reference, i, i - 1, false); 1.1127 + checkColumns(tree, reference, "drag each column left"); 1.1128 + } 1.1129 + 1.1130 + // And back 1.1131 + for (var i = numColumns - 2; i >= 0; i--) { 1.1132 + synthesizeColumnDrag(tree, i, i + 1, true); 1.1133 + arrayMove(reference, i, i + 1, true); 1.1134 + checkColumns(tree, reference, "drag each column right"); 1.1135 + } 1.1136 + 1.1137 + // Drag each column 5 to the right 1.1138 + for (var i = 0; i < numColumns - 5; i++) { 1.1139 + synthesizeColumnDrag(tree, i, i + 5, true); 1.1140 + arrayMove(reference, i, i + 5, true); 1.1141 + checkColumns(tree, reference, "drag each column 5 to the right"); 1.1142 + } 1.1143 + 1.1144 + // And to the left 1.1145 + for (var i = numColumns - 6; i >= 5; i--) { 1.1146 + synthesizeColumnDrag(tree, i, i - 5, false); 1.1147 + arrayMove(reference, i, i - 5, false); 1.1148 + checkColumns(tree, reference, "drag each column 5 to the left"); 1.1149 + } 1.1150 + 1.1151 + // Test that moving a column after itself does not move anything 1.1152 + synthesizeColumnDrag(tree, 0, 0, true); 1.1153 + checkColumns(tree, reference, "drag to itself"); 1.1154 + is(document.treecolDragging, null, "drag to itself completed"); 1.1155 + 1.1156 + // XXX roc should this be here??? 1.1157 + SimpleTest.finish(); 1.1158 +} 1.1159 + 1.1160 +function testtag_tree_wheel(aTree) 1.1161 +{ 1.1162 + const deltaModes = [ 1.1163 + WheelEvent.DOM_DELTA_PIXEL, // 0 1.1164 + WheelEvent.DOM_DELTA_LINE, // 1 1.1165 + WheelEvent.DOM_DELTA_PAGE // 2 1.1166 + ]; 1.1167 + function helper(aStart, aDelta, aIntDelta, aDeltaMode) 1.1168 + { 1.1169 + aTree.treeBoxObject.scrollToRow(aStart); 1.1170 + var expected = !aIntDelta ? aStart : 1.1171 + aDeltaMode != WheelEvent.DOM_DELTA_PAGE ? aStart + aIntDelta : 1.1172 + aIntDelta > 0 ? aStart + aTree.treeBoxObject.getPageLength() : 1.1173 + aStart - aTree.treeBoxObject.getPageLength(); 1.1174 + if (expected < 0) { 1.1175 + expected = 0; 1.1176 + } 1.1177 + if (expected > aTree.view.rowCount - aTree.treeBoxObject.getPageLength()) { 1.1178 + expected = aTree.view.rowCount - aTree.treeBoxObject.getPageLength(); 1.1179 + } 1.1180 + synthesizeWheel(aTree.body, 1, 1, 1.1181 + { deltaMode: aDeltaMode, deltaY: aDelta, 1.1182 + lineOrPageDeltaY: aIntDelta }); 1.1183 + is(aTree.treeBoxObject.getFirstVisibleRow(), expected, 1.1184 + "testtag_tree_wheel: vertical, starting " + aStart + 1.1185 + " delta " + aDelta + " lineOrPageDelta " + aIntDelta + 1.1186 + " aDeltaMode " + aDeltaMode); 1.1187 + 1.1188 + aTree.treeBoxObject.scrollToRow(aStart); 1.1189 + // Check that horizontal scrolling has no effect 1.1190 + synthesizeWheel(aTree.body, 1, 1, 1.1191 + { deltaMode: aDeltaMode, deltaX: aDelta, 1.1192 + lineOrPageDeltaX: aIntDelta }); 1.1193 + is(aTree.treeBoxObject.getFirstVisibleRow(), aStart, 1.1194 + "testtag_tree_wheel: horizontal, starting " + aStart + 1.1195 + " delta " + aDelta + " lineOrPageDelta " + aIntDelta + 1.1196 + " aDeltaMode " + aDeltaMode); 1.1197 + } 1.1198 + 1.1199 + var defaultPrevented = 0; 1.1200 + 1.1201 + function wheelListener(event) { 1.1202 + defaultPrevented++; 1.1203 + } 1.1204 + window.addEventListener("wheel", wheelListener, false); 1.1205 + 1.1206 + deltaModes.forEach(function(aDeltaMode) { 1.1207 + var delta = (aDeltaMode == WheelEvent.DOM_DELTA_PIXEL) ? 5.0 : 0.3; 1.1208 + helper(2, -delta, 0, aDeltaMode); 1.1209 + helper(2, -delta, -1, aDeltaMode); 1.1210 + helper(2, delta, 0, aDeltaMode); 1.1211 + helper(2, delta, 1, aDeltaMode); 1.1212 + helper(2, -2 * delta, 0, aDeltaMode); 1.1213 + helper(2, -2 * delta, -1, aDeltaMode); 1.1214 + helper(2, 2 * delta, 0, aDeltaMode); 1.1215 + helper(2, 2 * delta, 1, aDeltaMode); 1.1216 + }); 1.1217 + 1.1218 + window.removeEventListener("wheel", wheelListener, false); 1.1219 + is(defaultPrevented, 48, "wheel event default prevented"); 1.1220 +} 1.1221 + 1.1222 +function synthesizeColumnDrag(aTree, aMouseDownColumnNumber, aMouseUpColumnNumber, aAfter) 1.1223 +{ 1.1224 + var columns = getSortedColumnArray(aTree); 1.1225 + 1.1226 + var down = columns[aMouseDownColumnNumber].element; 1.1227 + var up = columns[aMouseUpColumnNumber].element; 1.1228 + 1.1229 + // Target the initial mousedown in the middle of the column header so we 1.1230 + // avoid the extra hit test space given to the splitter 1.1231 + var columnWidth = down.boxObject.width; 1.1232 + var splitterHitWidth = columnWidth / 2; 1.1233 + synthesizeMouse(down, splitterHitWidth, 3, { type: "mousedown"}); 1.1234 + 1.1235 + var offsetX = 0; 1.1236 + if (aAfter) { 1.1237 + offsetX = columnWidth; 1.1238 + } 1.1239 + 1.1240 + if (aMouseUpColumnNumber > aMouseDownColumnNumber) { 1.1241 + for (var i = aMouseDownColumnNumber; i <= aMouseUpColumnNumber; i++) { 1.1242 + var move = columns[i].element; 1.1243 + synthesizeMouse(move, offsetX, 3, { type: "mousemove"}); 1.1244 + } 1.1245 + } 1.1246 + else { 1.1247 + for (var i = aMouseDownColumnNumber; i >= aMouseUpColumnNumber; i--) { 1.1248 + var move = columns[i].element; 1.1249 + synthesizeMouse(move, offsetX, 3, { type: "mousemove"}); 1.1250 + } 1.1251 + } 1.1252 + 1.1253 + synthesizeMouse(up, offsetX, 3, { type: "mouseup"}); 1.1254 +} 1.1255 + 1.1256 +function arrayMove(aArray, aFrom, aTo, aAfter) 1.1257 +{ 1.1258 + var o = aArray.splice(aFrom, 1)[0]; 1.1259 + if (aTo > aFrom) { 1.1260 + aTo--; 1.1261 + } 1.1262 + 1.1263 + if (aAfter) { 1.1264 + aTo++; 1.1265 + } 1.1266 + 1.1267 + aArray.splice(aTo, 0, o); 1.1268 +} 1.1269 + 1.1270 +function getSortedColumnArray(aTree) 1.1271 +{ 1.1272 + var columns = aTree.columns; 1.1273 + var a = []; 1.1274 + for (var i = 0; i < columns.length; i++) { 1.1275 + a.push(columns.getColumnAt(i)); 1.1276 + } 1.1277 + 1.1278 + a.sort(function(a, b) { 1.1279 + var o1 = parseInt(a.element.getAttribute("ordinal")); 1.1280 + var o2 = parseInt(b.element.getAttribute("ordinal")); 1.1281 + return o1 - o2; 1.1282 + }); 1.1283 + return a; 1.1284 +} 1.1285 + 1.1286 +function checkColumns(aTree, aReference, aMessage) 1.1287 +{ 1.1288 + var columns = getSortedColumnArray(aTree); 1.1289 + var ids = []; 1.1290 + columns.forEach(function(e) { 1.1291 + ids.push(e.element.id); 1.1292 + }); 1.1293 + is(compareArrays(ids, aReference), true, aMessage); 1.1294 +} 1.1295 + 1.1296 +function mouseOnCell(tree, row, column, testname) 1.1297 +{ 1.1298 + var x = {}, y = {}, width = {}, height = {}; 1.1299 + tree.boxObject.getCoordsForCellItem(row, column, "text", x, y, width, height); 1.1300 + 1.1301 + synthesizeMouseExpectEvent(tree.body, x.value, y.value, {}, tree, "select", testname); 1.1302 +} 1.1303 + 1.1304 +function mouseClickOnColumnHeader(aColumns, aColumnIndex, aButton, aClickCount) 1.1305 +{ 1.1306 + var columnHeader = aColumns[aColumnIndex].element; 1.1307 + var columnHeaderRect = columnHeader.getBoundingClientRect(); 1.1308 + var columnWidth = columnHeaderRect.right - columnHeaderRect.left; 1.1309 + // For multiple click we send separate click events, with increasing 1.1310 + // clickCount. This simulates the common behavior of multiple clicks. 1.1311 + for (var i = 1; i <= aClickCount; i++) { 1.1312 + // Target the middle of the column header. 1.1313 + synthesizeMouse(columnHeader, columnWidth / 2, 3, 1.1314 + { button: aButton, 1.1315 + clickCount: i }, null); 1.1316 + } 1.1317 +} 1.1318 + 1.1319 +function mouseDblClickOnCell(tree, row, column, testname) 1.1320 +{ 1.1321 + // select the row we will edit 1.1322 + var selection = tree.view.selection; 1.1323 + selection.select(row); 1.1324 + tree.treeBoxObject.ensureRowIsVisible(row); 1.1325 + 1.1326 + // get cell coordinates 1.1327 + var x = {}, y = {}, width = {}, height = {}; 1.1328 + tree.treeBoxObject.getCoordsForCellItem(row, column, "text", x, y, width, height); 1.1329 + 1.1330 + synthesizeMouse(tree.body, x.value, y.value, { clickCount: 2 }, null); 1.1331 +} 1.1332 + 1.1333 +function compareArrays(arr1, arr2) 1.1334 +{ 1.1335 + if (arr1.length != arr2.length) 1.1336 + return false; 1.1337 + 1.1338 + for (var i = 0; i < arr1.length; i++) { 1.1339 + if (arr1[i] != arr2[i]) 1.1340 + return false; 1.1341 + } 1.1342 + 1.1343 + return true; 1.1344 +} 1.1345 + 1.1346 +function convertProperties(arr) 1.1347 +{ 1.1348 + var results = []; 1.1349 + var count = arr.Count(); 1.1350 + for (var i = 0; i < count; i++) 1.1351 + results.push(arr.GetElementAt(i).QueryInterface(Components.interfaces.nsIAtom).toString()); 1.1352 + 1.1353 + results.sort(); 1.1354 + return results.join(" "); 1.1355 +} 1.1356 + 1.1357 +function convertDOMtoTreeRowInfo(treechildren, level, rowidx) 1.1358 +{ 1.1359 + var obj = { rows: [] }; 1.1360 + 1.1361 + var parentidx = rowidx.value; 1.1362 + 1.1363 + treechildren = treechildren.childNodes; 1.1364 + for (var r = 0; r < treechildren.length; r++) { 1.1365 + rowidx.value++; 1.1366 + 1.1367 + var treeitem = treechildren[r]; 1.1368 + if (treeitem.hasChildNodes()) { 1.1369 + var treerow = treeitem.firstChild; 1.1370 + var cellInfo = []; 1.1371 + for (var c = 0; c < treerow.childNodes.length; c++) { 1.1372 + var cell = treerow.childNodes[c]; 1.1373 + cellInfo.push({ label: "" + cell.getAttribute("label"), 1.1374 + value: cell.getAttribute("value"), 1.1375 + properties: cell.getAttribute("properties"), 1.1376 + editable: cell.getAttribute("editable") != "false", 1.1377 + selectable: cell.getAttribute("selectable") != "false", 1.1378 + image: cell.getAttribute("src"), 1.1379 + mode: cell.hasAttribute("mode") ? parseInt(cell.getAttribute("mode")) : 3 }); 1.1380 + } 1.1381 + 1.1382 + var descendants = treeitem.lastChild; 1.1383 + var children = (treerow == descendants) ? null : 1.1384 + convertDOMtoTreeRowInfo(descendants, level + 1, rowidx); 1.1385 + obj.rows.push({ cells: cellInfo, 1.1386 + properties: treerow.getAttribute("properties"), 1.1387 + container: treeitem.getAttribute("container") == "true", 1.1388 + separator: treeitem.localName == "treeseparator", 1.1389 + children: children, 1.1390 + level: level, 1.1391 + parent: parentidx }); 1.1392 + } 1.1393 + } 1.1394 + 1.1395 + return obj; 1.1396 +}