|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include "XULTreeGridAccessibleWrap.h" |
|
7 |
|
8 #include "nsAccCache.h" |
|
9 #include "nsAccessibilityService.h" |
|
10 #include "nsAccUtils.h" |
|
11 #include "DocAccessible.h" |
|
12 #include "nsEventShell.h" |
|
13 #include "Relation.h" |
|
14 #include "Role.h" |
|
15 #include "States.h" |
|
16 |
|
17 #include "nsIBoxObject.h" |
|
18 #include "nsIMutableArray.h" |
|
19 #include "nsIPersistentProperties2.h" |
|
20 #include "nsITreeSelection.h" |
|
21 #include "nsComponentManagerUtils.h" |
|
22 |
|
23 using namespace mozilla::a11y; |
|
24 |
|
25 //////////////////////////////////////////////////////////////////////////////// |
|
26 // XULTreeGridAccessible: nsISupports implementation |
|
27 |
|
28 NS_IMPL_ISUPPORTS_INHERITED(XULTreeGridAccessible, |
|
29 XULTreeAccessible, |
|
30 nsIAccessibleTable) |
|
31 |
|
32 //////////////////////////////////////////////////////////////////////////////// |
|
33 // XULTreeGridAccessible: nsIAccessibleTable implementation |
|
34 |
|
35 uint32_t |
|
36 XULTreeGridAccessible::ColCount() |
|
37 { |
|
38 return nsCoreUtils::GetSensibleColumnCount(mTree); |
|
39 } |
|
40 |
|
41 uint32_t |
|
42 XULTreeGridAccessible::RowCount() |
|
43 { |
|
44 if (!mTreeView) |
|
45 return 0; |
|
46 |
|
47 int32_t rowCount = 0; |
|
48 mTreeView->GetRowCount(&rowCount); |
|
49 return rowCount >= 0 ? rowCount : 0; |
|
50 } |
|
51 |
|
52 uint32_t |
|
53 XULTreeGridAccessible::SelectedCellCount() |
|
54 { |
|
55 return SelectedRowCount() * ColCount(); |
|
56 } |
|
57 |
|
58 uint32_t |
|
59 XULTreeGridAccessible::SelectedColCount() |
|
60 { |
|
61 // If all the row has been selected, then all the columns are selected, |
|
62 // because we can't select a column alone. |
|
63 |
|
64 uint32_t selectedRowCount = SelectedItemCount(); |
|
65 return selectedRowCount > 0 && selectedRowCount == RowCount() ? ColCount() : 0; |
|
66 } |
|
67 |
|
68 uint32_t |
|
69 XULTreeGridAccessible::SelectedRowCount() |
|
70 { |
|
71 return SelectedItemCount(); |
|
72 } |
|
73 |
|
74 void |
|
75 XULTreeGridAccessible::SelectedCells(nsTArray<Accessible*>* aCells) |
|
76 { |
|
77 uint32_t colCount = ColCount(), rowCount = RowCount(); |
|
78 |
|
79 for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) { |
|
80 if (IsRowSelected(rowIdx)) { |
|
81 for (uint32_t colIdx = 0; colIdx < colCount; colIdx++) { |
|
82 Accessible* cell = CellAt(rowIdx, colIdx); |
|
83 aCells->AppendElement(cell); |
|
84 } |
|
85 } |
|
86 } |
|
87 } |
|
88 |
|
89 void |
|
90 XULTreeGridAccessible::SelectedCellIndices(nsTArray<uint32_t>* aCells) |
|
91 { |
|
92 uint32_t colCount = ColCount(), rowCount = RowCount(); |
|
93 |
|
94 for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) |
|
95 if (IsRowSelected(rowIdx)) |
|
96 for (uint32_t colIdx = 0; colIdx < colCount; colIdx++) |
|
97 aCells->AppendElement(rowIdx * colCount + colIdx); |
|
98 } |
|
99 |
|
100 void |
|
101 XULTreeGridAccessible::SelectedColIndices(nsTArray<uint32_t>* aCols) |
|
102 { |
|
103 if (RowCount() != SelectedRowCount()) |
|
104 return; |
|
105 |
|
106 uint32_t colCount = ColCount(); |
|
107 aCols->SetCapacity(colCount); |
|
108 for (uint32_t colIdx = 0; colIdx < colCount; colIdx++) |
|
109 aCols->AppendElement(colIdx); |
|
110 } |
|
111 |
|
112 void |
|
113 XULTreeGridAccessible::SelectedRowIndices(nsTArray<uint32_t>* aRows) |
|
114 { |
|
115 uint32_t rowCount = RowCount(); |
|
116 for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) |
|
117 if (IsRowSelected(rowIdx)) |
|
118 aRows->AppendElement(rowIdx); |
|
119 } |
|
120 |
|
121 Accessible* |
|
122 XULTreeGridAccessible::CellAt(uint32_t aRowIndex, uint32_t aColumnIndex) |
|
123 { |
|
124 Accessible* row = GetTreeItemAccessible(aRowIndex); |
|
125 if (!row) |
|
126 return nullptr; |
|
127 |
|
128 nsCOMPtr<nsITreeColumn> column = |
|
129 nsCoreUtils::GetSensibleColumnAt(mTree, aColumnIndex); |
|
130 if (!column) |
|
131 return nullptr; |
|
132 |
|
133 nsRefPtr<XULTreeItemAccessibleBase> rowAcc = do_QueryObject(row); |
|
134 if (!rowAcc) |
|
135 return nullptr; |
|
136 |
|
137 return rowAcc->GetCellAccessible(column); |
|
138 } |
|
139 |
|
140 void |
|
141 XULTreeGridAccessible::ColDescription(uint32_t aColIdx, nsString& aDescription) |
|
142 { |
|
143 aDescription.Truncate(); |
|
144 |
|
145 nsCOMPtr<nsIAccessible> treeColumns; |
|
146 Accessible::GetFirstChild(getter_AddRefs(treeColumns)); |
|
147 if (treeColumns) { |
|
148 nsCOMPtr<nsIAccessible> treeColumnItem; |
|
149 treeColumns->GetChildAt(aColIdx, getter_AddRefs(treeColumnItem)); |
|
150 if (treeColumnItem) |
|
151 treeColumnItem->GetName(aDescription); |
|
152 } |
|
153 } |
|
154 |
|
155 bool |
|
156 XULTreeGridAccessible::IsColSelected(uint32_t aColIdx) |
|
157 { |
|
158 // If all the row has been selected, then all the columns are selected. |
|
159 // Because we can't select a column alone. |
|
160 return SelectedItemCount() == RowCount(); |
|
161 } |
|
162 |
|
163 bool |
|
164 XULTreeGridAccessible::IsRowSelected(uint32_t aRowIdx) |
|
165 { |
|
166 if (!mTreeView) |
|
167 return false; |
|
168 |
|
169 nsCOMPtr<nsITreeSelection> selection; |
|
170 nsresult rv = mTreeView->GetSelection(getter_AddRefs(selection)); |
|
171 NS_ENSURE_SUCCESS(rv, false); |
|
172 |
|
173 bool isSelected = false; |
|
174 selection->IsSelected(aRowIdx, &isSelected); |
|
175 return isSelected; |
|
176 } |
|
177 |
|
178 bool |
|
179 XULTreeGridAccessible::IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx) |
|
180 { |
|
181 return IsRowSelected(aRowIdx); |
|
182 } |
|
183 |
|
184 void |
|
185 XULTreeGridAccessible::SelectRow(uint32_t aRowIdx) |
|
186 { |
|
187 if (!mTreeView) |
|
188 return; |
|
189 |
|
190 nsCOMPtr<nsITreeSelection> selection; |
|
191 mTreeView->GetSelection(getter_AddRefs(selection)); |
|
192 NS_ASSERTION(selection, "GetSelection() Shouldn't fail!"); |
|
193 |
|
194 selection->Select(aRowIdx); |
|
195 } |
|
196 |
|
197 void |
|
198 XULTreeGridAccessible::UnselectRow(uint32_t aRowIdx) |
|
199 { |
|
200 if (!mTreeView) |
|
201 return; |
|
202 |
|
203 nsCOMPtr<nsITreeSelection> selection; |
|
204 mTreeView->GetSelection(getter_AddRefs(selection)); |
|
205 |
|
206 if (selection) |
|
207 selection->ClearRange(aRowIdx, aRowIdx); |
|
208 } |
|
209 |
|
210 //////////////////////////////////////////////////////////////////////////////// |
|
211 // XULTreeGridAccessible: Accessible implementation |
|
212 |
|
213 void |
|
214 XULTreeGridAccessible::Shutdown() |
|
215 { |
|
216 mTable = nullptr; |
|
217 XULTreeAccessible::Shutdown(); |
|
218 } |
|
219 |
|
220 role |
|
221 XULTreeGridAccessible::NativeRole() |
|
222 { |
|
223 nsCOMPtr<nsITreeColumns> treeColumns; |
|
224 mTree->GetColumns(getter_AddRefs(treeColumns)); |
|
225 if (!treeColumns) { |
|
226 NS_ERROR("No treecolumns object for tree!"); |
|
227 return roles::NOTHING; |
|
228 } |
|
229 |
|
230 nsCOMPtr<nsITreeColumn> primaryColumn; |
|
231 treeColumns->GetPrimaryColumn(getter_AddRefs(primaryColumn)); |
|
232 |
|
233 return primaryColumn ? roles::TREE_TABLE : roles::TABLE; |
|
234 } |
|
235 |
|
236 //////////////////////////////////////////////////////////////////////////////// |
|
237 // XULTreeGridAccessible: XULTreeAccessible implementation |
|
238 |
|
239 already_AddRefed<Accessible> |
|
240 XULTreeGridAccessible::CreateTreeItemAccessible(int32_t aRow) const |
|
241 { |
|
242 nsRefPtr<Accessible> accessible = |
|
243 new XULTreeGridRowAccessible(mContent, mDoc, |
|
244 const_cast<XULTreeGridAccessible*>(this), |
|
245 mTree, mTreeView, aRow); |
|
246 |
|
247 return accessible.forget(); |
|
248 } |
|
249 |
|
250 |
|
251 //////////////////////////////////////////////////////////////////////////////// |
|
252 // XULTreeGridRowAccessible |
|
253 //////////////////////////////////////////////////////////////////////////////// |
|
254 |
|
255 XULTreeGridRowAccessible:: |
|
256 XULTreeGridRowAccessible(nsIContent* aContent, DocAccessible* aDoc, |
|
257 Accessible* aTreeAcc, nsITreeBoxObject* aTree, |
|
258 nsITreeView* aTreeView, int32_t aRow) : |
|
259 XULTreeItemAccessibleBase(aContent, aDoc, aTreeAcc, aTree, aTreeView, aRow), |
|
260 mAccessibleCache(kDefaultTreeCacheSize) |
|
261 { |
|
262 mGenericTypes |= eTableRow; |
|
263 } |
|
264 |
|
265 //////////////////////////////////////////////////////////////////////////////// |
|
266 // XULTreeGridRowAccessible: nsISupports and cycle collection implementation |
|
267 |
|
268 NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeGridRowAccessible, |
|
269 XULTreeItemAccessibleBase, |
|
270 mAccessibleCache) |
|
271 |
|
272 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(XULTreeGridRowAccessible) |
|
273 NS_INTERFACE_MAP_END_INHERITING(XULTreeItemAccessibleBase) |
|
274 |
|
275 NS_IMPL_ADDREF_INHERITED(XULTreeGridRowAccessible, |
|
276 XULTreeItemAccessibleBase) |
|
277 NS_IMPL_RELEASE_INHERITED(XULTreeGridRowAccessible, |
|
278 XULTreeItemAccessibleBase) |
|
279 |
|
280 //////////////////////////////////////////////////////////////////////////////// |
|
281 // XULTreeGridRowAccessible: Accessible implementation |
|
282 |
|
283 void |
|
284 XULTreeGridRowAccessible::Shutdown() |
|
285 { |
|
286 ClearCache(mAccessibleCache); |
|
287 XULTreeItemAccessibleBase::Shutdown(); |
|
288 } |
|
289 |
|
290 role |
|
291 XULTreeGridRowAccessible::NativeRole() |
|
292 { |
|
293 return roles::ROW; |
|
294 } |
|
295 |
|
296 ENameValueFlag |
|
297 XULTreeGridRowAccessible::Name(nsString& aName) |
|
298 { |
|
299 aName.Truncate(); |
|
300 |
|
301 // XXX: the row name sholdn't be a concatenation of cell names (bug 664384). |
|
302 nsCOMPtr<nsITreeColumn> column = nsCoreUtils::GetFirstSensibleColumn(mTree); |
|
303 while (column) { |
|
304 if (!aName.IsEmpty()) |
|
305 aName.AppendLiteral(" "); |
|
306 |
|
307 nsAutoString cellName; |
|
308 GetCellName(column, cellName); |
|
309 aName.Append(cellName); |
|
310 |
|
311 column = nsCoreUtils::GetNextSensibleColumn(column); |
|
312 } |
|
313 |
|
314 return eNameOK; |
|
315 } |
|
316 |
|
317 Accessible* |
|
318 XULTreeGridRowAccessible::ChildAtPoint(int32_t aX, int32_t aY, |
|
319 EWhichChildAtPoint aWhichChild) |
|
320 { |
|
321 nsIFrame *frame = GetFrame(); |
|
322 if (!frame) |
|
323 return nullptr; |
|
324 |
|
325 nsPresContext *presContext = frame->PresContext(); |
|
326 nsIPresShell* presShell = presContext->PresShell(); |
|
327 |
|
328 nsIFrame *rootFrame = presShell->GetRootFrame(); |
|
329 NS_ENSURE_TRUE(rootFrame, nullptr); |
|
330 |
|
331 nsIntRect rootRect = rootFrame->GetScreenRect(); |
|
332 |
|
333 int32_t clientX = presContext->DevPixelsToIntCSSPixels(aX) - rootRect.x; |
|
334 int32_t clientY = presContext->DevPixelsToIntCSSPixels(aY) - rootRect.y; |
|
335 |
|
336 int32_t row = -1; |
|
337 nsCOMPtr<nsITreeColumn> column; |
|
338 nsAutoCString childEltUnused; |
|
339 mTree->GetCellAt(clientX, clientY, &row, getter_AddRefs(column), |
|
340 childEltUnused); |
|
341 |
|
342 // Return if we failed to find tree cell in the row for the given point. |
|
343 if (row != mRow || !column) |
|
344 return nullptr; |
|
345 |
|
346 return GetCellAccessible(column); |
|
347 } |
|
348 |
|
349 Accessible* |
|
350 XULTreeGridRowAccessible::GetChildAt(uint32_t aIndex) const |
|
351 { |
|
352 if (IsDefunct()) |
|
353 return nullptr; |
|
354 |
|
355 nsCOMPtr<nsITreeColumn> column = |
|
356 nsCoreUtils::GetSensibleColumnAt(mTree, aIndex); |
|
357 if (!column) |
|
358 return nullptr; |
|
359 |
|
360 return GetCellAccessible(column); |
|
361 } |
|
362 |
|
363 uint32_t |
|
364 XULTreeGridRowAccessible::ChildCount() const |
|
365 { |
|
366 return nsCoreUtils::GetSensibleColumnCount(mTree); |
|
367 } |
|
368 |
|
369 //////////////////////////////////////////////////////////////////////////////// |
|
370 // XULTreeGridRowAccessible: XULTreeItemAccessibleBase implementation |
|
371 |
|
372 Accessible* |
|
373 XULTreeGridRowAccessible::GetCellAccessible(nsITreeColumn* aColumn) const |
|
374 { |
|
375 NS_PRECONDITION(aColumn, "No tree column!"); |
|
376 |
|
377 void* key = static_cast<void*>(aColumn); |
|
378 Accessible* cachedCell = mAccessibleCache.GetWeak(key); |
|
379 if (cachedCell) |
|
380 return cachedCell; |
|
381 |
|
382 nsRefPtr<Accessible> cell = |
|
383 new XULTreeGridCellAccessibleWrap(mContent, mDoc, |
|
384 const_cast<XULTreeGridRowAccessible*>(this), |
|
385 mTree, mTreeView, mRow, aColumn); |
|
386 mAccessibleCache.Put(key, cell); |
|
387 Document()->BindToDocument(cell, nullptr); |
|
388 return cell; |
|
389 } |
|
390 |
|
391 void |
|
392 XULTreeGridRowAccessible::RowInvalidated(int32_t aStartColIdx, |
|
393 int32_t aEndColIdx) |
|
394 { |
|
395 nsCOMPtr<nsITreeColumns> treeColumns; |
|
396 mTree->GetColumns(getter_AddRefs(treeColumns)); |
|
397 if (!treeColumns) |
|
398 return; |
|
399 |
|
400 bool nameChanged = false; |
|
401 for (int32_t colIdx = aStartColIdx; colIdx <= aEndColIdx; ++colIdx) { |
|
402 nsCOMPtr<nsITreeColumn> column; |
|
403 treeColumns->GetColumnAt(colIdx, getter_AddRefs(column)); |
|
404 if (column && !nsCoreUtils::IsColumnHidden(column)) { |
|
405 Accessible* cellAccessible = GetCellAccessible(column); |
|
406 if (cellAccessible) { |
|
407 nsRefPtr<XULTreeGridCellAccessible> cellAcc = do_QueryObject(cellAccessible); |
|
408 |
|
409 nameChanged |= cellAcc->CellInvalidated(); |
|
410 } |
|
411 } |
|
412 } |
|
413 |
|
414 if (nameChanged) |
|
415 nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this); |
|
416 |
|
417 } |
|
418 |
|
419 //////////////////////////////////////////////////////////////////////////////// |
|
420 // XULTreeGridRowAccessible: Accessible protected implementation |
|
421 |
|
422 void |
|
423 XULTreeGridRowAccessible::CacheChildren() |
|
424 { |
|
425 } |
|
426 |
|
427 //////////////////////////////////////////////////////////////////////////////// |
|
428 // XULTreeGridCellAccessible |
|
429 //////////////////////////////////////////////////////////////////////////////// |
|
430 |
|
431 XULTreeGridCellAccessible:: |
|
432 XULTreeGridCellAccessible(nsIContent* aContent, DocAccessible* aDoc, |
|
433 XULTreeGridRowAccessible* aRowAcc, |
|
434 nsITreeBoxObject* aTree, nsITreeView* aTreeView, |
|
435 int32_t aRow, nsITreeColumn* aColumn) : |
|
436 LeafAccessible(aContent, aDoc), xpcAccessibleTableCell(this), mTree(aTree), |
|
437 mTreeView(aTreeView), mRow(aRow), mColumn(aColumn) |
|
438 { |
|
439 mParent = aRowAcc; |
|
440 mStateFlags |= eSharedNode; |
|
441 mGenericTypes |= eTableCell; |
|
442 |
|
443 NS_ASSERTION(mTreeView, "mTreeView is null"); |
|
444 |
|
445 int16_t type = -1; |
|
446 mColumn->GetType(&type); |
|
447 if (type == nsITreeColumn::TYPE_CHECKBOX) |
|
448 mTreeView->GetCellValue(mRow, mColumn, mCachedTextEquiv); |
|
449 else |
|
450 mTreeView->GetCellText(mRow, mColumn, mCachedTextEquiv); |
|
451 } |
|
452 |
|
453 //////////////////////////////////////////////////////////////////////////////// |
|
454 // XULTreeGridCellAccessible: nsISupports implementation |
|
455 |
|
456 NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeGridCellAccessible, LeafAccessible, |
|
457 mTree, mColumn) |
|
458 |
|
459 NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(XULTreeGridCellAccessible) |
|
460 NS_INTERFACE_TABLE_INHERITED(XULTreeGridCellAccessible, |
|
461 nsIAccessibleTableCell, |
|
462 XULTreeGridCellAccessible) |
|
463 NS_INTERFACE_TABLE_TAIL_INHERITING(LeafAccessible) |
|
464 NS_IMPL_ADDREF_INHERITED(XULTreeGridCellAccessible, LeafAccessible) |
|
465 NS_IMPL_RELEASE_INHERITED(XULTreeGridCellAccessible, LeafAccessible) |
|
466 |
|
467 //////////////////////////////////////////////////////////////////////////////// |
|
468 // XULTreeGridCellAccessible: nsIAccessible implementation |
|
469 |
|
470 void |
|
471 XULTreeGridCellAccessible::Shutdown() |
|
472 { |
|
473 mTableCell = nullptr; |
|
474 LeafAccessible::Shutdown(); |
|
475 } |
|
476 |
|
477 Accessible* |
|
478 XULTreeGridCellAccessible::FocusedChild() |
|
479 { |
|
480 return nullptr; |
|
481 } |
|
482 |
|
483 ENameValueFlag |
|
484 XULTreeGridCellAccessible::Name(nsString& aName) |
|
485 { |
|
486 aName.Truncate(); |
|
487 |
|
488 if (!mTreeView) |
|
489 return eNameOK; |
|
490 |
|
491 mTreeView->GetCellText(mRow, mColumn, aName); |
|
492 |
|
493 // If there is still no name try the cell value: |
|
494 // This is for graphical cells. We need tree/table view implementors to implement |
|
495 // FooView::GetCellValue to return a meaningful string for cases where there is |
|
496 // something shown in the cell (non-text) such as a star icon; in which case |
|
497 // GetCellValue for that cell would return "starred" or "flagged" for example. |
|
498 if (aName.IsEmpty()) |
|
499 mTreeView->GetCellValue(mRow, mColumn, aName); |
|
500 |
|
501 return eNameOK; |
|
502 } |
|
503 |
|
504 NS_IMETHODIMP |
|
505 XULTreeGridCellAccessible::GetBounds(int32_t* aX, int32_t* aY, |
|
506 int32_t* aWidth, int32_t* aHeight) |
|
507 { |
|
508 NS_ENSURE_ARG_POINTER(aX); |
|
509 *aX = 0; |
|
510 NS_ENSURE_ARG_POINTER(aY); |
|
511 *aY = 0; |
|
512 NS_ENSURE_ARG_POINTER(aWidth); |
|
513 *aWidth = 0; |
|
514 NS_ENSURE_ARG_POINTER(aHeight); |
|
515 *aHeight = 0; |
|
516 |
|
517 if (IsDefunct()) |
|
518 return NS_ERROR_FAILURE; |
|
519 |
|
520 // Get bounds for tree cell and add x and y of treechildren element to |
|
521 // x and y of the cell. |
|
522 nsCOMPtr<nsIBoxObject> boxObj = nsCoreUtils::GetTreeBodyBoxObject(mTree); |
|
523 NS_ENSURE_STATE(boxObj); |
|
524 |
|
525 int32_t x = 0, y = 0, width = 0, height = 0; |
|
526 nsresult rv = mTree->GetCoordsForCellItem(mRow, mColumn, |
|
527 NS_LITERAL_CSTRING("cell"), |
|
528 &x, &y, &width, &height); |
|
529 NS_ENSURE_SUCCESS(rv, rv); |
|
530 |
|
531 int32_t tcX = 0, tcY = 0; |
|
532 boxObj->GetScreenX(&tcX); |
|
533 boxObj->GetScreenY(&tcY); |
|
534 x += tcX; |
|
535 y += tcY; |
|
536 |
|
537 nsPresContext* presContext = mDoc->PresContext(); |
|
538 *aX = presContext->CSSPixelsToDevPixels(x); |
|
539 *aY = presContext->CSSPixelsToDevPixels(y); |
|
540 *aWidth = presContext->CSSPixelsToDevPixels(width); |
|
541 *aHeight = presContext->CSSPixelsToDevPixels(height); |
|
542 |
|
543 return NS_OK; |
|
544 } |
|
545 |
|
546 uint8_t |
|
547 XULTreeGridCellAccessible::ActionCount() |
|
548 { |
|
549 bool isCycler = false; |
|
550 mColumn->GetCycler(&isCycler); |
|
551 if (isCycler) |
|
552 return 1; |
|
553 |
|
554 int16_t type; |
|
555 mColumn->GetType(&type); |
|
556 if (type == nsITreeColumn::TYPE_CHECKBOX && IsEditable()) |
|
557 return 1; |
|
558 |
|
559 return 0; |
|
560 } |
|
561 |
|
562 NS_IMETHODIMP |
|
563 XULTreeGridCellAccessible::GetActionName(uint8_t aIndex, nsAString& aName) |
|
564 { |
|
565 aName.Truncate(); |
|
566 |
|
567 if (aIndex != eAction_Click) |
|
568 return NS_ERROR_INVALID_ARG; |
|
569 |
|
570 if (IsDefunct() || !mTreeView) |
|
571 return NS_ERROR_FAILURE; |
|
572 |
|
573 bool isCycler = false; |
|
574 mColumn->GetCycler(&isCycler); |
|
575 if (isCycler) { |
|
576 aName.AssignLiteral("cycle"); |
|
577 return NS_OK; |
|
578 } |
|
579 |
|
580 int16_t type; |
|
581 mColumn->GetType(&type); |
|
582 if (type == nsITreeColumn::TYPE_CHECKBOX && IsEditable()) { |
|
583 nsAutoString value; |
|
584 mTreeView->GetCellValue(mRow, mColumn, value); |
|
585 if (value.EqualsLiteral("true")) |
|
586 aName.AssignLiteral("uncheck"); |
|
587 else |
|
588 aName.AssignLiteral("check"); |
|
589 |
|
590 return NS_OK; |
|
591 } |
|
592 |
|
593 return NS_ERROR_INVALID_ARG; |
|
594 } |
|
595 |
|
596 NS_IMETHODIMP |
|
597 XULTreeGridCellAccessible::DoAction(uint8_t aIndex) |
|
598 { |
|
599 if (aIndex != eAction_Click) |
|
600 return NS_ERROR_INVALID_ARG; |
|
601 |
|
602 if (IsDefunct()) |
|
603 return NS_ERROR_FAILURE; |
|
604 |
|
605 bool isCycler = false; |
|
606 mColumn->GetCycler(&isCycler); |
|
607 if (isCycler) { |
|
608 DoCommand(); |
|
609 return NS_OK; |
|
610 } |
|
611 |
|
612 int16_t type; |
|
613 mColumn->GetType(&type); |
|
614 if (type == nsITreeColumn::TYPE_CHECKBOX && IsEditable()) { |
|
615 DoCommand(); |
|
616 return NS_OK; |
|
617 } |
|
618 |
|
619 return NS_ERROR_INVALID_ARG; |
|
620 } |
|
621 |
|
622 //////////////////////////////////////////////////////////////////////////////// |
|
623 // XULTreeGridCellAccessible: nsIAccessibleTableCell implementation |
|
624 |
|
625 TableAccessible* |
|
626 XULTreeGridCellAccessible::Table() const |
|
627 { |
|
628 Accessible* grandParent = mParent->Parent(); |
|
629 if (grandParent) |
|
630 return grandParent->AsTable(); |
|
631 |
|
632 return nullptr; |
|
633 } |
|
634 |
|
635 uint32_t |
|
636 XULTreeGridCellAccessible::ColIdx() const |
|
637 { |
|
638 uint32_t colIdx = 0; |
|
639 nsCOMPtr<nsITreeColumn> column = mColumn; |
|
640 while ((column = nsCoreUtils::GetPreviousSensibleColumn(column))) |
|
641 colIdx++; |
|
642 |
|
643 return colIdx; |
|
644 } |
|
645 |
|
646 uint32_t |
|
647 XULTreeGridCellAccessible::RowIdx() const |
|
648 { |
|
649 return mRow; |
|
650 } |
|
651 |
|
652 void |
|
653 XULTreeGridCellAccessible::ColHeaderCells(nsTArray<Accessible*>* aHeaderCells) |
|
654 { |
|
655 nsCOMPtr<nsIDOMElement> columnElm; |
|
656 mColumn->GetElement(getter_AddRefs(columnElm)); |
|
657 |
|
658 nsCOMPtr<nsIContent> columnContent(do_QueryInterface(columnElm)); |
|
659 Accessible* headerCell = mDoc->GetAccessible(columnContent); |
|
660 if (headerCell) |
|
661 aHeaderCells->AppendElement(headerCell); |
|
662 } |
|
663 |
|
664 bool |
|
665 XULTreeGridCellAccessible::Selected() |
|
666 { |
|
667 nsCOMPtr<nsITreeSelection> selection; |
|
668 nsresult rv = mTreeView->GetSelection(getter_AddRefs(selection)); |
|
669 NS_ENSURE_SUCCESS(rv, false); |
|
670 |
|
671 bool selected = false; |
|
672 selection->IsSelected(mRow, &selected); |
|
673 return selected; |
|
674 } |
|
675 |
|
676 //////////////////////////////////////////////////////////////////////////////// |
|
677 // XULTreeGridCellAccessible: Accessible public implementation |
|
678 |
|
679 already_AddRefed<nsIPersistentProperties> |
|
680 XULTreeGridCellAccessible::NativeAttributes() |
|
681 { |
|
682 nsCOMPtr<nsIPersistentProperties> attributes = |
|
683 do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID); |
|
684 |
|
685 // "table-cell-index" attribute |
|
686 TableAccessible* table = Table(); |
|
687 if (!table) |
|
688 return attributes.forget(); |
|
689 |
|
690 nsAutoString stringIdx; |
|
691 stringIdx.AppendInt(table->CellIndexAt(mRow, ColIdx())); |
|
692 nsAccUtils::SetAccAttr(attributes, nsGkAtoms::tableCellIndex, stringIdx); |
|
693 |
|
694 // "cycles" attribute |
|
695 bool isCycler = false; |
|
696 nsresult rv = mColumn->GetCycler(&isCycler); |
|
697 if (NS_SUCCEEDED(rv) && isCycler) |
|
698 nsAccUtils::SetAccAttr(attributes, nsGkAtoms::cycles, |
|
699 NS_LITERAL_STRING("true")); |
|
700 |
|
701 return attributes.forget(); |
|
702 } |
|
703 |
|
704 role |
|
705 XULTreeGridCellAccessible::NativeRole() |
|
706 { |
|
707 return roles::GRID_CELL; |
|
708 } |
|
709 |
|
710 uint64_t |
|
711 XULTreeGridCellAccessible::NativeState() |
|
712 { |
|
713 if (!mTreeView) |
|
714 return states::DEFUNCT; |
|
715 |
|
716 // selectable/selected state |
|
717 uint64_t states = states::SELECTABLE; // keep in sync with NativeInteractiveState |
|
718 |
|
719 nsCOMPtr<nsITreeSelection> selection; |
|
720 mTreeView->GetSelection(getter_AddRefs(selection)); |
|
721 if (selection) { |
|
722 bool isSelected = false; |
|
723 selection->IsSelected(mRow, &isSelected); |
|
724 if (isSelected) |
|
725 states |= states::SELECTED; |
|
726 } |
|
727 |
|
728 // checked state |
|
729 int16_t type; |
|
730 mColumn->GetType(&type); |
|
731 if (type == nsITreeColumn::TYPE_CHECKBOX) { |
|
732 states |= states::CHECKABLE; |
|
733 nsAutoString checked; |
|
734 mTreeView->GetCellValue(mRow, mColumn, checked); |
|
735 if (checked.EqualsIgnoreCase("true")) |
|
736 states |= states::CHECKED; |
|
737 } |
|
738 |
|
739 return states; |
|
740 } |
|
741 |
|
742 uint64_t |
|
743 XULTreeGridCellAccessible::NativeInteractiveState() const |
|
744 { |
|
745 return states::SELECTABLE; |
|
746 } |
|
747 |
|
748 int32_t |
|
749 XULTreeGridCellAccessible::IndexInParent() const |
|
750 { |
|
751 return ColIdx(); |
|
752 } |
|
753 |
|
754 Relation |
|
755 XULTreeGridCellAccessible::RelationByType(RelationType aType) |
|
756 { |
|
757 return Relation(); |
|
758 } |
|
759 |
|
760 //////////////////////////////////////////////////////////////////////////////// |
|
761 // XULTreeGridCellAccessible: public implementation |
|
762 |
|
763 bool |
|
764 XULTreeGridCellAccessible::CellInvalidated() |
|
765 { |
|
766 |
|
767 nsAutoString textEquiv; |
|
768 |
|
769 int16_t type; |
|
770 mColumn->GetType(&type); |
|
771 if (type == nsITreeColumn::TYPE_CHECKBOX) { |
|
772 mTreeView->GetCellValue(mRow, mColumn, textEquiv); |
|
773 if (mCachedTextEquiv != textEquiv) { |
|
774 bool isEnabled = textEquiv.EqualsLiteral("true"); |
|
775 nsRefPtr<AccEvent> accEvent = |
|
776 new AccStateChangeEvent(this, states::CHECKED, isEnabled); |
|
777 nsEventShell::FireEvent(accEvent); |
|
778 |
|
779 mCachedTextEquiv = textEquiv; |
|
780 return true; |
|
781 } |
|
782 |
|
783 return false; |
|
784 } |
|
785 |
|
786 mTreeView->GetCellText(mRow, mColumn, textEquiv); |
|
787 if (mCachedTextEquiv != textEquiv) { |
|
788 nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this); |
|
789 mCachedTextEquiv = textEquiv; |
|
790 return true; |
|
791 } |
|
792 |
|
793 return false; |
|
794 } |
|
795 |
|
796 //////////////////////////////////////////////////////////////////////////////// |
|
797 // XULTreeGridCellAccessible: Accessible protected implementation |
|
798 |
|
799 Accessible* |
|
800 XULTreeGridCellAccessible::GetSiblingAtOffset(int32_t aOffset, |
|
801 nsresult* aError) const |
|
802 { |
|
803 if (aError) |
|
804 *aError = NS_OK; // fail peacefully |
|
805 |
|
806 nsCOMPtr<nsITreeColumn> columnAtOffset(mColumn), column; |
|
807 if (aOffset < 0) { |
|
808 for (int32_t index = aOffset; index < 0 && columnAtOffset; index++) { |
|
809 column = nsCoreUtils::GetPreviousSensibleColumn(columnAtOffset); |
|
810 column.swap(columnAtOffset); |
|
811 } |
|
812 } else { |
|
813 for (int32_t index = aOffset; index > 0 && columnAtOffset; index--) { |
|
814 column = nsCoreUtils::GetNextSensibleColumn(columnAtOffset); |
|
815 column.swap(columnAtOffset); |
|
816 } |
|
817 } |
|
818 |
|
819 if (!columnAtOffset) |
|
820 return nullptr; |
|
821 |
|
822 nsRefPtr<XULTreeItemAccessibleBase> rowAcc = do_QueryObject(Parent()); |
|
823 return rowAcc->GetCellAccessible(columnAtOffset); |
|
824 } |
|
825 |
|
826 void |
|
827 XULTreeGridCellAccessible::DispatchClickEvent(nsIContent* aContent, |
|
828 uint32_t aActionIndex) |
|
829 { |
|
830 if (IsDefunct()) |
|
831 return; |
|
832 |
|
833 nsCoreUtils::DispatchClickEvent(mTree, mRow, mColumn); |
|
834 } |
|
835 |
|
836 //////////////////////////////////////////////////////////////////////////////// |
|
837 // XULTreeGridCellAccessible: protected implementation |
|
838 |
|
839 bool |
|
840 XULTreeGridCellAccessible::IsEditable() const |
|
841 { |
|
842 |
|
843 // XXX: logic corresponds to tree.xml, it's preferable to have interface |
|
844 // method to check it. |
|
845 bool isEditable = false; |
|
846 nsresult rv = mTreeView->IsEditable(mRow, mColumn, &isEditable); |
|
847 if (NS_FAILED(rv) || !isEditable) |
|
848 return false; |
|
849 |
|
850 nsCOMPtr<nsIDOMElement> columnElm; |
|
851 mColumn->GetElement(getter_AddRefs(columnElm)); |
|
852 if (!columnElm) |
|
853 return false; |
|
854 |
|
855 nsCOMPtr<nsIContent> columnContent(do_QueryInterface(columnElm)); |
|
856 if (!columnContent->AttrValueIs(kNameSpaceID_None, |
|
857 nsGkAtoms::editable, |
|
858 nsGkAtoms::_true, |
|
859 eCaseMatters)) |
|
860 return false; |
|
861 |
|
862 return mContent->AttrValueIs(kNameSpaceID_None, |
|
863 nsGkAtoms::editable, |
|
864 nsGkAtoms::_true, eCaseMatters); |
|
865 } |