accessible/src/xul/XULTreeAccessible.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/accessible/src/xul/XULTreeAccessible.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1218 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=2 et sw=2 tw=80: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "XULTreeAccessible.h"
    1.11 +
    1.12 +#include "Accessible-inl.h"
    1.13 +#include "DocAccessible-inl.h"
    1.14 +#include "nsAccCache.h"
    1.15 +#include "nsAccUtils.h"
    1.16 +#include "nsCoreUtils.h"
    1.17 +#include "nsEventShell.h"
    1.18 +#include "DocAccessible.h"
    1.19 +#include "Relation.h"
    1.20 +#include "Role.h"
    1.21 +#include "States.h"
    1.22 +
    1.23 +#include "nsComponentManagerUtils.h"
    1.24 +#include "nsIAccessibleRelation.h"
    1.25 +#include "nsIAutoCompleteInput.h"
    1.26 +#include "nsIAutoCompletePopup.h"
    1.27 +#include "nsIBoxObject.h"
    1.28 +#include "nsIDOMXULElement.h"
    1.29 +#include "nsIDOMXULMenuListElement.h"
    1.30 +#include "nsIDOMXULMultSelectCntrlEl.h"
    1.31 +#include "nsIDOMXULTreeElement.h"
    1.32 +#include "nsITreeSelection.h"
    1.33 +#include "nsIMutableArray.h"
    1.34 +#include "nsTreeBodyFrame.h"
    1.35 +#include "nsTreeColumns.h"
    1.36 +#include "nsTreeUtils.h"
    1.37 +
    1.38 +using namespace mozilla::a11y;
    1.39 +
    1.40 +////////////////////////////////////////////////////////////////////////////////
    1.41 +// XULTreeAccessible
    1.42 +////////////////////////////////////////////////////////////////////////////////
    1.43 +
    1.44 +XULTreeAccessible::
    1.45 +  XULTreeAccessible(nsIContent* aContent, DocAccessible* aDoc,
    1.46 +                    nsTreeBodyFrame* aTreeFrame) :
    1.47 +  AccessibleWrap(aContent, aDoc),
    1.48 +  mAccessibleCache(kDefaultTreeCacheSize)
    1.49 +{
    1.50 +  mType = eXULTreeType;
    1.51 +  mGenericTypes |= eSelect;
    1.52 +
    1.53 +  nsCOMPtr<nsITreeView> view = aTreeFrame->GetExistingView();
    1.54 +  mTreeView = view;
    1.55 +
    1.56 +  mTree = nsCoreUtils::GetTreeBoxObject(aContent);
    1.57 +  NS_ASSERTION(mTree, "Can't get mTree!\n");
    1.58 +
    1.59 +  nsIContent* parentContent = mContent->GetParent();
    1.60 +  if (parentContent) {
    1.61 +    nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
    1.62 +      do_QueryInterface(parentContent);
    1.63 +    if (autoCompletePopupElm)
    1.64 +      mGenericTypes |= eAutoCompletePopup;
    1.65 +  }
    1.66 +}
    1.67 +
    1.68 +////////////////////////////////////////////////////////////////////////////////
    1.69 +// XULTreeAccessible: nsISupports and cycle collection implementation
    1.70 +
    1.71 +NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeAccessible, Accessible,
    1.72 +                                   mTree, mAccessibleCache)
    1.73 +
    1.74 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(XULTreeAccessible)
    1.75 +NS_INTERFACE_MAP_END_INHERITING(Accessible)
    1.76 +
    1.77 +NS_IMPL_ADDREF_INHERITED(XULTreeAccessible, Accessible)
    1.78 +NS_IMPL_RELEASE_INHERITED(XULTreeAccessible, Accessible)
    1.79 +
    1.80 +////////////////////////////////////////////////////////////////////////////////
    1.81 +// XULTreeAccessible: Accessible implementation
    1.82 +
    1.83 +uint64_t
    1.84 +XULTreeAccessible::NativeState()
    1.85 +{
    1.86 +  // Get focus status from base class.
    1.87 +  uint64_t state = Accessible::NativeState();
    1.88 +
    1.89 +  // readonly state
    1.90 +  state |= states::READONLY;
    1.91 +
    1.92 +  // multiselectable state.
    1.93 +  if (!mTreeView)
    1.94 +    return state;
    1.95 +
    1.96 +  nsCOMPtr<nsITreeSelection> selection;
    1.97 +  mTreeView->GetSelection(getter_AddRefs(selection));
    1.98 +  NS_ENSURE_TRUE(selection, state);
    1.99 +
   1.100 +  bool isSingle = false;
   1.101 +  nsresult rv = selection->GetSingle(&isSingle);
   1.102 +  NS_ENSURE_SUCCESS(rv, state);
   1.103 +
   1.104 +  if (!isSingle)
   1.105 +    state |= states::MULTISELECTABLE;
   1.106 +
   1.107 +  return state;
   1.108 +}
   1.109 +
   1.110 +void
   1.111 +XULTreeAccessible::Value(nsString& aValue)
   1.112 +{
   1.113 +  aValue.Truncate();
   1.114 +  if (!mTreeView)
   1.115 +    return;
   1.116 +
   1.117 +  // Return the value is the first selected child.
   1.118 +  nsCOMPtr<nsITreeSelection> selection;
   1.119 +  mTreeView->GetSelection(getter_AddRefs(selection));
   1.120 +  if (!selection)
   1.121 +    return;
   1.122 +
   1.123 +  int32_t currentIndex;
   1.124 +  nsCOMPtr<nsIDOMElement> selectItem;
   1.125 +  selection->GetCurrentIndex(&currentIndex);
   1.126 +  if (currentIndex >= 0) {
   1.127 +    nsCOMPtr<nsITreeColumn> keyCol;
   1.128 +
   1.129 +    nsCOMPtr<nsITreeColumns> cols;
   1.130 +    mTree->GetColumns(getter_AddRefs(cols));
   1.131 +    if (cols)
   1.132 +      cols->GetKeyColumn(getter_AddRefs(keyCol));
   1.133 +
   1.134 +    mTreeView->GetCellText(currentIndex, keyCol, aValue);
   1.135 +  }
   1.136 +
   1.137 +}
   1.138 +
   1.139 +////////////////////////////////////////////////////////////////////////////////
   1.140 +// XULTreeAccessible: Accessible implementation
   1.141 +
   1.142 +void
   1.143 +XULTreeAccessible::Shutdown()
   1.144 +{
   1.145 +  // XXX: we don't remove accessible from document cache if shutdown wasn't
   1.146 +  // initiated by document destroying. Note, we can't remove accessible from
   1.147 +  // document cache here while document is going to be shutdown. Note, this is
   1.148 +  // not unique place where we have similar problem.
   1.149 +  ClearCache(mAccessibleCache);
   1.150 +
   1.151 +  mTree = nullptr;
   1.152 +  mTreeView = nullptr;
   1.153 +
   1.154 +  AccessibleWrap::Shutdown();
   1.155 +}
   1.156 +
   1.157 +role
   1.158 +XULTreeAccessible::NativeRole()
   1.159 +{
   1.160 +  // No primary column means we're in a list. In fact, history and mail turn off
   1.161 +  // the primary flag when switching to a flat view.
   1.162 +
   1.163 +  nsIContent* child = nsTreeUtils::GetDescendantChild(mContent, nsGkAtoms::treechildren);
   1.164 +  NS_ASSERTION(child, "tree without treechildren!");
   1.165 +  nsTreeBodyFrame* treeFrame = do_QueryFrame(child->GetPrimaryFrame());
   1.166 +  NS_ASSERTION(treeFrame, "xul tree accessible for tree without a frame!");
   1.167 +  if (!treeFrame)
   1.168 +    return roles::LIST;
   1.169 +
   1.170 +  nsRefPtr<nsTreeColumns> cols = treeFrame->Columns();
   1.171 +  nsCOMPtr<nsITreeColumn> primaryCol;
   1.172 +  cols->GetPrimaryColumn(getter_AddRefs(primaryCol));
   1.173 +
   1.174 +  return primaryCol ? roles::OUTLINE : roles::LIST;
   1.175 +}
   1.176 +
   1.177 +////////////////////////////////////////////////////////////////////////////////
   1.178 +// XULTreeAccessible: Accessible implementation (DON'T put methods here)
   1.179 +
   1.180 +Accessible*
   1.181 +XULTreeAccessible::ChildAtPoint(int32_t aX, int32_t aY,
   1.182 +                                EWhichChildAtPoint aWhichChild)
   1.183 +{
   1.184 +  nsIFrame *frame = GetFrame();
   1.185 +  if (!frame)
   1.186 +    return nullptr;
   1.187 +
   1.188 +  nsPresContext *presContext = frame->PresContext();
   1.189 +  nsIPresShell* presShell = presContext->PresShell();
   1.190 +
   1.191 +  nsIFrame *rootFrame = presShell->GetRootFrame();
   1.192 +  NS_ENSURE_TRUE(rootFrame, nullptr);
   1.193 +
   1.194 +  nsIntRect rootRect = rootFrame->GetScreenRect();
   1.195 +
   1.196 +  int32_t clientX = presContext->DevPixelsToIntCSSPixels(aX) - rootRect.x;
   1.197 +  int32_t clientY = presContext->DevPixelsToIntCSSPixels(aY) - rootRect.y;
   1.198 +
   1.199 +  int32_t row = -1;
   1.200 +  nsCOMPtr<nsITreeColumn> column;
   1.201 +  nsAutoCString childEltUnused;
   1.202 +  mTree->GetCellAt(clientX, clientY, &row, getter_AddRefs(column),
   1.203 +                   childEltUnused);
   1.204 +
   1.205 +  // If we failed to find tree cell for the given point then it might be
   1.206 +  // tree columns.
   1.207 +  if (row == -1 || !column)
   1.208 +    return AccessibleWrap::ChildAtPoint(aX, aY, aWhichChild);
   1.209 +
   1.210 +  Accessible* child = GetTreeItemAccessible(row);
   1.211 +  if (aWhichChild == eDeepestChild && child) {
   1.212 +    // Look for accessible cell for the found item accessible.
   1.213 +    nsRefPtr<XULTreeItemAccessibleBase> treeitem = do_QueryObject(child);
   1.214 +
   1.215 +    Accessible* cell = treeitem->GetCellAccessible(column);
   1.216 +    if (cell)
   1.217 +      child = cell;
   1.218 +  }
   1.219 +
   1.220 +  return child;
   1.221 +}
   1.222 +
   1.223 +////////////////////////////////////////////////////////////////////////////////
   1.224 +// XULTreeAccessible: SelectAccessible
   1.225 +
   1.226 +Accessible*
   1.227 +XULTreeAccessible::CurrentItem()
   1.228 +{
   1.229 +  if (!mTreeView)
   1.230 +    return nullptr;
   1.231 +
   1.232 +  nsCOMPtr<nsITreeSelection> selection;
   1.233 +  mTreeView->GetSelection(getter_AddRefs(selection));
   1.234 +  if (selection) {
   1.235 +    int32_t currentIndex = -1;
   1.236 +    selection->GetCurrentIndex(&currentIndex);
   1.237 +    if (currentIndex >= 0)
   1.238 +      return GetTreeItemAccessible(currentIndex);
   1.239 +  }
   1.240 +
   1.241 +  return nullptr;
   1.242 +}
   1.243 +
   1.244 +void
   1.245 +XULTreeAccessible::SetCurrentItem(Accessible* aItem)
   1.246 +{
   1.247 +  NS_ERROR("XULTreeAccessible::SetCurrentItem not implemented");
   1.248 +}
   1.249 +
   1.250 +already_AddRefed<nsIArray>
   1.251 +XULTreeAccessible::SelectedItems()
   1.252 +{
   1.253 +  if (!mTreeView)
   1.254 +    return nullptr;
   1.255 +
   1.256 +  nsCOMPtr<nsITreeSelection> selection;
   1.257 +  mTreeView->GetSelection(getter_AddRefs(selection));
   1.258 +  if (!selection)
   1.259 +    return nullptr;
   1.260 +
   1.261 +  nsCOMPtr<nsIMutableArray> selectedItems =
   1.262 +    do_CreateInstance(NS_ARRAY_CONTRACTID);
   1.263 +  if (!selectedItems)
   1.264 +    return nullptr;
   1.265 +
   1.266 +  int32_t rangeCount = 0;
   1.267 +  selection->GetRangeCount(&rangeCount);
   1.268 +  for (int32_t rangeIdx = 0; rangeIdx < rangeCount; rangeIdx++) {
   1.269 +    int32_t firstIdx = 0, lastIdx = -1;
   1.270 +    selection->GetRangeAt(rangeIdx, &firstIdx, &lastIdx);
   1.271 +    for (int32_t rowIdx = firstIdx; rowIdx <= lastIdx; rowIdx++) {
   1.272 +      nsIAccessible* item = GetTreeItemAccessible(rowIdx);
   1.273 +      if (item)
   1.274 +        selectedItems->AppendElement(item, false);
   1.275 +    }
   1.276 +  }
   1.277 +
   1.278 +  return selectedItems.forget();
   1.279 +}
   1.280 +
   1.281 +uint32_t
   1.282 +XULTreeAccessible::SelectedItemCount()
   1.283 +{
   1.284 +  if (!mTreeView)
   1.285 +    return 0;
   1.286 +
   1.287 +  nsCOMPtr<nsITreeSelection> selection;
   1.288 +  mTreeView->GetSelection(getter_AddRefs(selection));
   1.289 +  if (selection) {
   1.290 +    int32_t count = 0;
   1.291 +    selection->GetCount(&count);
   1.292 +    return count;
   1.293 +  }
   1.294 +
   1.295 +  return 0;
   1.296 +}
   1.297 +
   1.298 +bool
   1.299 +XULTreeAccessible::AddItemToSelection(uint32_t aIndex)
   1.300 +{
   1.301 +  if (!mTreeView)
   1.302 +    return false;
   1.303 +
   1.304 +  nsCOMPtr<nsITreeSelection> selection;
   1.305 +  mTreeView->GetSelection(getter_AddRefs(selection));
   1.306 +  if (selection) {
   1.307 +    bool isSelected = false;
   1.308 +    selection->IsSelected(aIndex, &isSelected);
   1.309 +    if (!isSelected)
   1.310 +      selection->ToggleSelect(aIndex);
   1.311 +
   1.312 +    return true;
   1.313 +  }
   1.314 +  return false;
   1.315 +}
   1.316 +
   1.317 +bool
   1.318 +XULTreeAccessible::RemoveItemFromSelection(uint32_t aIndex)
   1.319 +{
   1.320 +  if (!mTreeView)
   1.321 +    return false;
   1.322 +
   1.323 +  nsCOMPtr<nsITreeSelection> selection;
   1.324 +  mTreeView->GetSelection(getter_AddRefs(selection));
   1.325 +  if (selection) {
   1.326 +    bool isSelected = false;
   1.327 +    selection->IsSelected(aIndex, &isSelected);
   1.328 +    if (isSelected)
   1.329 +      selection->ToggleSelect(aIndex);
   1.330 +
   1.331 +    return true;
   1.332 +  }
   1.333 +  return false;
   1.334 +}
   1.335 +
   1.336 +bool
   1.337 +XULTreeAccessible::IsItemSelected(uint32_t aIndex)
   1.338 +{
   1.339 +  if (!mTreeView)
   1.340 +    return false;
   1.341 +
   1.342 +  nsCOMPtr<nsITreeSelection> selection;
   1.343 +  mTreeView->GetSelection(getter_AddRefs(selection));
   1.344 +  if (selection) {
   1.345 +    bool isSelected = false;
   1.346 +    selection->IsSelected(aIndex, &isSelected);
   1.347 +    return isSelected;
   1.348 +  }
   1.349 +  return false;
   1.350 +}
   1.351 +
   1.352 +bool
   1.353 +XULTreeAccessible::UnselectAll()
   1.354 +{
   1.355 +  if (!mTreeView)
   1.356 +    return false;
   1.357 +
   1.358 +  nsCOMPtr<nsITreeSelection> selection;
   1.359 +  mTreeView->GetSelection(getter_AddRefs(selection));
   1.360 +  if (!selection)
   1.361 +    return false;
   1.362 +
   1.363 +  selection->ClearSelection();
   1.364 +  return true;
   1.365 +}
   1.366 +
   1.367 +Accessible*
   1.368 +XULTreeAccessible::GetSelectedItem(uint32_t aIndex)
   1.369 +{
   1.370 +  if (!mTreeView)
   1.371 +    return nullptr;
   1.372 +
   1.373 +  nsCOMPtr<nsITreeSelection> selection;
   1.374 +  mTreeView->GetSelection(getter_AddRefs(selection));
   1.375 +  if (!selection)
   1.376 +    return nullptr;
   1.377 +
   1.378 +  uint32_t selCount = 0;
   1.379 +  int32_t rangeCount = 0;
   1.380 +  selection->GetRangeCount(&rangeCount);
   1.381 +  for (int32_t rangeIdx = 0; rangeIdx < rangeCount; rangeIdx++) {
   1.382 +    int32_t firstIdx = 0, lastIdx = -1;
   1.383 +    selection->GetRangeAt(rangeIdx, &firstIdx, &lastIdx);
   1.384 +    for (int32_t rowIdx = firstIdx; rowIdx <= lastIdx; rowIdx++) {
   1.385 +      if (selCount == aIndex)
   1.386 +        return GetTreeItemAccessible(rowIdx);
   1.387 +
   1.388 +      selCount++;
   1.389 +    }
   1.390 +  }
   1.391 +
   1.392 +  return nullptr;
   1.393 +}
   1.394 +
   1.395 +bool
   1.396 +XULTreeAccessible::SelectAll()
   1.397 +{
   1.398 +  // see if we are multiple select if so set ourselves as such
   1.399 +  if (!mTreeView)
   1.400 +    return false;
   1.401 +
   1.402 +  nsCOMPtr<nsITreeSelection> selection;
   1.403 +  mTreeView->GetSelection(getter_AddRefs(selection));
   1.404 +  if (selection) {
   1.405 +    bool single = false;
   1.406 +    selection->GetSingle(&single);
   1.407 +    if (!single) {
   1.408 +      selection->SelectAll();
   1.409 +      return true;
   1.410 +    }
   1.411 +  }
   1.412 +
   1.413 +  return false;
   1.414 +}
   1.415 +
   1.416 +////////////////////////////////////////////////////////////////////////////////
   1.417 +// XULTreeAccessible: Accessible implementation
   1.418 +
   1.419 +Accessible*
   1.420 +XULTreeAccessible::GetChildAt(uint32_t aIndex) const
   1.421 +{
   1.422 +  uint32_t childCount = Accessible::ChildCount();
   1.423 +  if (aIndex < childCount)
   1.424 +    return Accessible::GetChildAt(aIndex);
   1.425 +
   1.426 +  return GetTreeItemAccessible(aIndex - childCount);
   1.427 +}
   1.428 +
   1.429 +uint32_t
   1.430 +XULTreeAccessible::ChildCount() const
   1.431 +{
   1.432 +  // Tree's children count is row count + treecols count.
   1.433 +  uint32_t childCount = Accessible::ChildCount();
   1.434 +  if (!mTreeView)
   1.435 +    return childCount;
   1.436 +
   1.437 +  int32_t rowCount = 0;
   1.438 +  mTreeView->GetRowCount(&rowCount);
   1.439 +  childCount += rowCount;
   1.440 +
   1.441 +  return childCount;
   1.442 +}
   1.443 +
   1.444 +Relation
   1.445 +XULTreeAccessible::RelationByType(RelationType aType)
   1.446 +{
   1.447 +  if (aType == RelationType::NODE_PARENT_OF) {
   1.448 +    if (mTreeView)
   1.449 +      return Relation(new XULTreeItemIterator(this, mTreeView, -1));
   1.450 +
   1.451 +    return Relation();
   1.452 +  }
   1.453 +
   1.454 +  return Accessible::RelationByType(aType);
   1.455 +}
   1.456 +
   1.457 +////////////////////////////////////////////////////////////////////////////////
   1.458 +// XULTreeAccessible: Widgets
   1.459 +
   1.460 +bool
   1.461 +XULTreeAccessible::IsWidget() const
   1.462 +{
   1.463 +  return true;
   1.464 +}
   1.465 +
   1.466 +bool
   1.467 +XULTreeAccessible::IsActiveWidget() const
   1.468 +{
   1.469 +  if (IsAutoCompletePopup()) {
   1.470 +    nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
   1.471 +      do_QueryInterface(mContent->GetParent());
   1.472 +
   1.473 +    if (autoCompletePopupElm) {
   1.474 +      bool isOpen = false;
   1.475 +      autoCompletePopupElm->GetPopupOpen(&isOpen);
   1.476 +      return isOpen;
   1.477 +    }
   1.478 +  }
   1.479 +  return FocusMgr()->HasDOMFocus(mContent);
   1.480 +}
   1.481 +
   1.482 +bool
   1.483 +XULTreeAccessible::AreItemsOperable() const
   1.484 +{
   1.485 +  if (IsAutoCompletePopup()) {
   1.486 +    nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
   1.487 +      do_QueryInterface(mContent->GetParent());
   1.488 +
   1.489 +    if (autoCompletePopupElm) {
   1.490 +      bool isOpen = false;
   1.491 +      autoCompletePopupElm->GetPopupOpen(&isOpen);
   1.492 +      return isOpen;
   1.493 +    }
   1.494 +  }
   1.495 +  return true;
   1.496 +}
   1.497 +
   1.498 +Accessible*
   1.499 +XULTreeAccessible::ContainerWidget() const
   1.500 +{
   1.501 +  if (IsAutoCompletePopup()) {
   1.502 +    // This works for XUL autocompletes. It doesn't work for HTML forms
   1.503 +    // autocomplete because of potential crossprocess calls (when autocomplete
   1.504 +    // lives in content process while popup lives in chrome process). If that's
   1.505 +    // a problem then rethink Widgets interface.
   1.506 +    nsCOMPtr<nsIDOMXULMenuListElement> menuListElm =
   1.507 +      do_QueryInterface(mContent->GetParent());
   1.508 +    if (menuListElm) {
   1.509 +      nsCOMPtr<nsIDOMNode> inputElm;
   1.510 +      menuListElm->GetInputField(getter_AddRefs(inputElm));
   1.511 +      if (inputElm) {
   1.512 +        nsCOMPtr<nsINode> inputNode = do_QueryInterface(inputElm);
   1.513 +        if (inputNode) {
   1.514 +          Accessible* input = 
   1.515 +            mDoc->GetAccessible(inputNode);
   1.516 +          return input ? input->ContainerWidget() : nullptr;
   1.517 +        }
   1.518 +      }
   1.519 +    }
   1.520 +  }
   1.521 +  return nullptr;
   1.522 +}
   1.523 +
   1.524 +////////////////////////////////////////////////////////////////////////////////
   1.525 +// XULTreeAccessible: public implementation
   1.526 +
   1.527 +Accessible*
   1.528 +XULTreeAccessible::GetTreeItemAccessible(int32_t aRow) const
   1.529 +{
   1.530 +  if (aRow < 0 || IsDefunct() || !mTreeView)
   1.531 +    return nullptr;
   1.532 +
   1.533 +  int32_t rowCount = 0;
   1.534 +  nsresult rv = mTreeView->GetRowCount(&rowCount);
   1.535 +  if (NS_FAILED(rv) || aRow >= rowCount)
   1.536 +    return nullptr;
   1.537 +
   1.538 +  void *key = reinterpret_cast<void*>(aRow);
   1.539 +  Accessible* cachedTreeItem = mAccessibleCache.GetWeak(key);
   1.540 +  if (cachedTreeItem)
   1.541 +    return cachedTreeItem;
   1.542 +
   1.543 +  nsRefPtr<Accessible> treeItem = CreateTreeItemAccessible(aRow);
   1.544 +  if (treeItem) {
   1.545 +    mAccessibleCache.Put(key, treeItem);
   1.546 +    Document()->BindToDocument(treeItem, nullptr);
   1.547 +    return treeItem;
   1.548 +  }
   1.549 +
   1.550 +  return nullptr;
   1.551 +}
   1.552 +
   1.553 +void
   1.554 +XULTreeAccessible::InvalidateCache(int32_t aRow, int32_t aCount)
   1.555 +{
   1.556 +  if (IsDefunct())
   1.557 +    return;
   1.558 +
   1.559 +  if (!mTreeView) {
   1.560 +    ClearCache(mAccessibleCache);
   1.561 +    return;
   1.562 +  }
   1.563 +
   1.564 +  // Do not invalidate the cache if rows have been inserted.
   1.565 +  if (aCount > 0)
   1.566 +    return;
   1.567 +
   1.568 +  DocAccessible* document = Document();
   1.569 +
   1.570 +  // Fire destroy event for removed tree items and delete them from caches.
   1.571 +  for (int32_t rowIdx = aRow; rowIdx < aRow - aCount; rowIdx++) {
   1.572 +
   1.573 +    void* key = reinterpret_cast<void*>(rowIdx);
   1.574 +    Accessible* treeItem = mAccessibleCache.GetWeak(key);
   1.575 +
   1.576 +    if (treeItem) {
   1.577 +      nsRefPtr<AccEvent> event =
   1.578 +        new AccEvent(nsIAccessibleEvent::EVENT_HIDE, treeItem);
   1.579 +      nsEventShell::FireEvent(event);
   1.580 +
   1.581 +      // Unbind from document, shutdown and remove from tree cache.
   1.582 +      document->UnbindFromDocument(treeItem);
   1.583 +      mAccessibleCache.Remove(key);
   1.584 +    }
   1.585 +  }
   1.586 +
   1.587 +  // We dealt with removed tree items already however we may keep tree items
   1.588 +  // having row indexes greater than row count. We should remove these dead tree
   1.589 +  // items silently from caches.
   1.590 +  int32_t newRowCount = 0;
   1.591 +  nsresult rv = mTreeView->GetRowCount(&newRowCount);
   1.592 +  if (NS_FAILED(rv))
   1.593 +    return;
   1.594 +
   1.595 +  int32_t oldRowCount = newRowCount - aCount;
   1.596 +
   1.597 +  for (int32_t rowIdx = newRowCount; rowIdx < oldRowCount; ++rowIdx) {
   1.598 +
   1.599 +    void *key = reinterpret_cast<void*>(rowIdx);
   1.600 +    Accessible* treeItem = mAccessibleCache.GetWeak(key);
   1.601 +
   1.602 +    if (treeItem) {
   1.603 +      // Unbind from document, shutdown and remove from tree cache.
   1.604 +      document->UnbindFromDocument(treeItem);
   1.605 +      mAccessibleCache.Remove(key);
   1.606 +    }
   1.607 +  }
   1.608 +}
   1.609 +
   1.610 +void
   1.611 +XULTreeAccessible::TreeViewInvalidated(int32_t aStartRow, int32_t aEndRow,
   1.612 +                                       int32_t aStartCol, int32_t aEndCol)
   1.613 +{
   1.614 +  if (IsDefunct())
   1.615 +    return;
   1.616 +
   1.617 +  if (!mTreeView) {
   1.618 +    ClearCache(mAccessibleCache);
   1.619 +    return;
   1.620 +  }
   1.621 +
   1.622 +  int32_t endRow = aEndRow;
   1.623 +
   1.624 +  nsresult rv;
   1.625 +  if (endRow == -1) {
   1.626 +    int32_t rowCount = 0;
   1.627 +    rv = mTreeView->GetRowCount(&rowCount);
   1.628 +    if (NS_FAILED(rv))
   1.629 +      return;
   1.630 +
   1.631 +    endRow = rowCount - 1;
   1.632 +  }
   1.633 +
   1.634 +  nsCOMPtr<nsITreeColumns> treeColumns;
   1.635 +  mTree->GetColumns(getter_AddRefs(treeColumns));
   1.636 +  if (!treeColumns)
   1.637 +    return;
   1.638 +
   1.639 +  int32_t endCol = aEndCol;
   1.640 +
   1.641 +  if (endCol == -1) {
   1.642 +    int32_t colCount = 0;
   1.643 +    rv = treeColumns->GetCount(&colCount);
   1.644 +    if (NS_FAILED(rv))
   1.645 +      return;
   1.646 +
   1.647 +    endCol = colCount - 1;
   1.648 +  }
   1.649 +
   1.650 +  for (int32_t rowIdx = aStartRow; rowIdx <= endRow; ++rowIdx) {
   1.651 +
   1.652 +    void *key = reinterpret_cast<void*>(rowIdx);
   1.653 +    Accessible* accessible = mAccessibleCache.GetWeak(key);
   1.654 +
   1.655 +    if (accessible) {
   1.656 +      nsRefPtr<XULTreeItemAccessibleBase> treeitemAcc = do_QueryObject(accessible);
   1.657 +      NS_ASSERTION(treeitemAcc, "Wrong accessible at the given key!");
   1.658 +
   1.659 +      treeitemAcc->RowInvalidated(aStartCol, endCol);
   1.660 +    }
   1.661 +  }
   1.662 +}
   1.663 +
   1.664 +void
   1.665 +XULTreeAccessible::TreeViewChanged(nsITreeView* aView)
   1.666 +{
   1.667 +  if (IsDefunct())
   1.668 +    return;
   1.669 +
   1.670 +  // Fire reorder event on tree accessible on accessible tree (do not fire
   1.671 +  // show/hide events on tree items because it can be expensive to fire them for
   1.672 +  // each tree item.
   1.673 +  nsRefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(this);
   1.674 +  Document()->FireDelayedEvent(reorderEvent);
   1.675 +
   1.676 +  // Clear cache.
   1.677 +  ClearCache(mAccessibleCache);
   1.678 +  mTreeView = aView;
   1.679 +}
   1.680 +
   1.681 +////////////////////////////////////////////////////////////////////////////////
   1.682 +// XULTreeAccessible: protected implementation
   1.683 +
   1.684 +already_AddRefed<Accessible>
   1.685 +XULTreeAccessible::CreateTreeItemAccessible(int32_t aRow) const
   1.686 +{
   1.687 +  nsRefPtr<Accessible> accessible =
   1.688 +    new XULTreeItemAccessible(mContent, mDoc, const_cast<XULTreeAccessible*>(this),
   1.689 +                              mTree, mTreeView, aRow);
   1.690 +
   1.691 +  return accessible.forget();
   1.692 +}
   1.693 +                             
   1.694 +////////////////////////////////////////////////////////////////////////////////
   1.695 +// XULTreeItemAccessibleBase
   1.696 +////////////////////////////////////////////////////////////////////////////////
   1.697 +
   1.698 +XULTreeItemAccessibleBase::
   1.699 +  XULTreeItemAccessibleBase(nsIContent* aContent, DocAccessible* aDoc,
   1.700 +                            Accessible* aParent, nsITreeBoxObject* aTree,
   1.701 +                            nsITreeView* aTreeView, int32_t aRow) :
   1.702 +  AccessibleWrap(aContent, aDoc),
   1.703 +  mTree(aTree), mTreeView(aTreeView), mRow(aRow)
   1.704 +{
   1.705 +  mParent = aParent;
   1.706 +  mStateFlags |= eSharedNode;
   1.707 +}
   1.708 +
   1.709 +////////////////////////////////////////////////////////////////////////////////
   1.710 +// XULTreeItemAccessibleBase: nsISupports implementation
   1.711 +
   1.712 +NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeItemAccessibleBase, Accessible,
   1.713 +                                   mTree)
   1.714 +
   1.715 +NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(XULTreeItemAccessibleBase)
   1.716 +  NS_INTERFACE_TABLE_INHERITED(XULTreeItemAccessibleBase,
   1.717 +                               XULTreeItemAccessibleBase)
   1.718 +NS_INTERFACE_TABLE_TAIL_INHERITING(Accessible)
   1.719 +NS_IMPL_ADDREF_INHERITED(XULTreeItemAccessibleBase, Accessible)
   1.720 +NS_IMPL_RELEASE_INHERITED(XULTreeItemAccessibleBase, Accessible)
   1.721 +
   1.722 +////////////////////////////////////////////////////////////////////////////////
   1.723 +// XULTreeItemAccessibleBase: nsIAccessible implementation
   1.724 +
   1.725 +Accessible*
   1.726 +XULTreeItemAccessibleBase::FocusedChild()
   1.727 +{
   1.728 +  return FocusMgr()->FocusedAccessible() == this ? this : nullptr;
   1.729 +}
   1.730 +
   1.731 +NS_IMETHODIMP
   1.732 +XULTreeItemAccessibleBase::GetBounds(int32_t* aX, int32_t* aY,
   1.733 +                                     int32_t* aWidth, int32_t* aHeight)
   1.734 +{
   1.735 +  NS_ENSURE_ARG_POINTER(aX);
   1.736 +  *aX = 0;
   1.737 +  NS_ENSURE_ARG_POINTER(aY);
   1.738 +  *aY = 0;
   1.739 +  NS_ENSURE_ARG_POINTER(aWidth);
   1.740 +  *aWidth = 0;
   1.741 +  NS_ENSURE_ARG_POINTER(aHeight);
   1.742 +  *aHeight = 0;
   1.743 +
   1.744 +  if (IsDefunct())
   1.745 +    return NS_ERROR_FAILURE;
   1.746 +
   1.747 +  // Get x coordinate and width from treechildren element, get y coordinate and
   1.748 +  // height from tree cell.
   1.749 +
   1.750 +  nsCOMPtr<nsIBoxObject> boxObj = nsCoreUtils::GetTreeBodyBoxObject(mTree);
   1.751 +  NS_ENSURE_STATE(boxObj);
   1.752 +
   1.753 +  nsCOMPtr<nsITreeColumn> column = nsCoreUtils::GetFirstSensibleColumn(mTree);
   1.754 +
   1.755 +  int32_t x = 0, y = 0, width = 0, height = 0;
   1.756 +  nsresult rv = mTree->GetCoordsForCellItem(mRow, column, EmptyCString(),
   1.757 +                                            &x, &y, &width, &height);
   1.758 +  NS_ENSURE_SUCCESS(rv, rv);
   1.759 +
   1.760 +  boxObj->GetWidth(&width);
   1.761 +
   1.762 +  int32_t tcX = 0, tcY = 0;
   1.763 +  boxObj->GetScreenX(&tcX);
   1.764 +  boxObj->GetScreenY(&tcY);
   1.765 +
   1.766 +  x = tcX;
   1.767 +  y += tcY;
   1.768 +
   1.769 +  nsPresContext* presContext = mDoc->PresContext();
   1.770 +  *aX = presContext->CSSPixelsToDevPixels(x);
   1.771 +  *aY = presContext->CSSPixelsToDevPixels(y);
   1.772 +  *aWidth = presContext->CSSPixelsToDevPixels(width);
   1.773 +  *aHeight = presContext->CSSPixelsToDevPixels(height);
   1.774 +
   1.775 +  return NS_OK;
   1.776 +}
   1.777 +
   1.778 +NS_IMETHODIMP
   1.779 +XULTreeItemAccessibleBase::SetSelected(bool aSelect)
   1.780 +{
   1.781 +  if (IsDefunct())
   1.782 +    return NS_ERROR_FAILURE;
   1.783 +
   1.784 +  nsCOMPtr<nsITreeSelection> selection;
   1.785 +  mTreeView->GetSelection(getter_AddRefs(selection));
   1.786 +  if (selection) {
   1.787 +    bool isSelected;
   1.788 +    selection->IsSelected(mRow, &isSelected);
   1.789 +    if (isSelected != aSelect)
   1.790 +      selection->ToggleSelect(mRow);
   1.791 +  }
   1.792 +
   1.793 +  return NS_OK;
   1.794 +}
   1.795 +
   1.796 +NS_IMETHODIMP
   1.797 +XULTreeItemAccessibleBase::TakeFocus()
   1.798 +{
   1.799 +  if (IsDefunct())
   1.800 +    return NS_ERROR_FAILURE;
   1.801 +
   1.802 +  nsCOMPtr<nsITreeSelection> selection;
   1.803 +  mTreeView->GetSelection(getter_AddRefs(selection));
   1.804 +  if (selection)
   1.805 +    selection->SetCurrentIndex(mRow);
   1.806 +
   1.807 +  // focus event will be fired here
   1.808 +  return Accessible::TakeFocus();
   1.809 +}
   1.810 +
   1.811 +Relation
   1.812 +XULTreeItemAccessibleBase::RelationByType(RelationType aType)
   1.813 +{
   1.814 +
   1.815 +  switch (aType) {
   1.816 +    case RelationType::NODE_CHILD_OF: {
   1.817 +      int32_t parentIndex = -1;
   1.818 +      if (!NS_SUCCEEDED(mTreeView->GetParentIndex(mRow, &parentIndex)))
   1.819 +        return Relation();
   1.820 +
   1.821 +      if (parentIndex == -1)
   1.822 +        return Relation(mParent);
   1.823 +
   1.824 +      XULTreeAccessible* treeAcc = mParent->AsXULTree();
   1.825 +      return Relation(treeAcc->GetTreeItemAccessible(parentIndex));
   1.826 +    }
   1.827 +
   1.828 +    case RelationType::NODE_PARENT_OF: {
   1.829 +      bool isTrue = false;
   1.830 +      if (NS_FAILED(mTreeView->IsContainerEmpty(mRow, &isTrue)) || isTrue)
   1.831 +        return Relation();
   1.832 +
   1.833 +      if (NS_FAILED(mTreeView->IsContainerOpen(mRow, &isTrue)) || !isTrue)
   1.834 +        return Relation();
   1.835 +
   1.836 +      XULTreeAccessible* tree = mParent->AsXULTree();
   1.837 +      return Relation(new XULTreeItemIterator(tree, mTreeView, mRow));
   1.838 +    }
   1.839 +
   1.840 +    default:
   1.841 +      return Relation();
   1.842 +  }
   1.843 +}
   1.844 +
   1.845 +uint8_t
   1.846 +XULTreeItemAccessibleBase::ActionCount()
   1.847 +{
   1.848 +  // "activate" action is available for all treeitems, "expand/collapse" action
   1.849 +  // is avaible for treeitem which is container.
   1.850 +  return IsExpandable() ? 2 : 1;
   1.851 +}
   1.852 +
   1.853 +NS_IMETHODIMP
   1.854 +XULTreeItemAccessibleBase::GetActionName(uint8_t aIndex, nsAString& aName)
   1.855 +{
   1.856 +  if (IsDefunct())
   1.857 +    return NS_ERROR_FAILURE;
   1.858 +
   1.859 +  if (aIndex == eAction_Click) {
   1.860 +    aName.AssignLiteral("activate");
   1.861 +    return NS_OK;
   1.862 +  }
   1.863 +
   1.864 +  if (aIndex == eAction_Expand && IsExpandable()) {
   1.865 +    bool isContainerOpen;
   1.866 +    mTreeView->IsContainerOpen(mRow, &isContainerOpen);
   1.867 +    if (isContainerOpen)
   1.868 +      aName.AssignLiteral("collapse");
   1.869 +    else
   1.870 +      aName.AssignLiteral("expand");
   1.871 +
   1.872 +    return NS_OK;
   1.873 +  }
   1.874 +
   1.875 +  return NS_ERROR_INVALID_ARG;
   1.876 +}
   1.877 +
   1.878 +NS_IMETHODIMP
   1.879 +XULTreeItemAccessibleBase::DoAction(uint8_t aIndex)
   1.880 +{
   1.881 +  if (IsDefunct())
   1.882 +    return NS_ERROR_FAILURE;
   1.883 +
   1.884 +  if (aIndex != eAction_Click &&
   1.885 +      (aIndex != eAction_Expand || !IsExpandable()))
   1.886 +    return NS_ERROR_INVALID_ARG;
   1.887 +
   1.888 +  DoCommand(nullptr, aIndex);
   1.889 +  return NS_OK;
   1.890 +}
   1.891 +
   1.892 +////////////////////////////////////////////////////////////////////////////////
   1.893 +// XULTreeItemAccessibleBase: Accessible implementation
   1.894 +
   1.895 +void
   1.896 +XULTreeItemAccessibleBase::Shutdown()
   1.897 +{
   1.898 +  mTree = nullptr;
   1.899 +  mTreeView = nullptr;
   1.900 +  mRow = -1;
   1.901 +
   1.902 +  AccessibleWrap::Shutdown();
   1.903 +}
   1.904 +
   1.905 +GroupPos
   1.906 +XULTreeItemAccessibleBase::GroupPosition()
   1.907 +{
   1.908 +  GroupPos groupPos;
   1.909 +
   1.910 +  int32_t level;
   1.911 +  nsresult rv = mTreeView->GetLevel(mRow, &level);
   1.912 +  NS_ENSURE_SUCCESS(rv, groupPos);
   1.913 +
   1.914 +  int32_t topCount = 1;
   1.915 +  for (int32_t index = mRow - 1; index >= 0; index--) {
   1.916 +    int32_t lvl = -1;
   1.917 +    if (NS_SUCCEEDED(mTreeView->GetLevel(index, &lvl))) {
   1.918 +      if (lvl < level)
   1.919 +        break;
   1.920 +
   1.921 +      if (lvl == level)
   1.922 +        topCount++;
   1.923 +    }
   1.924 +  }
   1.925 +
   1.926 +  int32_t rowCount = 0;
   1.927 +  rv = mTreeView->GetRowCount(&rowCount);
   1.928 +  NS_ENSURE_SUCCESS(rv, groupPos);
   1.929 +
   1.930 +  int32_t bottomCount = 0;
   1.931 +  for (int32_t index = mRow + 1; index < rowCount; index++) {
   1.932 +    int32_t lvl = -1;
   1.933 +    if (NS_SUCCEEDED(mTreeView->GetLevel(index, &lvl))) {
   1.934 +      if (lvl < level)
   1.935 +        break;
   1.936 +
   1.937 +      if (lvl == level)
   1.938 +        bottomCount++;
   1.939 +    }
   1.940 +  }
   1.941 +
   1.942 +  groupPos.level = level + 1;
   1.943 +  groupPos.setSize = topCount + bottomCount;
   1.944 +  groupPos.posInSet = topCount;
   1.945 +
   1.946 +  return groupPos;
   1.947 +}
   1.948 +
   1.949 +uint64_t
   1.950 +XULTreeItemAccessibleBase::NativeState()
   1.951 +{
   1.952 +
   1.953 +  // focusable and selectable states
   1.954 +  uint64_t state = NativeInteractiveState();
   1.955 +
   1.956 +  // expanded/collapsed state
   1.957 +  if (IsExpandable()) {
   1.958 +    bool isContainerOpen;
   1.959 +    mTreeView->IsContainerOpen(mRow, &isContainerOpen);
   1.960 +    state |= isContainerOpen ? states::EXPANDED : states::COLLAPSED;
   1.961 +  }
   1.962 +
   1.963 +  // selected state
   1.964 +  nsCOMPtr<nsITreeSelection> selection;
   1.965 +  mTreeView->GetSelection(getter_AddRefs(selection));
   1.966 +  if (selection) {
   1.967 +    bool isSelected;
   1.968 +    selection->IsSelected(mRow, &isSelected);
   1.969 +    if (isSelected)
   1.970 +      state |= states::SELECTED;
   1.971 +  }
   1.972 +
   1.973 +  // focused state
   1.974 +  if (FocusMgr()->IsFocused(this))
   1.975 +    state |= states::FOCUSED;
   1.976 +
   1.977 +  // invisible state
   1.978 +  int32_t firstVisibleRow, lastVisibleRow;
   1.979 +  mTree->GetFirstVisibleRow(&firstVisibleRow);
   1.980 +  mTree->GetLastVisibleRow(&lastVisibleRow);
   1.981 +  if (mRow < firstVisibleRow || mRow > lastVisibleRow)
   1.982 +    state |= states::INVISIBLE;
   1.983 +
   1.984 +  return state;
   1.985 +}
   1.986 +
   1.987 +uint64_t
   1.988 +XULTreeItemAccessibleBase::NativeInteractiveState() const
   1.989 +{
   1.990 +  return states::FOCUSABLE | states::SELECTABLE;
   1.991 +}
   1.992 +
   1.993 +int32_t
   1.994 +XULTreeItemAccessibleBase::IndexInParent() const
   1.995 +{
   1.996 +  return mParent ? mParent->ContentChildCount() + mRow : -1;
   1.997 +}
   1.998 +
   1.999 +////////////////////////////////////////////////////////////////////////////////
  1.1000 +// XULTreeItemAccessibleBase: Widgets
  1.1001 +
  1.1002 +Accessible*
  1.1003 +XULTreeItemAccessibleBase::ContainerWidget() const
  1.1004 +{
  1.1005 +  return mParent;
  1.1006 +}
  1.1007 +
  1.1008 +////////////////////////////////////////////////////////////////////////////////
  1.1009 +// XULTreeItemAccessibleBase: Accessible protected methods
  1.1010 +
  1.1011 +void
  1.1012 +XULTreeItemAccessibleBase::DispatchClickEvent(nsIContent* aContent,
  1.1013 +                                              uint32_t aActionIndex)
  1.1014 +{
  1.1015 +  if (IsDefunct())
  1.1016 +    return;
  1.1017 +
  1.1018 +  nsCOMPtr<nsITreeColumns> columns;
  1.1019 +  mTree->GetColumns(getter_AddRefs(columns));
  1.1020 +  if (!columns)
  1.1021 +    return;
  1.1022 +
  1.1023 +  // Get column and pseudo element.
  1.1024 +  nsCOMPtr<nsITreeColumn> column;
  1.1025 +  nsAutoCString pseudoElm;
  1.1026 +
  1.1027 +  if (aActionIndex == eAction_Click) {
  1.1028 +    // Key column is visible and clickable.
  1.1029 +    columns->GetKeyColumn(getter_AddRefs(column));
  1.1030 +  } else {
  1.1031 +    // Primary column contains a twisty we should click on.
  1.1032 +    columns->GetPrimaryColumn(getter_AddRefs(column));
  1.1033 +    pseudoElm = NS_LITERAL_CSTRING("twisty");
  1.1034 +  }
  1.1035 +
  1.1036 +  if (column)
  1.1037 +    nsCoreUtils::DispatchClickEvent(mTree, mRow, column, pseudoElm);
  1.1038 +}
  1.1039 +
  1.1040 +Accessible*
  1.1041 +XULTreeItemAccessibleBase::GetSiblingAtOffset(int32_t aOffset,
  1.1042 +                                              nsresult* aError) const
  1.1043 +{
  1.1044 +  if (aError)
  1.1045 +    *aError = NS_OK; // fail peacefully
  1.1046 +
  1.1047 +  return mParent->GetChildAt(IndexInParent() + aOffset);
  1.1048 +}
  1.1049 +
  1.1050 +////////////////////////////////////////////////////////////////////////////////
  1.1051 +// XULTreeItemAccessibleBase: protected implementation
  1.1052 +
  1.1053 +bool
  1.1054 +XULTreeItemAccessibleBase::IsExpandable()
  1.1055 +{
  1.1056 +
  1.1057 +  bool isContainer = false;
  1.1058 +  mTreeView->IsContainer(mRow, &isContainer);
  1.1059 +  if (isContainer) {
  1.1060 +    bool isEmpty = false;
  1.1061 +    mTreeView->IsContainerEmpty(mRow, &isEmpty);
  1.1062 +    if (!isEmpty) {
  1.1063 +      nsCOMPtr<nsITreeColumns> columns;
  1.1064 +      mTree->GetColumns(getter_AddRefs(columns));
  1.1065 +      nsCOMPtr<nsITreeColumn> primaryColumn;
  1.1066 +      if (columns) {
  1.1067 +        columns->GetPrimaryColumn(getter_AddRefs(primaryColumn));
  1.1068 +        if (primaryColumn &&
  1.1069 +            !nsCoreUtils::IsColumnHidden(primaryColumn))
  1.1070 +          return true;
  1.1071 +      }
  1.1072 +    }
  1.1073 +  }
  1.1074 +
  1.1075 +  return false;
  1.1076 +}
  1.1077 +
  1.1078 +void
  1.1079 +XULTreeItemAccessibleBase::GetCellName(nsITreeColumn* aColumn, nsAString& aName)
  1.1080 +{
  1.1081 +
  1.1082 +  mTreeView->GetCellText(mRow, aColumn, aName);
  1.1083 +
  1.1084 +  // If there is still no name try the cell value:
  1.1085 +  // This is for graphical cells. We need tree/table view implementors to
  1.1086 +  // implement FooView::GetCellValue to return a meaningful string for cases
  1.1087 +  // where there is something shown in the cell (non-text) such as a star icon;
  1.1088 +  // in which case GetCellValue for that cell would return "starred" or
  1.1089 +  // "flagged" for example.
  1.1090 +  if (aName.IsEmpty())
  1.1091 +    mTreeView->GetCellValue(mRow, aColumn, aName);
  1.1092 +}
  1.1093 +
  1.1094 +
  1.1095 +////////////////////////////////////////////////////////////////////////////////
  1.1096 +// XULTreeItemAccessible
  1.1097 +////////////////////////////////////////////////////////////////////////////////
  1.1098 +
  1.1099 +XULTreeItemAccessible::
  1.1100 +  XULTreeItemAccessible(nsIContent* aContent, DocAccessible* aDoc,
  1.1101 +                        Accessible* aParent, nsITreeBoxObject* aTree,
  1.1102 +                        nsITreeView* aTreeView, int32_t aRow) :
  1.1103 +  XULTreeItemAccessibleBase(aContent, aDoc, aParent, aTree, aTreeView, aRow)
  1.1104 +{
  1.1105 +  mColumn = nsCoreUtils::GetFirstSensibleColumn(mTree);
  1.1106 +  GetCellName(mColumn, mCachedName);
  1.1107 +}
  1.1108 +
  1.1109 +////////////////////////////////////////////////////////////////////////////////
  1.1110 +// XULTreeItemAccessible: nsISupports implementation
  1.1111 +
  1.1112 +NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeItemAccessible,
  1.1113 +                                   XULTreeItemAccessibleBase,
  1.1114 +                                   mColumn)
  1.1115 +
  1.1116 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(XULTreeItemAccessible)
  1.1117 +NS_INTERFACE_MAP_END_INHERITING(XULTreeItemAccessibleBase)
  1.1118 +NS_IMPL_ADDREF_INHERITED(XULTreeItemAccessible, XULTreeItemAccessibleBase)
  1.1119 +NS_IMPL_RELEASE_INHERITED(XULTreeItemAccessible, XULTreeItemAccessibleBase)
  1.1120 +
  1.1121 +////////////////////////////////////////////////////////////////////////////////
  1.1122 +// XULTreeItemAccessible: nsIAccessible implementation
  1.1123 +
  1.1124 +ENameValueFlag
  1.1125 +XULTreeItemAccessible::Name(nsString& aName)
  1.1126 +{
  1.1127 +  aName.Truncate();
  1.1128 +
  1.1129 +  GetCellName(mColumn, aName);
  1.1130 +  return eNameOK;
  1.1131 +}
  1.1132 +
  1.1133 +////////////////////////////////////////////////////////////////////////////////
  1.1134 +// XULTreeItemAccessible: Accessible implementation
  1.1135 +
  1.1136 +void
  1.1137 +XULTreeItemAccessible::Shutdown()
  1.1138 +{
  1.1139 +  mColumn = nullptr;
  1.1140 +  XULTreeItemAccessibleBase::Shutdown();
  1.1141 +}
  1.1142 +
  1.1143 +role
  1.1144 +XULTreeItemAccessible::NativeRole()
  1.1145 +{
  1.1146 +  nsCOMPtr<nsITreeColumns> columns;
  1.1147 +  mTree->GetColumns(getter_AddRefs(columns));
  1.1148 +  if (!columns) {
  1.1149 +    NS_ERROR("No tree columns object in the tree!");
  1.1150 +    return roles::NOTHING;
  1.1151 +  }
  1.1152 +
  1.1153 +  nsCOMPtr<nsITreeColumn> primaryColumn;
  1.1154 +  columns->GetPrimaryColumn(getter_AddRefs(primaryColumn));
  1.1155 +
  1.1156 +  return primaryColumn ? roles::OUTLINEITEM : roles::LISTITEM;
  1.1157 +}
  1.1158 +
  1.1159 +////////////////////////////////////////////////////////////////////////////////
  1.1160 +// XULTreeItemAccessible: XULTreeItemAccessibleBase implementation
  1.1161 +
  1.1162 +void
  1.1163 +XULTreeItemAccessible::RowInvalidated(int32_t aStartColIdx, int32_t aEndColIdx)
  1.1164 +{
  1.1165 +  nsAutoString name;
  1.1166 +  Name(name);
  1.1167 +
  1.1168 +  if (name != mCachedName) {
  1.1169 +    nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this);
  1.1170 +    mCachedName = name;
  1.1171 +  }
  1.1172 +}
  1.1173 +
  1.1174 +////////////////////////////////////////////////////////////////////////////////
  1.1175 +// XULTreeItemAccessible: Accessible protected implementation
  1.1176 +
  1.1177 +void
  1.1178 +XULTreeItemAccessible::CacheChildren()
  1.1179 +{
  1.1180 +}
  1.1181 +
  1.1182 +
  1.1183 +////////////////////////////////////////////////////////////////////////////////
  1.1184 +//  XULTreeColumAccessible
  1.1185 +////////////////////////////////////////////////////////////////////////////////
  1.1186 +
  1.1187 +XULTreeColumAccessible::
  1.1188 +  XULTreeColumAccessible(nsIContent* aContent, DocAccessible* aDoc) :
  1.1189 +  XULColumAccessible(aContent, aDoc)
  1.1190 +{
  1.1191 +}
  1.1192 +
  1.1193 +Accessible*
  1.1194 +XULTreeColumAccessible::GetSiblingAtOffset(int32_t aOffset,
  1.1195 +                                           nsresult* aError) const
  1.1196 +{
  1.1197 +  if (aOffset < 0)
  1.1198 +    return XULColumAccessible::GetSiblingAtOffset(aOffset, aError);
  1.1199 +
  1.1200 +  if (aError)
  1.1201 +    *aError =  NS_OK; // fail peacefully
  1.1202 +
  1.1203 +  nsCOMPtr<nsITreeBoxObject> tree = nsCoreUtils::GetTreeBoxObject(mContent);
  1.1204 +  if (tree) {
  1.1205 +    nsCOMPtr<nsITreeView> treeView;
  1.1206 +    tree->GetView(getter_AddRefs(treeView));
  1.1207 +    if (treeView) {
  1.1208 +      int32_t rowCount = 0;
  1.1209 +      treeView->GetRowCount(&rowCount);
  1.1210 +      if (rowCount > 0 && aOffset <= rowCount) {
  1.1211 +        XULTreeAccessible* treeAcc = Parent()->AsXULTree();
  1.1212 +
  1.1213 +        if (treeAcc)
  1.1214 +          return treeAcc->GetTreeItemAccessible(aOffset - 1);
  1.1215 +      }
  1.1216 +    }
  1.1217 +  }
  1.1218 +
  1.1219 +  return nullptr;
  1.1220 +}
  1.1221 +

mercurial