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.
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/. */
7 #include "XULTreeAccessible.h"
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"
20 #include "nsComponentManagerUtils.h"
21 #include "nsIAccessibleRelation.h"
22 #include "nsIAutoCompleteInput.h"
23 #include "nsIAutoCompletePopup.h"
24 #include "nsIBoxObject.h"
25 #include "nsIDOMXULElement.h"
26 #include "nsIDOMXULMenuListElement.h"
27 #include "nsIDOMXULMultSelectCntrlEl.h"
28 #include "nsIDOMXULTreeElement.h"
29 #include "nsITreeSelection.h"
30 #include "nsIMutableArray.h"
31 #include "nsTreeBodyFrame.h"
32 #include "nsTreeColumns.h"
33 #include "nsTreeUtils.h"
35 using namespace mozilla::a11y;
37 ////////////////////////////////////////////////////////////////////////////////
38 // XULTreeAccessible
39 ////////////////////////////////////////////////////////////////////////////////
41 XULTreeAccessible::
42 XULTreeAccessible(nsIContent* aContent, DocAccessible* aDoc,
43 nsTreeBodyFrame* aTreeFrame) :
44 AccessibleWrap(aContent, aDoc),
45 mAccessibleCache(kDefaultTreeCacheSize)
46 {
47 mType = eXULTreeType;
48 mGenericTypes |= eSelect;
50 nsCOMPtr<nsITreeView> view = aTreeFrame->GetExistingView();
51 mTreeView = view;
53 mTree = nsCoreUtils::GetTreeBoxObject(aContent);
54 NS_ASSERTION(mTree, "Can't get mTree!\n");
56 nsIContent* parentContent = mContent->GetParent();
57 if (parentContent) {
58 nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
59 do_QueryInterface(parentContent);
60 if (autoCompletePopupElm)
61 mGenericTypes |= eAutoCompletePopup;
62 }
63 }
65 ////////////////////////////////////////////////////////////////////////////////
66 // XULTreeAccessible: nsISupports and cycle collection implementation
68 NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeAccessible, Accessible,
69 mTree, mAccessibleCache)
71 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(XULTreeAccessible)
72 NS_INTERFACE_MAP_END_INHERITING(Accessible)
74 NS_IMPL_ADDREF_INHERITED(XULTreeAccessible, Accessible)
75 NS_IMPL_RELEASE_INHERITED(XULTreeAccessible, Accessible)
77 ////////////////////////////////////////////////////////////////////////////////
78 // XULTreeAccessible: Accessible implementation
80 uint64_t
81 XULTreeAccessible::NativeState()
82 {
83 // Get focus status from base class.
84 uint64_t state = Accessible::NativeState();
86 // readonly state
87 state |= states::READONLY;
89 // multiselectable state.
90 if (!mTreeView)
91 return state;
93 nsCOMPtr<nsITreeSelection> selection;
94 mTreeView->GetSelection(getter_AddRefs(selection));
95 NS_ENSURE_TRUE(selection, state);
97 bool isSingle = false;
98 nsresult rv = selection->GetSingle(&isSingle);
99 NS_ENSURE_SUCCESS(rv, state);
101 if (!isSingle)
102 state |= states::MULTISELECTABLE;
104 return state;
105 }
107 void
108 XULTreeAccessible::Value(nsString& aValue)
109 {
110 aValue.Truncate();
111 if (!mTreeView)
112 return;
114 // Return the value is the first selected child.
115 nsCOMPtr<nsITreeSelection> selection;
116 mTreeView->GetSelection(getter_AddRefs(selection));
117 if (!selection)
118 return;
120 int32_t currentIndex;
121 nsCOMPtr<nsIDOMElement> selectItem;
122 selection->GetCurrentIndex(¤tIndex);
123 if (currentIndex >= 0) {
124 nsCOMPtr<nsITreeColumn> keyCol;
126 nsCOMPtr<nsITreeColumns> cols;
127 mTree->GetColumns(getter_AddRefs(cols));
128 if (cols)
129 cols->GetKeyColumn(getter_AddRefs(keyCol));
131 mTreeView->GetCellText(currentIndex, keyCol, aValue);
132 }
134 }
136 ////////////////////////////////////////////////////////////////////////////////
137 // XULTreeAccessible: Accessible implementation
139 void
140 XULTreeAccessible::Shutdown()
141 {
142 // XXX: we don't remove accessible from document cache if shutdown wasn't
143 // initiated by document destroying. Note, we can't remove accessible from
144 // document cache here while document is going to be shutdown. Note, this is
145 // not unique place where we have similar problem.
146 ClearCache(mAccessibleCache);
148 mTree = nullptr;
149 mTreeView = nullptr;
151 AccessibleWrap::Shutdown();
152 }
154 role
155 XULTreeAccessible::NativeRole()
156 {
157 // No primary column means we're in a list. In fact, history and mail turn off
158 // the primary flag when switching to a flat view.
160 nsIContent* child = nsTreeUtils::GetDescendantChild(mContent, nsGkAtoms::treechildren);
161 NS_ASSERTION(child, "tree without treechildren!");
162 nsTreeBodyFrame* treeFrame = do_QueryFrame(child->GetPrimaryFrame());
163 NS_ASSERTION(treeFrame, "xul tree accessible for tree without a frame!");
164 if (!treeFrame)
165 return roles::LIST;
167 nsRefPtr<nsTreeColumns> cols = treeFrame->Columns();
168 nsCOMPtr<nsITreeColumn> primaryCol;
169 cols->GetPrimaryColumn(getter_AddRefs(primaryCol));
171 return primaryCol ? roles::OUTLINE : roles::LIST;
172 }
174 ////////////////////////////////////////////////////////////////////////////////
175 // XULTreeAccessible: Accessible implementation (DON'T put methods here)
177 Accessible*
178 XULTreeAccessible::ChildAtPoint(int32_t aX, int32_t aY,
179 EWhichChildAtPoint aWhichChild)
180 {
181 nsIFrame *frame = GetFrame();
182 if (!frame)
183 return nullptr;
185 nsPresContext *presContext = frame->PresContext();
186 nsIPresShell* presShell = presContext->PresShell();
188 nsIFrame *rootFrame = presShell->GetRootFrame();
189 NS_ENSURE_TRUE(rootFrame, nullptr);
191 nsIntRect rootRect = rootFrame->GetScreenRect();
193 int32_t clientX = presContext->DevPixelsToIntCSSPixels(aX) - rootRect.x;
194 int32_t clientY = presContext->DevPixelsToIntCSSPixels(aY) - rootRect.y;
196 int32_t row = -1;
197 nsCOMPtr<nsITreeColumn> column;
198 nsAutoCString childEltUnused;
199 mTree->GetCellAt(clientX, clientY, &row, getter_AddRefs(column),
200 childEltUnused);
202 // If we failed to find tree cell for the given point then it might be
203 // tree columns.
204 if (row == -1 || !column)
205 return AccessibleWrap::ChildAtPoint(aX, aY, aWhichChild);
207 Accessible* child = GetTreeItemAccessible(row);
208 if (aWhichChild == eDeepestChild && child) {
209 // Look for accessible cell for the found item accessible.
210 nsRefPtr<XULTreeItemAccessibleBase> treeitem = do_QueryObject(child);
212 Accessible* cell = treeitem->GetCellAccessible(column);
213 if (cell)
214 child = cell;
215 }
217 return child;
218 }
220 ////////////////////////////////////////////////////////////////////////////////
221 // XULTreeAccessible: SelectAccessible
223 Accessible*
224 XULTreeAccessible::CurrentItem()
225 {
226 if (!mTreeView)
227 return nullptr;
229 nsCOMPtr<nsITreeSelection> selection;
230 mTreeView->GetSelection(getter_AddRefs(selection));
231 if (selection) {
232 int32_t currentIndex = -1;
233 selection->GetCurrentIndex(¤tIndex);
234 if (currentIndex >= 0)
235 return GetTreeItemAccessible(currentIndex);
236 }
238 return nullptr;
239 }
241 void
242 XULTreeAccessible::SetCurrentItem(Accessible* aItem)
243 {
244 NS_ERROR("XULTreeAccessible::SetCurrentItem not implemented");
245 }
247 already_AddRefed<nsIArray>
248 XULTreeAccessible::SelectedItems()
249 {
250 if (!mTreeView)
251 return nullptr;
253 nsCOMPtr<nsITreeSelection> selection;
254 mTreeView->GetSelection(getter_AddRefs(selection));
255 if (!selection)
256 return nullptr;
258 nsCOMPtr<nsIMutableArray> selectedItems =
259 do_CreateInstance(NS_ARRAY_CONTRACTID);
260 if (!selectedItems)
261 return nullptr;
263 int32_t rangeCount = 0;
264 selection->GetRangeCount(&rangeCount);
265 for (int32_t rangeIdx = 0; rangeIdx < rangeCount; rangeIdx++) {
266 int32_t firstIdx = 0, lastIdx = -1;
267 selection->GetRangeAt(rangeIdx, &firstIdx, &lastIdx);
268 for (int32_t rowIdx = firstIdx; rowIdx <= lastIdx; rowIdx++) {
269 nsIAccessible* item = GetTreeItemAccessible(rowIdx);
270 if (item)
271 selectedItems->AppendElement(item, false);
272 }
273 }
275 return selectedItems.forget();
276 }
278 uint32_t
279 XULTreeAccessible::SelectedItemCount()
280 {
281 if (!mTreeView)
282 return 0;
284 nsCOMPtr<nsITreeSelection> selection;
285 mTreeView->GetSelection(getter_AddRefs(selection));
286 if (selection) {
287 int32_t count = 0;
288 selection->GetCount(&count);
289 return count;
290 }
292 return 0;
293 }
295 bool
296 XULTreeAccessible::AddItemToSelection(uint32_t aIndex)
297 {
298 if (!mTreeView)
299 return false;
301 nsCOMPtr<nsITreeSelection> selection;
302 mTreeView->GetSelection(getter_AddRefs(selection));
303 if (selection) {
304 bool isSelected = false;
305 selection->IsSelected(aIndex, &isSelected);
306 if (!isSelected)
307 selection->ToggleSelect(aIndex);
309 return true;
310 }
311 return false;
312 }
314 bool
315 XULTreeAccessible::RemoveItemFromSelection(uint32_t aIndex)
316 {
317 if (!mTreeView)
318 return false;
320 nsCOMPtr<nsITreeSelection> selection;
321 mTreeView->GetSelection(getter_AddRefs(selection));
322 if (selection) {
323 bool isSelected = false;
324 selection->IsSelected(aIndex, &isSelected);
325 if (isSelected)
326 selection->ToggleSelect(aIndex);
328 return true;
329 }
330 return false;
331 }
333 bool
334 XULTreeAccessible::IsItemSelected(uint32_t aIndex)
335 {
336 if (!mTreeView)
337 return false;
339 nsCOMPtr<nsITreeSelection> selection;
340 mTreeView->GetSelection(getter_AddRefs(selection));
341 if (selection) {
342 bool isSelected = false;
343 selection->IsSelected(aIndex, &isSelected);
344 return isSelected;
345 }
346 return false;
347 }
349 bool
350 XULTreeAccessible::UnselectAll()
351 {
352 if (!mTreeView)
353 return false;
355 nsCOMPtr<nsITreeSelection> selection;
356 mTreeView->GetSelection(getter_AddRefs(selection));
357 if (!selection)
358 return false;
360 selection->ClearSelection();
361 return true;
362 }
364 Accessible*
365 XULTreeAccessible::GetSelectedItem(uint32_t aIndex)
366 {
367 if (!mTreeView)
368 return nullptr;
370 nsCOMPtr<nsITreeSelection> selection;
371 mTreeView->GetSelection(getter_AddRefs(selection));
372 if (!selection)
373 return nullptr;
375 uint32_t selCount = 0;
376 int32_t rangeCount = 0;
377 selection->GetRangeCount(&rangeCount);
378 for (int32_t rangeIdx = 0; rangeIdx < rangeCount; rangeIdx++) {
379 int32_t firstIdx = 0, lastIdx = -1;
380 selection->GetRangeAt(rangeIdx, &firstIdx, &lastIdx);
381 for (int32_t rowIdx = firstIdx; rowIdx <= lastIdx; rowIdx++) {
382 if (selCount == aIndex)
383 return GetTreeItemAccessible(rowIdx);
385 selCount++;
386 }
387 }
389 return nullptr;
390 }
392 bool
393 XULTreeAccessible::SelectAll()
394 {
395 // see if we are multiple select if so set ourselves as such
396 if (!mTreeView)
397 return false;
399 nsCOMPtr<nsITreeSelection> selection;
400 mTreeView->GetSelection(getter_AddRefs(selection));
401 if (selection) {
402 bool single = false;
403 selection->GetSingle(&single);
404 if (!single) {
405 selection->SelectAll();
406 return true;
407 }
408 }
410 return false;
411 }
413 ////////////////////////////////////////////////////////////////////////////////
414 // XULTreeAccessible: Accessible implementation
416 Accessible*
417 XULTreeAccessible::GetChildAt(uint32_t aIndex) const
418 {
419 uint32_t childCount = Accessible::ChildCount();
420 if (aIndex < childCount)
421 return Accessible::GetChildAt(aIndex);
423 return GetTreeItemAccessible(aIndex - childCount);
424 }
426 uint32_t
427 XULTreeAccessible::ChildCount() const
428 {
429 // Tree's children count is row count + treecols count.
430 uint32_t childCount = Accessible::ChildCount();
431 if (!mTreeView)
432 return childCount;
434 int32_t rowCount = 0;
435 mTreeView->GetRowCount(&rowCount);
436 childCount += rowCount;
438 return childCount;
439 }
441 Relation
442 XULTreeAccessible::RelationByType(RelationType aType)
443 {
444 if (aType == RelationType::NODE_PARENT_OF) {
445 if (mTreeView)
446 return Relation(new XULTreeItemIterator(this, mTreeView, -1));
448 return Relation();
449 }
451 return Accessible::RelationByType(aType);
452 }
454 ////////////////////////////////////////////////////////////////////////////////
455 // XULTreeAccessible: Widgets
457 bool
458 XULTreeAccessible::IsWidget() const
459 {
460 return true;
461 }
463 bool
464 XULTreeAccessible::IsActiveWidget() const
465 {
466 if (IsAutoCompletePopup()) {
467 nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
468 do_QueryInterface(mContent->GetParent());
470 if (autoCompletePopupElm) {
471 bool isOpen = false;
472 autoCompletePopupElm->GetPopupOpen(&isOpen);
473 return isOpen;
474 }
475 }
476 return FocusMgr()->HasDOMFocus(mContent);
477 }
479 bool
480 XULTreeAccessible::AreItemsOperable() const
481 {
482 if (IsAutoCompletePopup()) {
483 nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
484 do_QueryInterface(mContent->GetParent());
486 if (autoCompletePopupElm) {
487 bool isOpen = false;
488 autoCompletePopupElm->GetPopupOpen(&isOpen);
489 return isOpen;
490 }
491 }
492 return true;
493 }
495 Accessible*
496 XULTreeAccessible::ContainerWidget() const
497 {
498 if (IsAutoCompletePopup()) {
499 // This works for XUL autocompletes. It doesn't work for HTML forms
500 // autocomplete because of potential crossprocess calls (when autocomplete
501 // lives in content process while popup lives in chrome process). If that's
502 // a problem then rethink Widgets interface.
503 nsCOMPtr<nsIDOMXULMenuListElement> menuListElm =
504 do_QueryInterface(mContent->GetParent());
505 if (menuListElm) {
506 nsCOMPtr<nsIDOMNode> inputElm;
507 menuListElm->GetInputField(getter_AddRefs(inputElm));
508 if (inputElm) {
509 nsCOMPtr<nsINode> inputNode = do_QueryInterface(inputElm);
510 if (inputNode) {
511 Accessible* input =
512 mDoc->GetAccessible(inputNode);
513 return input ? input->ContainerWidget() : nullptr;
514 }
515 }
516 }
517 }
518 return nullptr;
519 }
521 ////////////////////////////////////////////////////////////////////////////////
522 // XULTreeAccessible: public implementation
524 Accessible*
525 XULTreeAccessible::GetTreeItemAccessible(int32_t aRow) const
526 {
527 if (aRow < 0 || IsDefunct() || !mTreeView)
528 return nullptr;
530 int32_t rowCount = 0;
531 nsresult rv = mTreeView->GetRowCount(&rowCount);
532 if (NS_FAILED(rv) || aRow >= rowCount)
533 return nullptr;
535 void *key = reinterpret_cast<void*>(aRow);
536 Accessible* cachedTreeItem = mAccessibleCache.GetWeak(key);
537 if (cachedTreeItem)
538 return cachedTreeItem;
540 nsRefPtr<Accessible> treeItem = CreateTreeItemAccessible(aRow);
541 if (treeItem) {
542 mAccessibleCache.Put(key, treeItem);
543 Document()->BindToDocument(treeItem, nullptr);
544 return treeItem;
545 }
547 return nullptr;
548 }
550 void
551 XULTreeAccessible::InvalidateCache(int32_t aRow, int32_t aCount)
552 {
553 if (IsDefunct())
554 return;
556 if (!mTreeView) {
557 ClearCache(mAccessibleCache);
558 return;
559 }
561 // Do not invalidate the cache if rows have been inserted.
562 if (aCount > 0)
563 return;
565 DocAccessible* document = Document();
567 // Fire destroy event for removed tree items and delete them from caches.
568 for (int32_t rowIdx = aRow; rowIdx < aRow - aCount; rowIdx++) {
570 void* key = reinterpret_cast<void*>(rowIdx);
571 Accessible* treeItem = mAccessibleCache.GetWeak(key);
573 if (treeItem) {
574 nsRefPtr<AccEvent> event =
575 new AccEvent(nsIAccessibleEvent::EVENT_HIDE, treeItem);
576 nsEventShell::FireEvent(event);
578 // Unbind from document, shutdown and remove from tree cache.
579 document->UnbindFromDocument(treeItem);
580 mAccessibleCache.Remove(key);
581 }
582 }
584 // We dealt with removed tree items already however we may keep tree items
585 // having row indexes greater than row count. We should remove these dead tree
586 // items silently from caches.
587 int32_t newRowCount = 0;
588 nsresult rv = mTreeView->GetRowCount(&newRowCount);
589 if (NS_FAILED(rv))
590 return;
592 int32_t oldRowCount = newRowCount - aCount;
594 for (int32_t rowIdx = newRowCount; rowIdx < oldRowCount; ++rowIdx) {
596 void *key = reinterpret_cast<void*>(rowIdx);
597 Accessible* treeItem = mAccessibleCache.GetWeak(key);
599 if (treeItem) {
600 // Unbind from document, shutdown and remove from tree cache.
601 document->UnbindFromDocument(treeItem);
602 mAccessibleCache.Remove(key);
603 }
604 }
605 }
607 void
608 XULTreeAccessible::TreeViewInvalidated(int32_t aStartRow, int32_t aEndRow,
609 int32_t aStartCol, int32_t aEndCol)
610 {
611 if (IsDefunct())
612 return;
614 if (!mTreeView) {
615 ClearCache(mAccessibleCache);
616 return;
617 }
619 int32_t endRow = aEndRow;
621 nsresult rv;
622 if (endRow == -1) {
623 int32_t rowCount = 0;
624 rv = mTreeView->GetRowCount(&rowCount);
625 if (NS_FAILED(rv))
626 return;
628 endRow = rowCount - 1;
629 }
631 nsCOMPtr<nsITreeColumns> treeColumns;
632 mTree->GetColumns(getter_AddRefs(treeColumns));
633 if (!treeColumns)
634 return;
636 int32_t endCol = aEndCol;
638 if (endCol == -1) {
639 int32_t colCount = 0;
640 rv = treeColumns->GetCount(&colCount);
641 if (NS_FAILED(rv))
642 return;
644 endCol = colCount - 1;
645 }
647 for (int32_t rowIdx = aStartRow; rowIdx <= endRow; ++rowIdx) {
649 void *key = reinterpret_cast<void*>(rowIdx);
650 Accessible* accessible = mAccessibleCache.GetWeak(key);
652 if (accessible) {
653 nsRefPtr<XULTreeItemAccessibleBase> treeitemAcc = do_QueryObject(accessible);
654 NS_ASSERTION(treeitemAcc, "Wrong accessible at the given key!");
656 treeitemAcc->RowInvalidated(aStartCol, endCol);
657 }
658 }
659 }
661 void
662 XULTreeAccessible::TreeViewChanged(nsITreeView* aView)
663 {
664 if (IsDefunct())
665 return;
667 // Fire reorder event on tree accessible on accessible tree (do not fire
668 // show/hide events on tree items because it can be expensive to fire them for
669 // each tree item.
670 nsRefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(this);
671 Document()->FireDelayedEvent(reorderEvent);
673 // Clear cache.
674 ClearCache(mAccessibleCache);
675 mTreeView = aView;
676 }
678 ////////////////////////////////////////////////////////////////////////////////
679 // XULTreeAccessible: protected implementation
681 already_AddRefed<Accessible>
682 XULTreeAccessible::CreateTreeItemAccessible(int32_t aRow) const
683 {
684 nsRefPtr<Accessible> accessible =
685 new XULTreeItemAccessible(mContent, mDoc, const_cast<XULTreeAccessible*>(this),
686 mTree, mTreeView, aRow);
688 return accessible.forget();
689 }
691 ////////////////////////////////////////////////////////////////////////////////
692 // XULTreeItemAccessibleBase
693 ////////////////////////////////////////////////////////////////////////////////
695 XULTreeItemAccessibleBase::
696 XULTreeItemAccessibleBase(nsIContent* aContent, DocAccessible* aDoc,
697 Accessible* aParent, nsITreeBoxObject* aTree,
698 nsITreeView* aTreeView, int32_t aRow) :
699 AccessibleWrap(aContent, aDoc),
700 mTree(aTree), mTreeView(aTreeView), mRow(aRow)
701 {
702 mParent = aParent;
703 mStateFlags |= eSharedNode;
704 }
706 ////////////////////////////////////////////////////////////////////////////////
707 // XULTreeItemAccessibleBase: nsISupports implementation
709 NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeItemAccessibleBase, Accessible,
710 mTree)
712 NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(XULTreeItemAccessibleBase)
713 NS_INTERFACE_TABLE_INHERITED(XULTreeItemAccessibleBase,
714 XULTreeItemAccessibleBase)
715 NS_INTERFACE_TABLE_TAIL_INHERITING(Accessible)
716 NS_IMPL_ADDREF_INHERITED(XULTreeItemAccessibleBase, Accessible)
717 NS_IMPL_RELEASE_INHERITED(XULTreeItemAccessibleBase, Accessible)
719 ////////////////////////////////////////////////////////////////////////////////
720 // XULTreeItemAccessibleBase: nsIAccessible implementation
722 Accessible*
723 XULTreeItemAccessibleBase::FocusedChild()
724 {
725 return FocusMgr()->FocusedAccessible() == this ? this : nullptr;
726 }
728 NS_IMETHODIMP
729 XULTreeItemAccessibleBase::GetBounds(int32_t* aX, int32_t* aY,
730 int32_t* aWidth, int32_t* aHeight)
731 {
732 NS_ENSURE_ARG_POINTER(aX);
733 *aX = 0;
734 NS_ENSURE_ARG_POINTER(aY);
735 *aY = 0;
736 NS_ENSURE_ARG_POINTER(aWidth);
737 *aWidth = 0;
738 NS_ENSURE_ARG_POINTER(aHeight);
739 *aHeight = 0;
741 if (IsDefunct())
742 return NS_ERROR_FAILURE;
744 // Get x coordinate and width from treechildren element, get y coordinate and
745 // height from tree cell.
747 nsCOMPtr<nsIBoxObject> boxObj = nsCoreUtils::GetTreeBodyBoxObject(mTree);
748 NS_ENSURE_STATE(boxObj);
750 nsCOMPtr<nsITreeColumn> column = nsCoreUtils::GetFirstSensibleColumn(mTree);
752 int32_t x = 0, y = 0, width = 0, height = 0;
753 nsresult rv = mTree->GetCoordsForCellItem(mRow, column, EmptyCString(),
754 &x, &y, &width, &height);
755 NS_ENSURE_SUCCESS(rv, rv);
757 boxObj->GetWidth(&width);
759 int32_t tcX = 0, tcY = 0;
760 boxObj->GetScreenX(&tcX);
761 boxObj->GetScreenY(&tcY);
763 x = tcX;
764 y += tcY;
766 nsPresContext* presContext = mDoc->PresContext();
767 *aX = presContext->CSSPixelsToDevPixels(x);
768 *aY = presContext->CSSPixelsToDevPixels(y);
769 *aWidth = presContext->CSSPixelsToDevPixels(width);
770 *aHeight = presContext->CSSPixelsToDevPixels(height);
772 return NS_OK;
773 }
775 NS_IMETHODIMP
776 XULTreeItemAccessibleBase::SetSelected(bool aSelect)
777 {
778 if (IsDefunct())
779 return NS_ERROR_FAILURE;
781 nsCOMPtr<nsITreeSelection> selection;
782 mTreeView->GetSelection(getter_AddRefs(selection));
783 if (selection) {
784 bool isSelected;
785 selection->IsSelected(mRow, &isSelected);
786 if (isSelected != aSelect)
787 selection->ToggleSelect(mRow);
788 }
790 return NS_OK;
791 }
793 NS_IMETHODIMP
794 XULTreeItemAccessibleBase::TakeFocus()
795 {
796 if (IsDefunct())
797 return NS_ERROR_FAILURE;
799 nsCOMPtr<nsITreeSelection> selection;
800 mTreeView->GetSelection(getter_AddRefs(selection));
801 if (selection)
802 selection->SetCurrentIndex(mRow);
804 // focus event will be fired here
805 return Accessible::TakeFocus();
806 }
808 Relation
809 XULTreeItemAccessibleBase::RelationByType(RelationType aType)
810 {
812 switch (aType) {
813 case RelationType::NODE_CHILD_OF: {
814 int32_t parentIndex = -1;
815 if (!NS_SUCCEEDED(mTreeView->GetParentIndex(mRow, &parentIndex)))
816 return Relation();
818 if (parentIndex == -1)
819 return Relation(mParent);
821 XULTreeAccessible* treeAcc = mParent->AsXULTree();
822 return Relation(treeAcc->GetTreeItemAccessible(parentIndex));
823 }
825 case RelationType::NODE_PARENT_OF: {
826 bool isTrue = false;
827 if (NS_FAILED(mTreeView->IsContainerEmpty(mRow, &isTrue)) || isTrue)
828 return Relation();
830 if (NS_FAILED(mTreeView->IsContainerOpen(mRow, &isTrue)) || !isTrue)
831 return Relation();
833 XULTreeAccessible* tree = mParent->AsXULTree();
834 return Relation(new XULTreeItemIterator(tree, mTreeView, mRow));
835 }
837 default:
838 return Relation();
839 }
840 }
842 uint8_t
843 XULTreeItemAccessibleBase::ActionCount()
844 {
845 // "activate" action is available for all treeitems, "expand/collapse" action
846 // is avaible for treeitem which is container.
847 return IsExpandable() ? 2 : 1;
848 }
850 NS_IMETHODIMP
851 XULTreeItemAccessibleBase::GetActionName(uint8_t aIndex, nsAString& aName)
852 {
853 if (IsDefunct())
854 return NS_ERROR_FAILURE;
856 if (aIndex == eAction_Click) {
857 aName.AssignLiteral("activate");
858 return NS_OK;
859 }
861 if (aIndex == eAction_Expand && IsExpandable()) {
862 bool isContainerOpen;
863 mTreeView->IsContainerOpen(mRow, &isContainerOpen);
864 if (isContainerOpen)
865 aName.AssignLiteral("collapse");
866 else
867 aName.AssignLiteral("expand");
869 return NS_OK;
870 }
872 return NS_ERROR_INVALID_ARG;
873 }
875 NS_IMETHODIMP
876 XULTreeItemAccessibleBase::DoAction(uint8_t aIndex)
877 {
878 if (IsDefunct())
879 return NS_ERROR_FAILURE;
881 if (aIndex != eAction_Click &&
882 (aIndex != eAction_Expand || !IsExpandable()))
883 return NS_ERROR_INVALID_ARG;
885 DoCommand(nullptr, aIndex);
886 return NS_OK;
887 }
889 ////////////////////////////////////////////////////////////////////////////////
890 // XULTreeItemAccessibleBase: Accessible implementation
892 void
893 XULTreeItemAccessibleBase::Shutdown()
894 {
895 mTree = nullptr;
896 mTreeView = nullptr;
897 mRow = -1;
899 AccessibleWrap::Shutdown();
900 }
902 GroupPos
903 XULTreeItemAccessibleBase::GroupPosition()
904 {
905 GroupPos groupPos;
907 int32_t level;
908 nsresult rv = mTreeView->GetLevel(mRow, &level);
909 NS_ENSURE_SUCCESS(rv, groupPos);
911 int32_t topCount = 1;
912 for (int32_t index = mRow - 1; index >= 0; index--) {
913 int32_t lvl = -1;
914 if (NS_SUCCEEDED(mTreeView->GetLevel(index, &lvl))) {
915 if (lvl < level)
916 break;
918 if (lvl == level)
919 topCount++;
920 }
921 }
923 int32_t rowCount = 0;
924 rv = mTreeView->GetRowCount(&rowCount);
925 NS_ENSURE_SUCCESS(rv, groupPos);
927 int32_t bottomCount = 0;
928 for (int32_t index = mRow + 1; index < rowCount; index++) {
929 int32_t lvl = -1;
930 if (NS_SUCCEEDED(mTreeView->GetLevel(index, &lvl))) {
931 if (lvl < level)
932 break;
934 if (lvl == level)
935 bottomCount++;
936 }
937 }
939 groupPos.level = level + 1;
940 groupPos.setSize = topCount + bottomCount;
941 groupPos.posInSet = topCount;
943 return groupPos;
944 }
946 uint64_t
947 XULTreeItemAccessibleBase::NativeState()
948 {
950 // focusable and selectable states
951 uint64_t state = NativeInteractiveState();
953 // expanded/collapsed state
954 if (IsExpandable()) {
955 bool isContainerOpen;
956 mTreeView->IsContainerOpen(mRow, &isContainerOpen);
957 state |= isContainerOpen ? states::EXPANDED : states::COLLAPSED;
958 }
960 // selected state
961 nsCOMPtr<nsITreeSelection> selection;
962 mTreeView->GetSelection(getter_AddRefs(selection));
963 if (selection) {
964 bool isSelected;
965 selection->IsSelected(mRow, &isSelected);
966 if (isSelected)
967 state |= states::SELECTED;
968 }
970 // focused state
971 if (FocusMgr()->IsFocused(this))
972 state |= states::FOCUSED;
974 // invisible state
975 int32_t firstVisibleRow, lastVisibleRow;
976 mTree->GetFirstVisibleRow(&firstVisibleRow);
977 mTree->GetLastVisibleRow(&lastVisibleRow);
978 if (mRow < firstVisibleRow || mRow > lastVisibleRow)
979 state |= states::INVISIBLE;
981 return state;
982 }
984 uint64_t
985 XULTreeItemAccessibleBase::NativeInteractiveState() const
986 {
987 return states::FOCUSABLE | states::SELECTABLE;
988 }
990 int32_t
991 XULTreeItemAccessibleBase::IndexInParent() const
992 {
993 return mParent ? mParent->ContentChildCount() + mRow : -1;
994 }
996 ////////////////////////////////////////////////////////////////////////////////
997 // XULTreeItemAccessibleBase: Widgets
999 Accessible*
1000 XULTreeItemAccessibleBase::ContainerWidget() const
1001 {
1002 return mParent;
1003 }
1005 ////////////////////////////////////////////////////////////////////////////////
1006 // XULTreeItemAccessibleBase: Accessible protected methods
1008 void
1009 XULTreeItemAccessibleBase::DispatchClickEvent(nsIContent* aContent,
1010 uint32_t aActionIndex)
1011 {
1012 if (IsDefunct())
1013 return;
1015 nsCOMPtr<nsITreeColumns> columns;
1016 mTree->GetColumns(getter_AddRefs(columns));
1017 if (!columns)
1018 return;
1020 // Get column and pseudo element.
1021 nsCOMPtr<nsITreeColumn> column;
1022 nsAutoCString pseudoElm;
1024 if (aActionIndex == eAction_Click) {
1025 // Key column is visible and clickable.
1026 columns->GetKeyColumn(getter_AddRefs(column));
1027 } else {
1028 // Primary column contains a twisty we should click on.
1029 columns->GetPrimaryColumn(getter_AddRefs(column));
1030 pseudoElm = NS_LITERAL_CSTRING("twisty");
1031 }
1033 if (column)
1034 nsCoreUtils::DispatchClickEvent(mTree, mRow, column, pseudoElm);
1035 }
1037 Accessible*
1038 XULTreeItemAccessibleBase::GetSiblingAtOffset(int32_t aOffset,
1039 nsresult* aError) const
1040 {
1041 if (aError)
1042 *aError = NS_OK; // fail peacefully
1044 return mParent->GetChildAt(IndexInParent() + aOffset);
1045 }
1047 ////////////////////////////////////////////////////////////////////////////////
1048 // XULTreeItemAccessibleBase: protected implementation
1050 bool
1051 XULTreeItemAccessibleBase::IsExpandable()
1052 {
1054 bool isContainer = false;
1055 mTreeView->IsContainer(mRow, &isContainer);
1056 if (isContainer) {
1057 bool isEmpty = false;
1058 mTreeView->IsContainerEmpty(mRow, &isEmpty);
1059 if (!isEmpty) {
1060 nsCOMPtr<nsITreeColumns> columns;
1061 mTree->GetColumns(getter_AddRefs(columns));
1062 nsCOMPtr<nsITreeColumn> primaryColumn;
1063 if (columns) {
1064 columns->GetPrimaryColumn(getter_AddRefs(primaryColumn));
1065 if (primaryColumn &&
1066 !nsCoreUtils::IsColumnHidden(primaryColumn))
1067 return true;
1068 }
1069 }
1070 }
1072 return false;
1073 }
1075 void
1076 XULTreeItemAccessibleBase::GetCellName(nsITreeColumn* aColumn, nsAString& aName)
1077 {
1079 mTreeView->GetCellText(mRow, aColumn, aName);
1081 // If there is still no name try the cell value:
1082 // This is for graphical cells. We need tree/table view implementors to
1083 // implement FooView::GetCellValue to return a meaningful string for cases
1084 // where there is something shown in the cell (non-text) such as a star icon;
1085 // in which case GetCellValue for that cell would return "starred" or
1086 // "flagged" for example.
1087 if (aName.IsEmpty())
1088 mTreeView->GetCellValue(mRow, aColumn, aName);
1089 }
1092 ////////////////////////////////////////////////////////////////////////////////
1093 // XULTreeItemAccessible
1094 ////////////////////////////////////////////////////////////////////////////////
1096 XULTreeItemAccessible::
1097 XULTreeItemAccessible(nsIContent* aContent, DocAccessible* aDoc,
1098 Accessible* aParent, nsITreeBoxObject* aTree,
1099 nsITreeView* aTreeView, int32_t aRow) :
1100 XULTreeItemAccessibleBase(aContent, aDoc, aParent, aTree, aTreeView, aRow)
1101 {
1102 mColumn = nsCoreUtils::GetFirstSensibleColumn(mTree);
1103 GetCellName(mColumn, mCachedName);
1104 }
1106 ////////////////////////////////////////////////////////////////////////////////
1107 // XULTreeItemAccessible: nsISupports implementation
1109 NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeItemAccessible,
1110 XULTreeItemAccessibleBase,
1111 mColumn)
1113 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(XULTreeItemAccessible)
1114 NS_INTERFACE_MAP_END_INHERITING(XULTreeItemAccessibleBase)
1115 NS_IMPL_ADDREF_INHERITED(XULTreeItemAccessible, XULTreeItemAccessibleBase)
1116 NS_IMPL_RELEASE_INHERITED(XULTreeItemAccessible, XULTreeItemAccessibleBase)
1118 ////////////////////////////////////////////////////////////////////////////////
1119 // XULTreeItemAccessible: nsIAccessible implementation
1121 ENameValueFlag
1122 XULTreeItemAccessible::Name(nsString& aName)
1123 {
1124 aName.Truncate();
1126 GetCellName(mColumn, aName);
1127 return eNameOK;
1128 }
1130 ////////////////////////////////////////////////////////////////////////////////
1131 // XULTreeItemAccessible: Accessible implementation
1133 void
1134 XULTreeItemAccessible::Shutdown()
1135 {
1136 mColumn = nullptr;
1137 XULTreeItemAccessibleBase::Shutdown();
1138 }
1140 role
1141 XULTreeItemAccessible::NativeRole()
1142 {
1143 nsCOMPtr<nsITreeColumns> columns;
1144 mTree->GetColumns(getter_AddRefs(columns));
1145 if (!columns) {
1146 NS_ERROR("No tree columns object in the tree!");
1147 return roles::NOTHING;
1148 }
1150 nsCOMPtr<nsITreeColumn> primaryColumn;
1151 columns->GetPrimaryColumn(getter_AddRefs(primaryColumn));
1153 return primaryColumn ? roles::OUTLINEITEM : roles::LISTITEM;
1154 }
1156 ////////////////////////////////////////////////////////////////////////////////
1157 // XULTreeItemAccessible: XULTreeItemAccessibleBase implementation
1159 void
1160 XULTreeItemAccessible::RowInvalidated(int32_t aStartColIdx, int32_t aEndColIdx)
1161 {
1162 nsAutoString name;
1163 Name(name);
1165 if (name != mCachedName) {
1166 nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this);
1167 mCachedName = name;
1168 }
1169 }
1171 ////////////////////////////////////////////////////////////////////////////////
1172 // XULTreeItemAccessible: Accessible protected implementation
1174 void
1175 XULTreeItemAccessible::CacheChildren()
1176 {
1177 }
1180 ////////////////////////////////////////////////////////////////////////////////
1181 // XULTreeColumAccessible
1182 ////////////////////////////////////////////////////////////////////////////////
1184 XULTreeColumAccessible::
1185 XULTreeColumAccessible(nsIContent* aContent, DocAccessible* aDoc) :
1186 XULColumAccessible(aContent, aDoc)
1187 {
1188 }
1190 Accessible*
1191 XULTreeColumAccessible::GetSiblingAtOffset(int32_t aOffset,
1192 nsresult* aError) const
1193 {
1194 if (aOffset < 0)
1195 return XULColumAccessible::GetSiblingAtOffset(aOffset, aError);
1197 if (aError)
1198 *aError = NS_OK; // fail peacefully
1200 nsCOMPtr<nsITreeBoxObject> tree = nsCoreUtils::GetTreeBoxObject(mContent);
1201 if (tree) {
1202 nsCOMPtr<nsITreeView> treeView;
1203 tree->GetView(getter_AddRefs(treeView));
1204 if (treeView) {
1205 int32_t rowCount = 0;
1206 treeView->GetRowCount(&rowCount);
1207 if (rowCount > 0 && aOffset <= rowCount) {
1208 XULTreeAccessible* treeAcc = Parent()->AsXULTree();
1210 if (treeAcc)
1211 return treeAcc->GetTreeItemAccessible(aOffset - 1);
1212 }
1213 }
1214 }
1216 return nullptr;
1217 }