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