/src/mozilla-central/accessible/xul/XULTreeAccessible.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #include "XULTreeAccessible.h" |
8 | | |
9 | | #include "Accessible-inl.h" |
10 | | #include "DocAccessible-inl.h" |
11 | | #include "nsAccCache.h" |
12 | | #include "nsAccUtils.h" |
13 | | #include "nsCoreUtils.h" |
14 | | #include "nsEventShell.h" |
15 | | #include "DocAccessible.h" |
16 | | #include "Relation.h" |
17 | | #include "Role.h" |
18 | | #include "States.h" |
19 | | #include "XULTreeGridAccessible.h" |
20 | | #include "nsQueryObject.h" |
21 | | |
22 | | #include "nsComponentManagerUtils.h" |
23 | | #include "nsIAccessibleRelation.h" |
24 | | #include "nsIAutoCompleteInput.h" |
25 | | #include "nsIAutoCompletePopup.h" |
26 | | #include "nsIBoxObject.h" |
27 | | #include "nsIDOMXULMenuListElement.h" |
28 | | #include "nsIDOMXULMultSelectCntrlEl.h" |
29 | | #include "nsITreeSelection.h" |
30 | | #include "nsIMutableArray.h" |
31 | | #include "nsTreeBodyFrame.h" |
32 | | #include "nsTreeColumns.h" |
33 | | #include "nsTreeUtils.h" |
34 | | |
35 | | using namespace mozilla::a11y; |
36 | | |
37 | | //////////////////////////////////////////////////////////////////////////////// |
38 | | // XULTreeAccessible |
39 | | //////////////////////////////////////////////////////////////////////////////// |
40 | | |
41 | | XULTreeAccessible:: |
42 | | XULTreeAccessible(nsIContent* aContent, DocAccessible* aDoc, |
43 | | nsTreeBodyFrame* aTreeFrame) : |
44 | | AccessibleWrap(aContent, aDoc), |
45 | | mAccessibleCache(kDefaultTreeCacheLength) |
46 | 0 | { |
47 | 0 | mType = eXULTreeType; |
48 | 0 | mGenericTypes |= eSelect; |
49 | 0 |
|
50 | 0 | nsCOMPtr<nsITreeView> view = aTreeFrame->GetExistingView(); |
51 | 0 | mTreeView = view; |
52 | 0 |
|
53 | 0 | mTree = nsCoreUtils::GetTreeBoxObject(aContent); |
54 | 0 | NS_ASSERTION(mTree, "Can't get mTree!\n"); |
55 | 0 |
|
56 | 0 | nsIContent* parentContent = mContent->GetParent(); |
57 | 0 | if (parentContent) { |
58 | 0 | nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm = |
59 | 0 | do_QueryInterface(parentContent); |
60 | 0 | if (autoCompletePopupElm) |
61 | 0 | mGenericTypes |= eAutoCompletePopup; |
62 | 0 | } |
63 | 0 | } |
64 | | |
65 | | XULTreeAccessible::~XULTreeAccessible() |
66 | 0 | { |
67 | 0 | } |
68 | | |
69 | | //////////////////////////////////////////////////////////////////////////////// |
70 | | // XULTreeAccessible: nsISupports and cycle collection implementation |
71 | | |
72 | | NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeAccessible, Accessible, |
73 | | mTree, mAccessibleCache) |
74 | | |
75 | 0 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XULTreeAccessible) |
76 | 0 | NS_INTERFACE_MAP_END_INHERITING(Accessible) |
77 | | |
78 | | NS_IMPL_ADDREF_INHERITED(XULTreeAccessible, Accessible) |
79 | | NS_IMPL_RELEASE_INHERITED(XULTreeAccessible, Accessible) |
80 | | |
81 | | //////////////////////////////////////////////////////////////////////////////// |
82 | | // XULTreeAccessible: Accessible implementation |
83 | | |
84 | | uint64_t |
85 | | XULTreeAccessible::NativeState() const |
86 | 0 | { |
87 | 0 | // Get focus status from base class. |
88 | 0 | uint64_t state = Accessible::NativeState(); |
89 | 0 |
|
90 | 0 | // readonly state |
91 | 0 | state |= states::READONLY; |
92 | 0 |
|
93 | 0 | // multiselectable state. |
94 | 0 | if (!mTreeView) |
95 | 0 | return state; |
96 | 0 | |
97 | 0 | nsCOMPtr<nsITreeSelection> selection; |
98 | 0 | mTreeView->GetSelection(getter_AddRefs(selection)); |
99 | 0 | NS_ENSURE_TRUE(selection, state); |
100 | 0 |
|
101 | 0 | bool isSingle = false; |
102 | 0 | nsresult rv = selection->GetSingle(&isSingle); |
103 | 0 | NS_ENSURE_SUCCESS(rv, state); |
104 | 0 |
|
105 | 0 | if (!isSingle) |
106 | 0 | state |= states::MULTISELECTABLE; |
107 | 0 |
|
108 | 0 | return state; |
109 | 0 | } |
110 | | |
111 | | void |
112 | | XULTreeAccessible::Value(nsString& aValue) const |
113 | 0 | { |
114 | 0 | aValue.Truncate(); |
115 | 0 | if (!mTreeView) |
116 | 0 | return; |
117 | 0 | |
118 | 0 | // Return the value is the first selected child. |
119 | 0 | nsCOMPtr<nsITreeSelection> selection; |
120 | 0 | mTreeView->GetSelection(getter_AddRefs(selection)); |
121 | 0 | if (!selection) |
122 | 0 | return; |
123 | 0 | |
124 | 0 | int32_t currentIndex; |
125 | 0 | selection->GetCurrentIndex(¤tIndex); |
126 | 0 | if (currentIndex >= 0) { |
127 | 0 | RefPtr<nsTreeColumn> keyCol; |
128 | 0 |
|
129 | 0 | RefPtr<nsTreeColumns> cols; |
130 | 0 | mTree->GetColumns(getter_AddRefs(cols)); |
131 | 0 | if (cols) |
132 | 0 | keyCol = cols->GetKeyColumn(); |
133 | 0 |
|
134 | 0 | mTreeView->GetCellText(currentIndex, keyCol, aValue); |
135 | 0 | } |
136 | 0 |
|
137 | 0 | } |
138 | | |
139 | | //////////////////////////////////////////////////////////////////////////////// |
140 | | // XULTreeAccessible: Accessible implementation |
141 | | |
142 | | void |
143 | | XULTreeAccessible::Shutdown() |
144 | 0 | { |
145 | 0 | if (mDoc && !mDoc->IsDefunct()) { |
146 | 0 | UnbindCacheEntriesFromDocument(mAccessibleCache); |
147 | 0 | } |
148 | 0 |
|
149 | 0 | mTree = nullptr; |
150 | 0 | mTreeView = nullptr; |
151 | 0 |
|
152 | 0 | AccessibleWrap::Shutdown(); |
153 | 0 | } |
154 | | |
155 | | role |
156 | | XULTreeAccessible::NativeRole() const |
157 | 0 | { |
158 | 0 | // No primary column means we're in a list. In fact, history and mail turn off |
159 | 0 | // the primary flag when switching to a flat view. |
160 | 0 |
|
161 | 0 | nsIContent* child = nsTreeUtils::GetDescendantChild(mContent, nsGkAtoms::treechildren); |
162 | 0 | NS_ASSERTION(child, "tree without treechildren!"); |
163 | 0 | nsTreeBodyFrame* treeFrame = do_QueryFrame(child->GetPrimaryFrame()); |
164 | 0 | NS_ASSERTION(treeFrame, "xul tree accessible for tree without a frame!"); |
165 | 0 | if (!treeFrame) |
166 | 0 | return roles::LIST; |
167 | 0 | |
168 | 0 | RefPtr<nsTreeColumns> cols = treeFrame->Columns(); |
169 | 0 | nsTreeColumn* primaryCol = cols->GetPrimaryColumn(); |
170 | 0 |
|
171 | 0 | return primaryCol ? roles::OUTLINE : roles::LIST; |
172 | 0 | } |
173 | | |
174 | | //////////////////////////////////////////////////////////////////////////////// |
175 | | // XULTreeAccessible: Accessible implementation (DON'T put methods here) |
176 | | |
177 | | Accessible* |
178 | | XULTreeAccessible::ChildAtPoint(int32_t aX, int32_t aY, |
179 | | EWhichChildAtPoint aWhichChild) |
180 | 0 | { |
181 | 0 | nsIFrame *frame = GetFrame(); |
182 | 0 | if (!frame) |
183 | 0 | return nullptr; |
184 | 0 | |
185 | 0 | nsPresContext *presContext = frame->PresContext(); |
186 | 0 | nsIPresShell* presShell = presContext->PresShell(); |
187 | 0 |
|
188 | 0 | nsIFrame *rootFrame = presShell->GetRootFrame(); |
189 | 0 | NS_ENSURE_TRUE(rootFrame, nullptr); |
190 | 0 |
|
191 | 0 | CSSIntRect rootRect = rootFrame->GetScreenRect(); |
192 | 0 |
|
193 | 0 | int32_t clientX = presContext->DevPixelsToIntCSSPixels(aX) - rootRect.X(); |
194 | 0 | int32_t clientY = presContext->DevPixelsToIntCSSPixels(aY) - rootRect.Y(); |
195 | 0 |
|
196 | 0 | int32_t row = -1; |
197 | 0 | RefPtr<nsTreeColumn> column; |
198 | 0 | nsAutoString childEltUnused; |
199 | 0 | mTree->GetCellAt(clientX, clientY, &row, getter_AddRefs(column), |
200 | 0 | childEltUnused); |
201 | 0 |
|
202 | 0 | // If we failed to find tree cell for the given point then it might be |
203 | 0 | // tree columns. |
204 | 0 | if (row == -1 || !column) |
205 | 0 | return AccessibleWrap::ChildAtPoint(aX, aY, aWhichChild); |
206 | 0 | |
207 | 0 | Accessible* child = GetTreeItemAccessible(row); |
208 | 0 | if (aWhichChild == eDeepestChild && child) { |
209 | 0 | // Look for accessible cell for the found item accessible. |
210 | 0 | RefPtr<XULTreeItemAccessibleBase> treeitem = do_QueryObject(child); |
211 | 0 |
|
212 | 0 | Accessible* cell = treeitem->GetCellAccessible(column); |
213 | 0 | if (cell) |
214 | 0 | child = cell; |
215 | 0 | } |
216 | 0 |
|
217 | 0 | return child; |
218 | 0 | } |
219 | | |
220 | | //////////////////////////////////////////////////////////////////////////////// |
221 | | // XULTreeAccessible: SelectAccessible |
222 | | |
223 | | Accessible* |
224 | | XULTreeAccessible::CurrentItem() const |
225 | 0 | { |
226 | 0 | if (!mTreeView) |
227 | 0 | return nullptr; |
228 | 0 | |
229 | 0 | nsCOMPtr<nsITreeSelection> selection; |
230 | 0 | mTreeView->GetSelection(getter_AddRefs(selection)); |
231 | 0 | if (selection) { |
232 | 0 | int32_t currentIndex = -1; |
233 | 0 | selection->GetCurrentIndex(¤tIndex); |
234 | 0 | if (currentIndex >= 0) |
235 | 0 | return GetTreeItemAccessible(currentIndex); |
236 | 0 | } |
237 | 0 | |
238 | 0 | return nullptr; |
239 | 0 | } |
240 | | |
241 | | void |
242 | | XULTreeAccessible::SetCurrentItem(const Accessible* aItem) |
243 | 0 | { |
244 | 0 | NS_ERROR("XULTreeAccessible::SetCurrentItem not implemented"); |
245 | 0 | } |
246 | | |
247 | | void |
248 | | XULTreeAccessible::SelectedItems(nsTArray<Accessible*>* aItems) |
249 | 0 | { |
250 | 0 | if (!mTreeView) |
251 | 0 | return; |
252 | 0 | |
253 | 0 | nsCOMPtr<nsITreeSelection> selection; |
254 | 0 | mTreeView->GetSelection(getter_AddRefs(selection)); |
255 | 0 | if (!selection) |
256 | 0 | return; |
257 | 0 | |
258 | 0 | int32_t rangeCount = 0; |
259 | 0 | selection->GetRangeCount(&rangeCount); |
260 | 0 | for (int32_t rangeIdx = 0; rangeIdx < rangeCount; rangeIdx++) { |
261 | 0 | int32_t firstIdx = 0, lastIdx = -1; |
262 | 0 | selection->GetRangeAt(rangeIdx, &firstIdx, &lastIdx); |
263 | 0 | for (int32_t rowIdx = firstIdx; rowIdx <= lastIdx; rowIdx++) { |
264 | 0 | Accessible* item = GetTreeItemAccessible(rowIdx); |
265 | 0 | if (item) |
266 | 0 | aItems->AppendElement(item); |
267 | 0 | } |
268 | 0 | } |
269 | 0 | } |
270 | | |
271 | | uint32_t |
272 | | XULTreeAccessible::SelectedItemCount() |
273 | 0 | { |
274 | 0 | if (!mTreeView) |
275 | 0 | return 0; |
276 | 0 | |
277 | 0 | nsCOMPtr<nsITreeSelection> selection; |
278 | 0 | mTreeView->GetSelection(getter_AddRefs(selection)); |
279 | 0 | if (selection) { |
280 | 0 | int32_t count = 0; |
281 | 0 | selection->GetCount(&count); |
282 | 0 | return count; |
283 | 0 | } |
284 | 0 | |
285 | 0 | return 0; |
286 | 0 | } |
287 | | |
288 | | bool |
289 | | XULTreeAccessible::AddItemToSelection(uint32_t aIndex) |
290 | 0 | { |
291 | 0 | if (!mTreeView) |
292 | 0 | return false; |
293 | 0 | |
294 | 0 | nsCOMPtr<nsITreeSelection> selection; |
295 | 0 | mTreeView->GetSelection(getter_AddRefs(selection)); |
296 | 0 | if (selection) { |
297 | 0 | bool isSelected = false; |
298 | 0 | selection->IsSelected(aIndex, &isSelected); |
299 | 0 | if (!isSelected) |
300 | 0 | selection->ToggleSelect(aIndex); |
301 | 0 |
|
302 | 0 | return true; |
303 | 0 | } |
304 | 0 | return false; |
305 | 0 | } |
306 | | |
307 | | bool |
308 | | XULTreeAccessible::RemoveItemFromSelection(uint32_t aIndex) |
309 | 0 | { |
310 | 0 | if (!mTreeView) |
311 | 0 | return false; |
312 | 0 | |
313 | 0 | nsCOMPtr<nsITreeSelection> selection; |
314 | 0 | mTreeView->GetSelection(getter_AddRefs(selection)); |
315 | 0 | if (selection) { |
316 | 0 | bool isSelected = false; |
317 | 0 | selection->IsSelected(aIndex, &isSelected); |
318 | 0 | if (isSelected) |
319 | 0 | selection->ToggleSelect(aIndex); |
320 | 0 |
|
321 | 0 | return true; |
322 | 0 | } |
323 | 0 | return false; |
324 | 0 | } |
325 | | |
326 | | bool |
327 | | XULTreeAccessible::IsItemSelected(uint32_t aIndex) |
328 | 0 | { |
329 | 0 | if (!mTreeView) |
330 | 0 | return false; |
331 | 0 | |
332 | 0 | nsCOMPtr<nsITreeSelection> selection; |
333 | 0 | mTreeView->GetSelection(getter_AddRefs(selection)); |
334 | 0 | if (selection) { |
335 | 0 | bool isSelected = false; |
336 | 0 | selection->IsSelected(aIndex, &isSelected); |
337 | 0 | return isSelected; |
338 | 0 | } |
339 | 0 | return false; |
340 | 0 | } |
341 | | |
342 | | bool |
343 | | XULTreeAccessible::UnselectAll() |
344 | 0 | { |
345 | 0 | if (!mTreeView) |
346 | 0 | return false; |
347 | 0 | |
348 | 0 | nsCOMPtr<nsITreeSelection> selection; |
349 | 0 | mTreeView->GetSelection(getter_AddRefs(selection)); |
350 | 0 | if (!selection) |
351 | 0 | return false; |
352 | 0 | |
353 | 0 | selection->ClearSelection(); |
354 | 0 | return true; |
355 | 0 | } |
356 | | |
357 | | Accessible* |
358 | | XULTreeAccessible::GetSelectedItem(uint32_t aIndex) |
359 | 0 | { |
360 | 0 | if (!mTreeView) |
361 | 0 | return nullptr; |
362 | 0 | |
363 | 0 | nsCOMPtr<nsITreeSelection> selection; |
364 | 0 | mTreeView->GetSelection(getter_AddRefs(selection)); |
365 | 0 | if (!selection) |
366 | 0 | return nullptr; |
367 | 0 | |
368 | 0 | uint32_t selCount = 0; |
369 | 0 | int32_t rangeCount = 0; |
370 | 0 | selection->GetRangeCount(&rangeCount); |
371 | 0 | for (int32_t rangeIdx = 0; rangeIdx < rangeCount; rangeIdx++) { |
372 | 0 | int32_t firstIdx = 0, lastIdx = -1; |
373 | 0 | selection->GetRangeAt(rangeIdx, &firstIdx, &lastIdx); |
374 | 0 | for (int32_t rowIdx = firstIdx; rowIdx <= lastIdx; rowIdx++) { |
375 | 0 | if (selCount == aIndex) |
376 | 0 | return GetTreeItemAccessible(rowIdx); |
377 | 0 | |
378 | 0 | selCount++; |
379 | 0 | } |
380 | 0 | } |
381 | 0 |
|
382 | 0 | return nullptr; |
383 | 0 | } |
384 | | |
385 | | bool |
386 | | XULTreeAccessible::SelectAll() |
387 | 0 | { |
388 | 0 | // see if we are multiple select if so set ourselves as such |
389 | 0 | if (!mTreeView) |
390 | 0 | return false; |
391 | 0 | |
392 | 0 | nsCOMPtr<nsITreeSelection> selection; |
393 | 0 | mTreeView->GetSelection(getter_AddRefs(selection)); |
394 | 0 | if (selection) { |
395 | 0 | bool single = false; |
396 | 0 | selection->GetSingle(&single); |
397 | 0 | if (!single) { |
398 | 0 | selection->SelectAll(); |
399 | 0 | return true; |
400 | 0 | } |
401 | 0 | } |
402 | 0 | |
403 | 0 | return false; |
404 | 0 | } |
405 | | |
406 | | //////////////////////////////////////////////////////////////////////////////// |
407 | | // XULTreeAccessible: Accessible implementation |
408 | | |
409 | | Accessible* |
410 | | XULTreeAccessible::GetChildAt(uint32_t aIndex) const |
411 | 0 | { |
412 | 0 | uint32_t childCount = Accessible::ChildCount(); |
413 | 0 | if (aIndex < childCount) |
414 | 0 | return Accessible::GetChildAt(aIndex); |
415 | 0 | |
416 | 0 | return GetTreeItemAccessible(aIndex - childCount); |
417 | 0 | } |
418 | | |
419 | | uint32_t |
420 | | XULTreeAccessible::ChildCount() const |
421 | 0 | { |
422 | 0 | // Tree's children count is row count + treecols count. |
423 | 0 | uint32_t childCount = Accessible::ChildCount(); |
424 | 0 | if (!mTreeView) |
425 | 0 | return childCount; |
426 | 0 | |
427 | 0 | int32_t rowCount = 0; |
428 | 0 | mTreeView->GetRowCount(&rowCount); |
429 | 0 | childCount += rowCount; |
430 | 0 |
|
431 | 0 | return childCount; |
432 | 0 | } |
433 | | |
434 | | Relation |
435 | | XULTreeAccessible::RelationByType(RelationType aType) const |
436 | 0 | { |
437 | 0 | if (aType == RelationType::NODE_PARENT_OF) { |
438 | 0 | if (mTreeView) |
439 | 0 | return Relation(new XULTreeItemIterator(this, mTreeView, -1)); |
440 | 0 | |
441 | 0 | return Relation(); |
442 | 0 | } |
443 | 0 | |
444 | 0 | return Accessible::RelationByType(aType); |
445 | 0 | } |
446 | | |
447 | | //////////////////////////////////////////////////////////////////////////////// |
448 | | // XULTreeAccessible: Widgets |
449 | | |
450 | | bool |
451 | | XULTreeAccessible::IsWidget() const |
452 | 0 | { |
453 | 0 | return true; |
454 | 0 | } |
455 | | |
456 | | bool |
457 | | XULTreeAccessible::IsActiveWidget() const |
458 | 0 | { |
459 | 0 | if (IsAutoCompletePopup()) { |
460 | 0 | nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm = |
461 | 0 | do_QueryInterface(mContent->GetParent()); |
462 | 0 |
|
463 | 0 | if (autoCompletePopupElm) { |
464 | 0 | bool isOpen = false; |
465 | 0 | autoCompletePopupElm->GetPopupOpen(&isOpen); |
466 | 0 | return isOpen; |
467 | 0 | } |
468 | 0 | } |
469 | 0 | return FocusMgr()->HasDOMFocus(mContent); |
470 | 0 | } |
471 | | |
472 | | bool |
473 | | XULTreeAccessible::AreItemsOperable() const |
474 | 0 | { |
475 | 0 | if (IsAutoCompletePopup()) { |
476 | 0 | nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm = |
477 | 0 | do_QueryInterface(mContent->GetParent()); |
478 | 0 |
|
479 | 0 | if (autoCompletePopupElm) { |
480 | 0 | bool isOpen = false; |
481 | 0 | autoCompletePopupElm->GetPopupOpen(&isOpen); |
482 | 0 | return isOpen; |
483 | 0 | } |
484 | 0 | } |
485 | 0 | return true; |
486 | 0 | } |
487 | | |
488 | | Accessible* |
489 | | XULTreeAccessible::ContainerWidget() const |
490 | 0 | { |
491 | 0 | if (IsAutoCompletePopup()) { |
492 | 0 | // This works for XUL autocompletes. It doesn't work for HTML forms |
493 | 0 | // autocomplete because of potential crossprocess calls (when autocomplete |
494 | 0 | // lives in content process while popup lives in chrome process). If that's |
495 | 0 | // a problem then rethink Widgets interface. |
496 | 0 | nsCOMPtr<nsIDOMXULMenuListElement> menuListElm = |
497 | 0 | do_QueryInterface(mContent->GetParent()); |
498 | 0 | if (menuListElm) { |
499 | 0 | RefPtr<mozilla::dom::Element> inputElm; |
500 | 0 | menuListElm->GetInputField(getter_AddRefs(inputElm)); |
501 | 0 | if (inputElm) { |
502 | 0 | Accessible* input = mDoc->GetAccessible(inputElm); |
503 | 0 | return input ? input->ContainerWidget() : nullptr; |
504 | 0 | } |
505 | 0 | } |
506 | 0 | } |
507 | 0 | return nullptr; |
508 | 0 | } |
509 | | |
510 | | //////////////////////////////////////////////////////////////////////////////// |
511 | | // XULTreeAccessible: public implementation |
512 | | |
513 | | Accessible* |
514 | | XULTreeAccessible::GetTreeItemAccessible(int32_t aRow) const |
515 | 0 | { |
516 | 0 | if (aRow < 0 || IsDefunct() || !mTreeView) |
517 | 0 | return nullptr; |
518 | 0 | |
519 | 0 | int32_t rowCount = 0; |
520 | 0 | nsresult rv = mTreeView->GetRowCount(&rowCount); |
521 | 0 | if (NS_FAILED(rv) || aRow >= rowCount) |
522 | 0 | return nullptr; |
523 | 0 | |
524 | 0 | void *key = reinterpret_cast<void*>(intptr_t(aRow)); |
525 | 0 | Accessible* cachedTreeItem = mAccessibleCache.GetWeak(key); |
526 | 0 | if (cachedTreeItem) |
527 | 0 | return cachedTreeItem; |
528 | 0 | |
529 | 0 | RefPtr<Accessible> treeItem = CreateTreeItemAccessible(aRow); |
530 | 0 | if (treeItem) { |
531 | 0 | mAccessibleCache.Put(key, treeItem); |
532 | 0 | Document()->BindToDocument(treeItem, nullptr); |
533 | 0 | return treeItem; |
534 | 0 | } |
535 | 0 | |
536 | 0 | return nullptr; |
537 | 0 | } |
538 | | |
539 | | void |
540 | | XULTreeAccessible::InvalidateCache(int32_t aRow, int32_t aCount) |
541 | 0 | { |
542 | 0 | if (IsDefunct()) |
543 | 0 | return; |
544 | 0 | |
545 | 0 | if (!mTreeView) { |
546 | 0 | UnbindCacheEntriesFromDocument(mAccessibleCache); |
547 | 0 | return; |
548 | 0 | } |
549 | 0 | |
550 | 0 | // Do not invalidate the cache if rows have been inserted. |
551 | 0 | if (aCount > 0) |
552 | 0 | return; |
553 | 0 | |
554 | 0 | DocAccessible* document = Document(); |
555 | 0 |
|
556 | 0 | // Fire destroy event for removed tree items and delete them from caches. |
557 | 0 | for (int32_t rowIdx = aRow; rowIdx < aRow - aCount; rowIdx++) { |
558 | 0 |
|
559 | 0 | void* key = reinterpret_cast<void*>(intptr_t(rowIdx)); |
560 | 0 | Accessible* treeItem = mAccessibleCache.GetWeak(key); |
561 | 0 |
|
562 | 0 | if (treeItem) { |
563 | 0 | RefPtr<AccEvent> event = |
564 | 0 | new AccEvent(nsIAccessibleEvent::EVENT_HIDE, treeItem); |
565 | 0 | nsEventShell::FireEvent(event); |
566 | 0 |
|
567 | 0 | // Unbind from document, shutdown and remove from tree cache. |
568 | 0 | document->UnbindFromDocument(treeItem); |
569 | 0 | mAccessibleCache.Remove(key); |
570 | 0 | } |
571 | 0 | } |
572 | 0 |
|
573 | 0 | // We dealt with removed tree items already however we may keep tree items |
574 | 0 | // having row indexes greater than row count. We should remove these dead tree |
575 | 0 | // items silently from caches. |
576 | 0 | int32_t newRowCount = 0; |
577 | 0 | nsresult rv = mTreeView->GetRowCount(&newRowCount); |
578 | 0 | if (NS_FAILED(rv)) |
579 | 0 | return; |
580 | 0 | |
581 | 0 | int32_t oldRowCount = newRowCount - aCount; |
582 | 0 |
|
583 | 0 | for (int32_t rowIdx = newRowCount; rowIdx < oldRowCount; ++rowIdx) { |
584 | 0 |
|
585 | 0 | void *key = reinterpret_cast<void*>(intptr_t(rowIdx)); |
586 | 0 | Accessible* treeItem = mAccessibleCache.GetWeak(key); |
587 | 0 |
|
588 | 0 | if (treeItem) { |
589 | 0 | // Unbind from document, shutdown and remove from tree cache. |
590 | 0 | document->UnbindFromDocument(treeItem); |
591 | 0 | mAccessibleCache.Remove(key); |
592 | 0 | } |
593 | 0 | } |
594 | 0 | } |
595 | | |
596 | | void |
597 | | XULTreeAccessible::TreeViewInvalidated(int32_t aStartRow, int32_t aEndRow, |
598 | | int32_t aStartCol, int32_t aEndCol) |
599 | 0 | { |
600 | 0 | if (IsDefunct()) |
601 | 0 | return; |
602 | 0 | |
603 | 0 | if (!mTreeView) { |
604 | 0 | UnbindCacheEntriesFromDocument(mAccessibleCache); |
605 | 0 | return; |
606 | 0 | } |
607 | 0 | |
608 | 0 | int32_t endRow = aEndRow; |
609 | 0 |
|
610 | 0 | nsresult rv; |
611 | 0 | if (endRow == -1) { |
612 | 0 | int32_t rowCount = 0; |
613 | 0 | rv = mTreeView->GetRowCount(&rowCount); |
614 | 0 | if (NS_FAILED(rv)) |
615 | 0 | return; |
616 | 0 | |
617 | 0 | endRow = rowCount - 1; |
618 | 0 | } |
619 | 0 |
|
620 | 0 | RefPtr<nsTreeColumns> treeColumns; |
621 | 0 | mTree->GetColumns(getter_AddRefs(treeColumns)); |
622 | 0 | if (!treeColumns) |
623 | 0 | return; |
624 | 0 | |
625 | 0 | int32_t endCol = aEndCol; |
626 | 0 |
|
627 | 0 | if (endCol == -1) { |
628 | 0 | // We need to make sure to cast to int32_t before we do the subtraction, in |
629 | 0 | // case the column count is 0. |
630 | 0 | endCol = static_cast<int32_t>(treeColumns->Count()) - 1; |
631 | 0 | } |
632 | 0 |
|
633 | 0 | for (int32_t rowIdx = aStartRow; rowIdx <= endRow; ++rowIdx) { |
634 | 0 |
|
635 | 0 | void *key = reinterpret_cast<void*>(intptr_t(rowIdx)); |
636 | 0 | Accessible* accessible = mAccessibleCache.GetWeak(key); |
637 | 0 |
|
638 | 0 | if (accessible) { |
639 | 0 | RefPtr<XULTreeItemAccessibleBase> treeitemAcc = do_QueryObject(accessible); |
640 | 0 | NS_ASSERTION(treeitemAcc, "Wrong accessible at the given key!"); |
641 | 0 |
|
642 | 0 | treeitemAcc->RowInvalidated(aStartCol, endCol); |
643 | 0 | } |
644 | 0 | } |
645 | 0 | } |
646 | | |
647 | | void |
648 | | XULTreeAccessible::TreeViewChanged(nsITreeView* aView) |
649 | 0 | { |
650 | 0 | if (IsDefunct()) |
651 | 0 | return; |
652 | 0 | |
653 | 0 | // Fire reorder event on tree accessible on accessible tree (do not fire |
654 | 0 | // show/hide events on tree items because it can be expensive to fire them for |
655 | 0 | // each tree item. |
656 | 0 | RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(this); |
657 | 0 | Document()->FireDelayedEvent(reorderEvent); |
658 | 0 |
|
659 | 0 | // Clear cache. |
660 | 0 | UnbindCacheEntriesFromDocument(mAccessibleCache); |
661 | 0 |
|
662 | 0 | mTreeView = aView; |
663 | 0 | Accessible* item = CurrentItem(); |
664 | 0 | if (item) { |
665 | 0 | FocusMgr()->ActiveItemChanged(item, true); |
666 | 0 | } |
667 | 0 | } |
668 | | |
669 | | //////////////////////////////////////////////////////////////////////////////// |
670 | | // XULTreeAccessible: protected implementation |
671 | | |
672 | | already_AddRefed<Accessible> |
673 | | XULTreeAccessible::CreateTreeItemAccessible(int32_t aRow) const |
674 | 0 | { |
675 | 0 | RefPtr<Accessible> accessible = |
676 | 0 | new XULTreeItemAccessible(mContent, mDoc, const_cast<XULTreeAccessible*>(this), |
677 | 0 | mTree, mTreeView, aRow); |
678 | 0 |
|
679 | 0 | return accessible.forget(); |
680 | 0 | } |
681 | | |
682 | | //////////////////////////////////////////////////////////////////////////////// |
683 | | // XULTreeItemAccessibleBase |
684 | | //////////////////////////////////////////////////////////////////////////////// |
685 | | |
686 | | XULTreeItemAccessibleBase:: |
687 | | XULTreeItemAccessibleBase(nsIContent* aContent, DocAccessible* aDoc, |
688 | | Accessible* aParent, nsITreeBoxObject* aTree, |
689 | | nsITreeView* aTreeView, int32_t aRow) : |
690 | | AccessibleWrap(aContent, aDoc), |
691 | | mTree(aTree), mTreeView(aTreeView), mRow(aRow) |
692 | 0 | { |
693 | 0 | mParent = aParent; |
694 | 0 | mStateFlags |= eSharedNode; |
695 | 0 | } |
696 | | |
697 | | XULTreeItemAccessibleBase::~XULTreeItemAccessibleBase() |
698 | 0 | { |
699 | 0 | } |
700 | | |
701 | | //////////////////////////////////////////////////////////////////////////////// |
702 | | // XULTreeItemAccessibleBase: nsISupports implementation |
703 | | |
704 | | NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeItemAccessibleBase, Accessible, |
705 | | mTree) |
706 | | |
707 | | NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(XULTreeItemAccessibleBase, |
708 | | Accessible, |
709 | | XULTreeItemAccessibleBase) |
710 | | |
711 | | //////////////////////////////////////////////////////////////////////////////// |
712 | | // XULTreeItemAccessibleBase: Accessible |
713 | | |
714 | | Accessible* |
715 | | XULTreeItemAccessibleBase::FocusedChild() |
716 | 0 | { |
717 | 0 | return FocusMgr()->FocusedAccessible() == this ? this : nullptr; |
718 | 0 | } |
719 | | |
720 | | nsIntRect |
721 | | XULTreeItemAccessibleBase::BoundsInCSSPixels() const |
722 | 0 | { |
723 | 0 | // Get x coordinate and width from treechildren element, get y coordinate and |
724 | 0 | // height from tree cell. |
725 | 0 |
|
726 | 0 | nsCOMPtr<nsIBoxObject> boxObj = nsCoreUtils::GetTreeBodyBoxObject(mTree); |
727 | 0 | if (!boxObj) { |
728 | 0 | return nsIntRect(); |
729 | 0 | } |
730 | 0 | |
731 | 0 | RefPtr<nsTreeColumn> column = nsCoreUtils::GetFirstSensibleColumn(mTree); |
732 | 0 |
|
733 | 0 | int32_t x = 0, y = 0, width = 0, height = 0; |
734 | 0 | nsresult rv = mTree->GetCoordsForCellItem(mRow, column, EmptyString(), |
735 | 0 | &x, &y, &width, &height); |
736 | 0 | if (NS_FAILED(rv)) { |
737 | 0 | return nsIntRect(); |
738 | 0 | } |
739 | 0 | |
740 | 0 | boxObj->GetWidth(&width); |
741 | 0 |
|
742 | 0 | int32_t tcX = 0, tcY = 0; |
743 | 0 | boxObj->GetScreenX(&tcX); |
744 | 0 | boxObj->GetScreenY(&tcY); |
745 | 0 |
|
746 | 0 | x = tcX; |
747 | 0 | y += tcY; |
748 | 0 |
|
749 | 0 | return nsIntRect(x, y, width, height); |
750 | 0 | } |
751 | | |
752 | | nsRect |
753 | | XULTreeItemAccessibleBase::BoundsInAppUnits() const |
754 | 0 | { |
755 | 0 | nsIntRect bounds = BoundsInCSSPixels(); |
756 | 0 | nsPresContext* presContext = mDoc->PresContext(); |
757 | 0 | return nsRect(presContext->CSSPixelsToAppUnits(bounds.X()), |
758 | 0 | presContext->CSSPixelsToAppUnits(bounds.Y()), |
759 | 0 | presContext->CSSPixelsToAppUnits(bounds.Width()), |
760 | 0 | presContext->CSSPixelsToAppUnits(bounds.Height())); |
761 | 0 | } |
762 | | |
763 | | void |
764 | | XULTreeItemAccessibleBase::SetSelected(bool aSelect) |
765 | 0 | { |
766 | 0 | nsCOMPtr<nsITreeSelection> selection; |
767 | 0 | mTreeView->GetSelection(getter_AddRefs(selection)); |
768 | 0 | if (selection) { |
769 | 0 | bool isSelected = false; |
770 | 0 | selection->IsSelected(mRow, &isSelected); |
771 | 0 | if (isSelected != aSelect) |
772 | 0 | selection->ToggleSelect(mRow); |
773 | 0 | } |
774 | 0 | } |
775 | | |
776 | | void |
777 | | XULTreeItemAccessibleBase::TakeFocus() const |
778 | 0 | { |
779 | 0 | nsCOMPtr<nsITreeSelection> selection; |
780 | 0 | mTreeView->GetSelection(getter_AddRefs(selection)); |
781 | 0 | if (selection) |
782 | 0 | selection->SetCurrentIndex(mRow); |
783 | 0 |
|
784 | 0 | // focus event will be fired here |
785 | 0 | Accessible::TakeFocus(); |
786 | 0 | } |
787 | | |
788 | | Relation |
789 | | XULTreeItemAccessibleBase::RelationByType(RelationType aType) const |
790 | 0 | { |
791 | 0 |
|
792 | 0 | switch (aType) { |
793 | 0 | case RelationType::NODE_CHILD_OF: { |
794 | 0 | int32_t parentIndex = -1; |
795 | 0 | if (!NS_SUCCEEDED(mTreeView->GetParentIndex(mRow, &parentIndex))) |
796 | 0 | return Relation(); |
797 | 0 | |
798 | 0 | if (parentIndex == -1) |
799 | 0 | return Relation(mParent); |
800 | 0 | |
801 | 0 | XULTreeAccessible* treeAcc = mParent->AsXULTree(); |
802 | 0 | return Relation(treeAcc->GetTreeItemAccessible(parentIndex)); |
803 | 0 | } |
804 | 0 |
|
805 | 0 | case RelationType::NODE_PARENT_OF: { |
806 | 0 | bool isTrue = false; |
807 | 0 | if (NS_FAILED(mTreeView->IsContainerEmpty(mRow, &isTrue)) || isTrue) |
808 | 0 | return Relation(); |
809 | 0 | |
810 | 0 | if (NS_FAILED(mTreeView->IsContainerOpen(mRow, &isTrue)) || !isTrue) |
811 | 0 | return Relation(); |
812 | 0 | |
813 | 0 | XULTreeAccessible* tree = mParent->AsXULTree(); |
814 | 0 | return Relation(new XULTreeItemIterator(tree, mTreeView, mRow)); |
815 | 0 | } |
816 | 0 |
|
817 | 0 | default: |
818 | 0 | return Relation(); |
819 | 0 | } |
820 | 0 | } |
821 | | |
822 | | uint8_t |
823 | | XULTreeItemAccessibleBase::ActionCount() const |
824 | 0 | { |
825 | 0 | // "activate" action is available for all treeitems, "expand/collapse" action |
826 | 0 | // is avaible for treeitem which is container. |
827 | 0 | return IsExpandable() ? 2 : 1; |
828 | 0 | } |
829 | | |
830 | | void |
831 | | XULTreeItemAccessibleBase::ActionNameAt(uint8_t aIndex, nsAString& aName) |
832 | 0 | { |
833 | 0 | if (aIndex == eAction_Click) { |
834 | 0 | aName.AssignLiteral("activate"); |
835 | 0 | return; |
836 | 0 | } |
837 | 0 | |
838 | 0 | if (aIndex == eAction_Expand && IsExpandable()) { |
839 | 0 | bool isContainerOpen = false; |
840 | 0 | mTreeView->IsContainerOpen(mRow, &isContainerOpen); |
841 | 0 | if (isContainerOpen) |
842 | 0 | aName.AssignLiteral("collapse"); |
843 | 0 | else |
844 | 0 | aName.AssignLiteral("expand"); |
845 | 0 | } |
846 | 0 | } |
847 | | |
848 | | bool |
849 | | XULTreeItemAccessibleBase::DoAction(uint8_t aIndex) const |
850 | 0 | { |
851 | 0 | if (aIndex != eAction_Click && |
852 | 0 | (aIndex != eAction_Expand || !IsExpandable())) |
853 | 0 | return false; |
854 | 0 | |
855 | 0 | DoCommand(nullptr, aIndex); |
856 | 0 | return true; |
857 | 0 | } |
858 | | |
859 | | //////////////////////////////////////////////////////////////////////////////// |
860 | | // XULTreeItemAccessibleBase: Accessible implementation |
861 | | |
862 | | void |
863 | | XULTreeItemAccessibleBase::Shutdown() |
864 | 0 | { |
865 | 0 | mTree = nullptr; |
866 | 0 | mTreeView = nullptr; |
867 | 0 | mRow = -1; |
868 | 0 | mParent = nullptr; // null-out to prevent base class's shutdown ops |
869 | 0 |
|
870 | 0 | AccessibleWrap::Shutdown(); |
871 | 0 | } |
872 | | |
873 | | GroupPos |
874 | | XULTreeItemAccessibleBase::GroupPosition() |
875 | 0 | { |
876 | 0 | GroupPos groupPos; |
877 | 0 |
|
878 | 0 | int32_t level; |
879 | 0 | nsresult rv = mTreeView->GetLevel(mRow, &level); |
880 | 0 | NS_ENSURE_SUCCESS(rv, groupPos); |
881 | 0 |
|
882 | 0 | int32_t topCount = 1; |
883 | 0 | for (int32_t index = mRow - 1; index >= 0; index--) { |
884 | 0 | int32_t lvl = -1; |
885 | 0 | if (NS_SUCCEEDED(mTreeView->GetLevel(index, &lvl))) { |
886 | 0 | if (lvl < level) |
887 | 0 | break; |
888 | 0 | |
889 | 0 | if (lvl == level) |
890 | 0 | topCount++; |
891 | 0 | } |
892 | 0 | } |
893 | 0 |
|
894 | 0 | int32_t rowCount = 0; |
895 | 0 | rv = mTreeView->GetRowCount(&rowCount); |
896 | 0 | NS_ENSURE_SUCCESS(rv, groupPos); |
897 | 0 |
|
898 | 0 | int32_t bottomCount = 0; |
899 | 0 | for (int32_t index = mRow + 1; index < rowCount; index++) { |
900 | 0 | int32_t lvl = -1; |
901 | 0 | if (NS_SUCCEEDED(mTreeView->GetLevel(index, &lvl))) { |
902 | 0 | if (lvl < level) |
903 | 0 | break; |
904 | 0 | |
905 | 0 | if (lvl == level) |
906 | 0 | bottomCount++; |
907 | 0 | } |
908 | 0 | } |
909 | 0 |
|
910 | 0 | groupPos.level = level + 1; |
911 | 0 | groupPos.setSize = topCount + bottomCount; |
912 | 0 | groupPos.posInSet = topCount; |
913 | 0 |
|
914 | 0 | return groupPos; |
915 | 0 | } |
916 | | |
917 | | uint64_t |
918 | | XULTreeItemAccessibleBase::NativeState() const |
919 | 0 | { |
920 | 0 |
|
921 | 0 | // focusable and selectable states |
922 | 0 | uint64_t state = NativeInteractiveState(); |
923 | 0 |
|
924 | 0 | // expanded/collapsed state |
925 | 0 | if (IsExpandable()) { |
926 | 0 | bool isContainerOpen; |
927 | 0 | mTreeView->IsContainerOpen(mRow, &isContainerOpen); |
928 | 0 | state |= isContainerOpen ? states::EXPANDED : states::COLLAPSED; |
929 | 0 | } |
930 | 0 |
|
931 | 0 | // selected state |
932 | 0 | nsCOMPtr<nsITreeSelection> selection; |
933 | 0 | mTreeView->GetSelection(getter_AddRefs(selection)); |
934 | 0 | if (selection) { |
935 | 0 | bool isSelected; |
936 | 0 | selection->IsSelected(mRow, &isSelected); |
937 | 0 | if (isSelected) |
938 | 0 | state |= states::SELECTED; |
939 | 0 | } |
940 | 0 |
|
941 | 0 | // focused state |
942 | 0 | if (FocusMgr()->IsFocused(this)) |
943 | 0 | state |= states::FOCUSED; |
944 | 0 |
|
945 | 0 | // invisible state |
946 | 0 | int32_t firstVisibleRow, lastVisibleRow; |
947 | 0 | mTree->GetFirstVisibleRow(&firstVisibleRow); |
948 | 0 | mTree->GetLastVisibleRow(&lastVisibleRow); |
949 | 0 | if (mRow < firstVisibleRow || mRow > lastVisibleRow) |
950 | 0 | state |= states::INVISIBLE; |
951 | 0 |
|
952 | 0 | return state; |
953 | 0 | } |
954 | | |
955 | | uint64_t |
956 | | XULTreeItemAccessibleBase::NativeInteractiveState() const |
957 | 0 | { |
958 | 0 | return states::FOCUSABLE | states::SELECTABLE; |
959 | 0 | } |
960 | | |
961 | | int32_t |
962 | | XULTreeItemAccessibleBase::IndexInParent() const |
963 | 0 | { |
964 | 0 | return mParent ? mParent->ContentChildCount() + mRow : -1; |
965 | 0 | } |
966 | | |
967 | | //////////////////////////////////////////////////////////////////////////////// |
968 | | // XULTreeItemAccessibleBase: Widgets |
969 | | |
970 | | Accessible* |
971 | | XULTreeItemAccessibleBase::ContainerWidget() const |
972 | 0 | { |
973 | 0 | return mParent; |
974 | 0 | } |
975 | | |
976 | | //////////////////////////////////////////////////////////////////////////////// |
977 | | // XULTreeItemAccessibleBase: Accessible protected methods |
978 | | |
979 | | void |
980 | | XULTreeItemAccessibleBase::DispatchClickEvent(nsIContent* aContent, |
981 | | uint32_t aActionIndex) const |
982 | 0 | { |
983 | 0 | if (IsDefunct()) |
984 | 0 | return; |
985 | 0 | |
986 | 0 | RefPtr<nsTreeColumns> columns; |
987 | 0 | mTree->GetColumns(getter_AddRefs(columns)); |
988 | 0 | if (!columns) |
989 | 0 | return; |
990 | 0 | |
991 | 0 | // Get column and pseudo element. |
992 | 0 | RefPtr<nsTreeColumn> column; |
993 | 0 | nsAutoString pseudoElm; |
994 | 0 |
|
995 | 0 | if (aActionIndex == eAction_Click) { |
996 | 0 | // Key column is visible and clickable. |
997 | 0 | column = columns->GetKeyColumn(); |
998 | 0 | } else { |
999 | 0 | // Primary column contains a twisty we should click on. |
1000 | 0 | column = columns->GetPrimaryColumn(); |
1001 | 0 | pseudoElm = NS_LITERAL_STRING("twisty"); |
1002 | 0 | } |
1003 | 0 |
|
1004 | 0 | if (column) |
1005 | 0 | nsCoreUtils::DispatchClickEvent(mTree, mRow, column, pseudoElm); |
1006 | 0 | } |
1007 | | |
1008 | | Accessible* |
1009 | | XULTreeItemAccessibleBase::GetSiblingAtOffset(int32_t aOffset, |
1010 | | nsresult* aError) const |
1011 | 0 | { |
1012 | 0 | if (aError) |
1013 | 0 | *aError = NS_OK; // fail peacefully |
1014 | 0 |
|
1015 | 0 | return mParent->GetChildAt(IndexInParent() + aOffset); |
1016 | 0 | } |
1017 | | |
1018 | | //////////////////////////////////////////////////////////////////////////////// |
1019 | | // XULTreeItemAccessibleBase: protected implementation |
1020 | | |
1021 | | bool |
1022 | | XULTreeItemAccessibleBase::IsExpandable() const |
1023 | 0 | { |
1024 | 0 |
|
1025 | 0 | bool isContainer = false; |
1026 | 0 | mTreeView->IsContainer(mRow, &isContainer); |
1027 | 0 | if (isContainer) { |
1028 | 0 | bool isEmpty = false; |
1029 | 0 | mTreeView->IsContainerEmpty(mRow, &isEmpty); |
1030 | 0 | if (!isEmpty) { |
1031 | 0 | RefPtr<nsTreeColumns> columns; |
1032 | 0 | mTree->GetColumns(getter_AddRefs(columns)); |
1033 | 0 | if (columns) { |
1034 | 0 | nsTreeColumn* primaryColumn = columns->GetPrimaryColumn(); |
1035 | 0 | if (primaryColumn && |
1036 | 0 | !nsCoreUtils::IsColumnHidden(primaryColumn)) |
1037 | 0 | return true; |
1038 | 0 | } |
1039 | 0 | } |
1040 | 0 | } |
1041 | 0 | |
1042 | 0 | return false; |
1043 | 0 | } |
1044 | | |
1045 | | void |
1046 | | XULTreeItemAccessibleBase::GetCellName(nsTreeColumn* aColumn, nsAString& aName) const |
1047 | 0 | { |
1048 | 0 |
|
1049 | 0 | mTreeView->GetCellText(mRow, aColumn, aName); |
1050 | 0 |
|
1051 | 0 | // If there is still no name try the cell value: |
1052 | 0 | // This is for graphical cells. We need tree/table view implementors to |
1053 | 0 | // implement FooView::GetCellValue to return a meaningful string for cases |
1054 | 0 | // where there is something shown in the cell (non-text) such as a star icon; |
1055 | 0 | // in which case GetCellValue for that cell would return "starred" or |
1056 | 0 | // "flagged" for example. |
1057 | 0 | if (aName.IsEmpty()) |
1058 | 0 | mTreeView->GetCellValue(mRow, aColumn, aName); |
1059 | 0 | } |
1060 | | |
1061 | | |
1062 | | //////////////////////////////////////////////////////////////////////////////// |
1063 | | // XULTreeItemAccessible |
1064 | | //////////////////////////////////////////////////////////////////////////////// |
1065 | | |
1066 | | XULTreeItemAccessible:: |
1067 | | XULTreeItemAccessible(nsIContent* aContent, DocAccessible* aDoc, |
1068 | | Accessible* aParent, nsITreeBoxObject* aTree, |
1069 | | nsITreeView* aTreeView, int32_t aRow) : |
1070 | | XULTreeItemAccessibleBase(aContent, aDoc, aParent, aTree, aTreeView, aRow) |
1071 | 0 | { |
1072 | 0 | mStateFlags |= eNoKidsFromDOM; |
1073 | 0 | mColumn = nsCoreUtils::GetFirstSensibleColumn(mTree); |
1074 | 0 | GetCellName(mColumn, mCachedName); |
1075 | 0 | } |
1076 | | |
1077 | | XULTreeItemAccessible::~XULTreeItemAccessible() |
1078 | 0 | { |
1079 | 0 | } |
1080 | | |
1081 | | //////////////////////////////////////////////////////////////////////////////// |
1082 | | // XULTreeItemAccessible: nsISupports implementation |
1083 | | |
1084 | | NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeItemAccessible, |
1085 | | XULTreeItemAccessibleBase, |
1086 | | mColumn) |
1087 | | |
1088 | 0 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XULTreeItemAccessible) |
1089 | 0 | NS_INTERFACE_MAP_END_INHERITING(XULTreeItemAccessibleBase) |
1090 | | NS_IMPL_ADDREF_INHERITED(XULTreeItemAccessible, XULTreeItemAccessibleBase) |
1091 | | NS_IMPL_RELEASE_INHERITED(XULTreeItemAccessible, XULTreeItemAccessibleBase) |
1092 | | |
1093 | | //////////////////////////////////////////////////////////////////////////////// |
1094 | | // XULTreeItemAccessible: nsIAccessible implementation |
1095 | | |
1096 | | ENameValueFlag |
1097 | | XULTreeItemAccessible::Name(nsString& aName) const |
1098 | 0 | { |
1099 | 0 | aName.Truncate(); |
1100 | 0 |
|
1101 | 0 | GetCellName(mColumn, aName); |
1102 | 0 | return eNameOK; |
1103 | 0 | } |
1104 | | |
1105 | | //////////////////////////////////////////////////////////////////////////////// |
1106 | | // XULTreeItemAccessible: Accessible implementation |
1107 | | |
1108 | | void |
1109 | | XULTreeItemAccessible::Shutdown() |
1110 | 0 | { |
1111 | 0 | mColumn = nullptr; |
1112 | 0 | XULTreeItemAccessibleBase::Shutdown(); |
1113 | 0 | } |
1114 | | |
1115 | | role |
1116 | | XULTreeItemAccessible::NativeRole() const |
1117 | 0 | { |
1118 | 0 | RefPtr<nsTreeColumns> columns; |
1119 | 0 | mTree->GetColumns(getter_AddRefs(columns)); |
1120 | 0 | if (!columns) { |
1121 | 0 | NS_ERROR("No tree columns object in the tree!"); |
1122 | 0 | return roles::NOTHING; |
1123 | 0 | } |
1124 | 0 |
|
1125 | 0 | nsTreeColumn* primaryColumn = columns->GetPrimaryColumn(); |
1126 | 0 |
|
1127 | 0 | return primaryColumn ? roles::OUTLINEITEM : roles::LISTITEM; |
1128 | 0 | } |
1129 | | |
1130 | | //////////////////////////////////////////////////////////////////////////////// |
1131 | | // XULTreeItemAccessible: XULTreeItemAccessibleBase implementation |
1132 | | |
1133 | | void |
1134 | | XULTreeItemAccessible::RowInvalidated(int32_t aStartColIdx, int32_t aEndColIdx) |
1135 | 0 | { |
1136 | 0 | nsAutoString name; |
1137 | 0 | Name(name); |
1138 | 0 |
|
1139 | 0 | if (name != mCachedName) { |
1140 | 0 | nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this); |
1141 | 0 | mCachedName = name; |
1142 | 0 | } |
1143 | 0 | } |
1144 | | |
1145 | | |
1146 | | //////////////////////////////////////////////////////////////////////////////// |
1147 | | // XULTreeColumAccessible |
1148 | | //////////////////////////////////////////////////////////////////////////////// |
1149 | | |
1150 | | XULTreeColumAccessible:: |
1151 | | XULTreeColumAccessible(nsIContent* aContent, DocAccessible* aDoc) : |
1152 | | XULColumAccessible(aContent, aDoc) |
1153 | 0 | { |
1154 | 0 | } |
1155 | | |
1156 | | Accessible* |
1157 | | XULTreeColumAccessible::GetSiblingAtOffset(int32_t aOffset, |
1158 | | nsresult* aError) const |
1159 | 0 | { |
1160 | 0 | if (aOffset < 0) |
1161 | 0 | return XULColumAccessible::GetSiblingAtOffset(aOffset, aError); |
1162 | 0 | |
1163 | 0 | if (aError) |
1164 | 0 | *aError = NS_OK; // fail peacefully |
1165 | 0 |
|
1166 | 0 | nsCOMPtr<nsITreeBoxObject> tree = nsCoreUtils::GetTreeBoxObject(mContent); |
1167 | 0 | if (tree) { |
1168 | 0 | nsCOMPtr<nsITreeView> treeView; |
1169 | 0 | tree->GetView(getter_AddRefs(treeView)); |
1170 | 0 | if (treeView) { |
1171 | 0 | int32_t rowCount = 0; |
1172 | 0 | treeView->GetRowCount(&rowCount); |
1173 | 0 | if (rowCount > 0 && aOffset <= rowCount) { |
1174 | 0 | XULTreeAccessible* treeAcc = Parent()->AsXULTree(); |
1175 | 0 |
|
1176 | 0 | if (treeAcc) |
1177 | 0 | return treeAcc->GetTreeItemAccessible(aOffset - 1); |
1178 | 0 | } |
1179 | 0 | } |
1180 | 0 | } |
1181 | 0 | |
1182 | 0 | return nullptr; |
1183 | 0 | } |