Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  XULTreeAccessible.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "XULTreeAccessible.h"

#include "LocalAccessible-inl.h"
#include "DocAccessible-inl.h"
#include "nsAccCache.h"
#include "nsAccUtils.h"
#include "nsCoreUtils.h"
#include "nsEventShell.h"
#include "DocAccessible.h"
#include "Relation.h"
#include "mozilla/a11y/Role.h"
#include "States.h"
#include "XULTreeGridAccessible.h"
#include "nsQueryObject.h"

#include "nsComponentManagerUtils.h"
#include "nsIAutoCompletePopup.h"
#include "nsIDOMXULMenuListElement.h"
#include "nsITreeSelection.h"
#include "nsTreeBodyFrame.h"
#include "nsTreeColumns.h"
#include "nsTreeUtils.h"
#include "mozilla/PresShell.h"
#include "mozilla/dom/XULTreeElementBinding.h"

using namespace mozilla::a11y;

////////////////////////////////////////////////////////////////////////////////
// XULTreeAccessible
////////////////////////////////////////////////////////////////////////////////

XULTreeAccessible::XULTreeAccessible(nsIContent* aContent, DocAccessible* aDoc,
                                     nsTreeBodyFrame* aTreeFrame)
    : AccessibleWrap(aContent, aDoc),
      mAccessibleCache(kDefaultTreeCacheLength) {
  mType = eXULTreeType;
  mGenericTypes |= eSelect;

  nsCOMPtr<nsITreeView> view = aTreeFrame->GetExistingView();
  mTreeView = view;

  mTree = nsCoreUtils::GetTree(aContent);
  NS_ASSERTION(mTree, "Can't get mTree!\n");

  nsIContent* parentContent = mContent->GetParent();
  if (parentContent) {
    nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
        do_QueryInterface(parentContent);
    if (autoCompletePopupElm) mGenericTypes |= eAutoCompletePopup;
  }
}

XULTreeAccessible::~XULTreeAccessible() {}

////////////////////////////////////////////////////////////////////////////////
// XULTreeAccessible: nsISupports and cycle collection implementation

NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeAccessible, LocalAccessible, mTree,
                                   mAccessibleCache)

NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XULTreeAccessible)
NS_INTERFACE_MAP_END_INHERITING(LocalAccessible)

NS_IMPL_ADDREF_INHERITED(XULTreeAccessible, LocalAccessible)
NS_IMPL_RELEASE_INHERITED(XULTreeAccessible, LocalAccessible)

////////////////////////////////////////////////////////////////////////////////
// XULTreeAccessible: LocalAccessible implementation

uint64_t XULTreeAccessible::NativeState() const {
  // Get focus status from base class.
  uint64_t state = LocalAccessible::NativeState();

  // readonly state
  state |= states::READONLY;

  // multiselectable state.
  if (!mTreeView) return state;

  nsCOMPtr<nsITreeSelection> selection;
  mTreeView->GetSelection(getter_AddRefs(selection));
  NS_ENSURE_TRUE(selection, state);

  bool isSingle = false;
  nsresult rv = selection->GetSingle(&isSingle);
  NS_ENSURE_SUCCESS(rv, state);

  if (!isSingle) state |= states::MULTISELECTABLE;

  return state;
}

void XULTreeAccessible::Value(nsString& aValue) const {
  aValue.Truncate();
  if (!mTreeView) return;

  // Return the value is the first selected child.
  nsCOMPtr<nsITreeSelection> selection;
  mTreeView->GetSelection(getter_AddRefs(selection));
  if (!selection) return;

  int32_t currentIndex;
  selection->GetCurrentIndex(¤tIndex);
  if (currentIndex >= 0) {
    RefPtr<nsTreeColumn> keyCol;

    RefPtr<nsTreeColumns> cols = mTree->GetColumns();
    if (cols) keyCol = cols->GetKeyColumn();

    mTreeView->GetCellText(currentIndex, keyCol, aValue);
  }
}

////////////////////////////////////////////////////////////////////////////////
// XULTreeAccessible: LocalAccessible implementation

void XULTreeAccessible::Shutdown() {
  if (mDoc && !mDoc->IsDefunct()) {
    UnbindCacheEntriesFromDocument(mAccessibleCache);
  }

  mTree = nullptr;
  mTreeView = nullptr;

  AccessibleWrap::Shutdown();
}

role XULTreeAccessible::NativeRole() const {
  // No primary column means we're in a list. In fact, history and mail turn off
  // the primary flag when switching to a flat view.

  nsIContent* child =
      nsTreeUtils::GetDescendantChild(mContent, nsGkAtoms::treechildren);
  NS_ASSERTION(child, "tree without treechildren!");
  nsTreeBodyFrame* treeFrame = do_QueryFrame(child->GetPrimaryFrame());
  NS_ASSERTION(treeFrame, "xul tree accessible for tree without a frame!");
  if (!treeFrame) return roles::LIST;

  RefPtr<nsTreeColumns> cols = treeFrame->Columns();
  nsTreeColumn* primaryCol = cols->GetPrimaryColumn();

  return primaryCol ? roles::OUTLINE : roles::LIST;
}

////////////////////////////////////////////////////////////////////////////////
// XULTreeAccessible: LocalAccessible implementation (DON'T put methods here)

LocalAccessible* XULTreeAccessible::LocalChildAtPoint(
    int32_t aX, int32_t aY, EWhichChildAtPoint aWhichChild) {
  nsIFrame* frame = GetFrame();
  if (!frame) return nullptr;

  nsPresContext* presContext = frame->PresContext();
  PresShell* presShell = presContext->PresShell();

  nsIFrame* rootFrame = presShell->GetRootFrame();
  NS_ENSURE_TRUE(rootFrame, nullptr);

  CSSIntRect rootRect = rootFrame->GetScreenRect();

  int32_t clientX = presContext->DevPixelsToIntCSSPixels(aX) - rootRect.X();
  int32_t clientY = presContext->DevPixelsToIntCSSPixels(aY) - rootRect.Y();

  ErrorResult rv;
  dom::TreeCellInfo cellInfo;
  mTree->GetCellAt(clientX, clientY, cellInfo, rv);

  // If we failed to find tree cell for the given point then it might be
  // tree columns.
  if (cellInfo.mRow == -1 || !cellInfo.mCol) {
    return AccessibleWrap::LocalChildAtPoint(aX, aY, aWhichChild);
  }

  XULTreeItemAccessibleBase* child = GetTreeItemAccessible(cellInfo.mRow);
  if (aWhichChild == EWhichChildAtPoint::DeepestChild && child) {
    LocalAccessible* cell = child->GetCellAccessible(cellInfo.mCol);
    if (cell) {
      return cell;
    }
  }

  return child;
}

////////////////////////////////////////////////////////////////////////////////
// XULTreeAccessible: SelectAccessible

LocalAccessible* XULTreeAccessible::CurrentItem() const {
  if (!mTreeView) return nullptr;

  nsCOMPtr<nsITreeSelection> selection;
  mTreeView->GetSelection(getter_AddRefs(selection));
  if (selection) {
    int32_t currentIndex = -1;
    selection->GetCurrentIndex(¤tIndex);
    if (currentIndex >= 0) return GetTreeItemAccessible(currentIndex);
  }

  return nullptr;
}

void XULTreeAccessible::SetCurrentItem(const LocalAccessible* aItem) {
  NS_ERROR("XULTreeAccessible::SetCurrentItem not implemented");
}

void XULTreeAccessible::SelectedItems(nsTArray<Accessible*>* aItems) {
  if (!mTreeView) return;

  nsCOMPtr<nsITreeSelection> selection;
  mTreeView->GetSelection(getter_AddRefs(selection));
  if (!selection) return;

  int32_t rangeCount = 0;
  selection->GetRangeCount(&rangeCount);
  for (int32_t rangeIdx = 0; rangeIdx < rangeCount; rangeIdx++) {
    int32_t firstIdx = 0, lastIdx = -1;
    selection->GetRangeAt(rangeIdx, &firstIdx, &lastIdx);
    for (int32_t rowIdx = firstIdx; rowIdx <= lastIdx; rowIdx++) {
      LocalAccessible* item = GetTreeItemAccessible(rowIdx);
      if (item) aItems->AppendElement(item);
    }
  }
}

uint32_t XULTreeAccessible::SelectedItemCount() {
  if (!mTreeView) return 0;

  nsCOMPtr<nsITreeSelection> selection;
  mTreeView->GetSelection(getter_AddRefs(selection));
  if (selection) {
    int32_t count = 0;
    selection->GetCount(&count);
    return count;
  }

  return 0;
}

bool XULTreeAccessible::AddItemToSelection(uint32_t aIndex) {
  if (!mTreeView) return false;

  nsCOMPtr<nsITreeSelection> selection;
  mTreeView->GetSelection(getter_AddRefs(selection));
  if (selection) {
    bool isSelected = false;
    selection->IsSelected(aIndex, &isSelected);
    if (!isSelected) selection->ToggleSelect(aIndex);

    return true;
  }
  return false;
}

bool XULTreeAccessible::RemoveItemFromSelection(uint32_t aIndex) {
  if (!mTreeView) return false;

  nsCOMPtr<nsITreeSelection> selection;
  mTreeView->GetSelection(getter_AddRefs(selection));
  if (selection) {
    bool isSelected = false;
    selection->IsSelected(aIndex, &isSelected);
    if (isSelected) selection->ToggleSelect(aIndex);

    return true;
  }
  return false;
}

bool XULTreeAccessible::IsItemSelected(uint32_t aIndex) {
  if (!mTreeView) return false;

  nsCOMPtr<nsITreeSelection> selection;
  mTreeView->GetSelection(getter_AddRefs(selection));
  if (selection) {
    bool isSelected = false;
    selection->IsSelected(aIndex, &isSelected);
    return isSelected;
  }
  return false;
}

bool XULTreeAccessible::UnselectAll() {
  if (!mTreeView) return false;

  nsCOMPtr<nsITreeSelection> selection;
  mTreeView->GetSelection(getter_AddRefs(selection));
  if (!selection) return false;

  selection->ClearSelection();
  return true;
}

Accessible* XULTreeAccessible::GetSelectedItem(uint32_t aIndex) {
  if (!mTreeView) return nullptr;

  nsCOMPtr<nsITreeSelection> selection;
  mTreeView->GetSelection(getter_AddRefs(selection));
  if (!selection) return nullptr;

  uint32_t selCount = 0;
  int32_t rangeCount = 0;
  selection->GetRangeCount(&rangeCount);
  for (int32_t rangeIdx = 0; rangeIdx < rangeCount; rangeIdx++) {
    int32_t firstIdx = 0, lastIdx = -1;
    selection->GetRangeAt(rangeIdx, &firstIdx, &lastIdx);
    for (int32_t rowIdx = firstIdx; rowIdx <= lastIdx; rowIdx++) {
      if (selCount == aIndex) return GetTreeItemAccessible(rowIdx);

      selCount++;
    }
  }

  return nullptr;
}

bool XULTreeAccessible::SelectAll() {
  // see if we are multiple select if so set ourselves as such
  if (!mTreeView) return false;

  nsCOMPtr<nsITreeSelection> selection;
  mTreeView->GetSelection(getter_AddRefs(selection));
  if (selection) {
    bool single = false;
    selection->GetSingle(&single);
    if (!single) {
      selection->SelectAll();
      return true;
    }
  }

  return false;
}

////////////////////////////////////////////////////////////////////////////////
// XULTreeAccessible: LocalAccessible implementation

LocalAccessible* XULTreeAccessible::LocalChildAt(uint32_t aIndex) const {
  uint32_t childCount = LocalAccessible::ChildCount();
  if (aIndex < childCount) {
    return LocalAccessible::LocalChildAt(aIndex);
  }

  return GetTreeItemAccessible(aIndex - childCount);
}

uint32_t XULTreeAccessible::ChildCount() const {
  // Tree's children count is row count + treecols count.
  uint32_t childCount = LocalAccessible::ChildCount();
  if (!mTreeView) return childCount;

  int32_t rowCount = 0;
  mTreeView->GetRowCount(&rowCount);
  childCount += rowCount;

  return childCount;
}

Relation XULTreeAccessible::RelationByType(RelationType aType) const {
  if (aType == RelationType::NODE_PARENT_OF) {
    if (mTreeView) {
      return Relation(new XULTreeItemIterator(this, mTreeView, -1));
    }

    return Relation();
  }

  return LocalAccessible::RelationByType(aType);
}

////////////////////////////////////////////////////////////////////////////////
// XULTreeAccessible: Widgets

bool XULTreeAccessible::IsWidget() const { return true; }

bool XULTreeAccessible::IsActiveWidget() const {
  if (IsAutoCompletePopup()) {
    nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
        do_QueryInterface(mContent->GetParent());

    if (autoCompletePopupElm) {
      bool isOpen = false;
      autoCompletePopupElm->GetPopupOpen(&isOpen);
      return isOpen;
    }
  }
  return FocusMgr()->HasDOMFocus(mContent);
}

bool XULTreeAccessible::AreItemsOperable() const {
  if (IsAutoCompletePopup()) {
    nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
        do_QueryInterface(mContent->GetParent());

    if (autoCompletePopupElm) {
      bool isOpen = false;
      autoCompletePopupElm->GetPopupOpen(&isOpen);
      return isOpen;
    }
  }
  return true;
}

LocalAccessible* XULTreeAccessible::ContainerWidget() const { return nullptr; }

////////////////////////////////////////////////////////////////////////////////
// XULTreeAccessible: public implementation

XULTreeItemAccessibleBase* XULTreeAccessible::GetTreeItemAccessible(
    int32_t aRow) const {
  if (aRow < 0 || IsDefunct() || !mTreeView) return nullptr;

  int32_t rowCount = 0;
  nsresult rv = mTreeView->GetRowCount(&rowCount);
  if (NS_FAILED(rv) || aRow >= rowCount) return nullptr;

  void* key = reinterpret_cast<void*>(intptr_t(aRow));
  return mAccessibleCache.WithEntryHandle(
      key, [&](auto&& entry) -> XULTreeItemAccessibleBase* {
        if (entry) {
          return entry->get();
        }

        RefPtr<XULTreeItemAccessibleBase> treeItem =
            CreateTreeItemAccessible(aRow);
        if (treeItem) {
          entry.Insert(RefPtr{treeItem});
          Document()->BindToDocument(treeItem, nullptr);
          return treeItem.get();
        }

        return nullptr;
      });
}

void XULTreeAccessible::InvalidateCache(int32_t aRow, int32_t aCount) {
  if (IsDefunct()) return;

  if (!mTreeView) {
    UnbindCacheEntriesFromDocument(mAccessibleCache);
    return;
  }

  // Do not invalidate the cache if rows have been inserted.
  if (aCount > 0) return;

  DocAccessible* document = Document();

  // Fire destroy event for removed tree items and delete them from caches.
  for (int32_t rowIdx = aRow; rowIdx < aRow - aCount; rowIdx++) {
    void* key = reinterpret_cast<void*>(intptr_t(rowIdx));
    XULTreeItemAccessibleBase* treeItem = mAccessibleCache.GetWeak(key);

    if (treeItem) {
      RefPtr<AccEvent> event =
          new AccEvent(nsIAccessibleEvent::EVENT_HIDE, treeItem);
      nsEventShell::FireEvent(event);

      // Unbind from document, shutdown and remove from tree cache.
      document->UnbindFromDocument(treeItem);
      mAccessibleCache.Remove(key);
    }
  }

  // We dealt with removed tree items already however we may keep tree items
  // having row indexes greater than row count. We should remove these dead tree
  // items silently from caches.
  int32_t newRowCount = 0;
  nsresult rv = mTreeView->GetRowCount(&newRowCount);
  if (NS_FAILED(rv)) return;

  int32_t oldRowCount = newRowCount - aCount;

  for (int32_t rowIdx = newRowCount; rowIdx < oldRowCount; ++rowIdx) {
    void* key = reinterpret_cast<void*>(intptr_t(rowIdx));
    XULTreeItemAccessibleBase* treeItem = mAccessibleCache.GetWeak(key);

    if (treeItem) {
      // Unbind from document, shutdown and remove from tree cache.
      document->UnbindFromDocument(treeItem);
      mAccessibleCache.Remove(key);
    }
  }
}

void XULTreeAccessible::TreeViewInvalidated(int32_t aStartRow, int32_t aEndRow,
                                            int32_t aStartCol,
                                            int32_t aEndCol) {
  if (IsDefunct()) return;

  if (!mTreeView) {
    UnbindCacheEntriesFromDocument(mAccessibleCache);
    return;
  }

  int32_t endRow = aEndRow;

  nsresult rv;
  if (endRow == -1) {
    int32_t rowCount = 0;
    rv = mTreeView->GetRowCount(&rowCount);
    if (NS_FAILED(rv)) return;

    endRow = rowCount - 1;
  }

  RefPtr<nsTreeColumns> treeColumns = mTree->GetColumns();
  if (!treeColumns) return;

  int32_t endCol = aEndCol;

  if (endCol == -1) {
    // We need to make sure to cast to int32_t before we do the subtraction, in
    // case the column count is 0.
    endCol = static_cast<int32_t>(treeColumns->Count()) - 1;
  }

  for (int32_t rowIdx = aStartRow; rowIdx <= endRow; ++rowIdx) {
    void* key = reinterpret_cast<void*>(intptr_t(rowIdx));
    XULTreeItemAccessibleBase* treeitemAcc = mAccessibleCache.GetWeak(key);

    if (treeitemAcc) {
      treeitemAcc->RowInvalidated(aStartCol, endCol);
    }
  }
}

void XULTreeAccessible::TreeViewChanged(nsITreeView* aView) {
  if (IsDefunct()) return;

  // Fire reorder event on tree accessible on accessible tree (do not fire
  // show/hide events on tree items because it can be expensive to fire them for
  // each tree item.
  RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(this);
  Document()->FireDelayedEvent(reorderEvent);

  // Clear cache.
  UnbindCacheEntriesFromDocument(mAccessibleCache);

  mTreeView = aView;
  LocalAccessible* item = CurrentItem();
  if (item) {
    FocusMgr()->ActiveItemChanged(item, true);
  }
}

////////////////////////////////////////////////////////////////////////////////
// XULTreeAccessible: protected implementation

already_AddRefed<XULTreeItemAccessibleBase>
XULTreeAccessible::CreateTreeItemAccessible(int32_t aRow) const {
  RefPtr<XULTreeItemAccessibleBase> accessible = new XULTreeItemAccessible(
      mContent, mDoc, const_cast<XULTreeAccessible*>(this), mTree, mTreeView,
      aRow);

  return accessible.forget();
}

////////////////////////////////////////////////////////////////////////////////
// XULTreeItemAccessibleBase
////////////////////////////////////////////////////////////////////////////////

XULTreeItemAccessibleBase::XULTreeItemAccessibleBase(
    nsIContent* aContent, DocAccessible* aDoc, LocalAccessible* aParent,
    dom::XULTreeElement* aTree, nsITreeView* aTreeView, int32_t aRow)
    : AccessibleWrap(aContent, aDoc),
      mTree(aTree),
      mTreeView(aTreeView),
      mRow(aRow) {
  mParent = aParent;
  mStateFlags |= eSharedNode;
}

XULTreeItemAccessibleBase::~XULTreeItemAccessibleBase() {}

////////////////////////////////////////////////////////////////////////////////
// XULTreeItemAccessibleBase: nsISupports implementation

NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeItemAccessibleBase, LocalAccessible,
                                   mTree)

NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(XULTreeItemAccessibleBase,
                                               LocalAccessible)

////////////////////////////////////////////////////////////////////////////////
// XULTreeItemAccessibleBase: LocalAccessible

Accessible* XULTreeItemAccessibleBase::FocusedChild() {
  return FocusMgr()->FocusedLocalAccessible() == this ? this : nullptr;
}

nsIntRect XULTreeItemAccessibleBase::BoundsInCSSPixels() const {
  // Get x coordinate and width from treechildren element, get y coordinate and
  // height from tree cell.

  RefPtr<nsTreeColumn> column = nsCoreUtils::GetFirstSensibleColumn(mTree);

  nsresult rv;
  nsIntRect rect = mTree->GetCoordsForCellItem(mRow, column, u"cell"_ns, rv);
  if (NS_FAILED(rv)) {
    return nsIntRect();
  }

  RefPtr<dom::Element> bodyElement = mTree->GetTreeBody();
  if (!bodyElement || !bodyElement->IsXULElement()) {
    return nsIntRect();
  }

  rect.width = bodyElement->ClientWidth();

  nsIFrame* bodyFrame = bodyElement->GetPrimaryFrame();
  if (!bodyFrame) {
    return nsIntRect();
  }

  CSSIntRect screenRect = bodyFrame->GetScreenRect();
  rect.x = screenRect.x;
  rect.y += screenRect.y;
  return rect;
}

nsRect XULTreeItemAccessibleBase::BoundsInAppUnits() const {
  nsIntRect bounds = BoundsInCSSPixels();
  nsPresContext* presContext = mDoc->PresContext();
  return nsRect(presContext->CSSPixelsToAppUnits(bounds.X()),
                presContext->CSSPixelsToAppUnits(bounds.Y()),
                presContext->CSSPixelsToAppUnits(bounds.Width()),
                presContext->CSSPixelsToAppUnits(bounds.Height()));
}

void XULTreeItemAccessibleBase::SetSelected(bool aSelect) {
  nsCOMPtr<nsITreeSelection> selection;
  mTreeView->GetSelection(getter_AddRefs(selection));
  if (selection) {
    bool isSelected = false;
    selection->IsSelected(mRow, &isSelected);
    if (isSelected != aSelect) selection->ToggleSelect(mRow);
  }
}

void XULTreeItemAccessibleBase::TakeFocus() const {
  nsCOMPtr<nsITreeSelection> selection;
  mTreeView->GetSelection(getter_AddRefs(selection));
  if (selection) selection->SetCurrentIndex(mRow);

  // focus event will be fired here
  LocalAccessible::TakeFocus();
}

Relation XULTreeItemAccessibleBase::RelationByType(RelationType aType) const {
  switch (aType) {
    case RelationType::NODE_CHILD_OF: {
      int32_t parentIndex = -1;
      if (!NS_SUCCEEDED(mTreeView->GetParentIndex(mRow, &parentIndex))) {
        return Relation();
      }

      if (parentIndex == -1) return Relation(mParent);

      XULTreeAccessible* treeAcc = mParent->AsXULTree();
      return Relation(treeAcc->GetTreeItemAccessible(parentIndex));
    }

    case RelationType::NODE_PARENT_OF: {
      bool isTrue = false;
      if (NS_FAILED(mTreeView->IsContainerEmpty(mRow, &isTrue)) || isTrue) {
        return Relation();
      }

      if (NS_FAILED(mTreeView->IsContainerOpen(mRow, &isTrue)) || !isTrue) {
        return Relation();
      }

      XULTreeAccessible* tree = mParent->AsXULTree();
      return Relation(new XULTreeItemIterator(tree, mTreeView, mRow));
    }

    default:
      return Relation();
  }
}

bool XULTreeItemAccessibleBase::HasPrimaryAction() const { return true; }

uint8_t XULTreeItemAccessibleBase::ActionCount() const {
  // "activate" action is available for all treeitems, "expand/collapse" action
  // is avaible for treeitem which is container.
  return IsExpandable() ? 2 : 1;
}

void XULTreeItemAccessibleBase::ActionNameAt(uint8_t aIndex, nsAString& aName) {
  if (aIndex == eAction_Click) {
    aName.AssignLiteral("activate");
    return;
  }

  if (aIndex == eAction_Expand && IsExpandable()) {
    bool isContainerOpen = false;
    mTreeView->IsContainerOpen(mRow, &isContainerOpen);
    if (isContainerOpen) {
      aName.AssignLiteral("collapse");
    } else {
      aName.AssignLiteral("expand");
    }
  }
}

bool XULTreeItemAccessibleBase::DoAction(uint8_t aIndex) const {
  if (aIndex != eAction_Click &&
      (aIndex != eAction_Expand || !IsExpandable())) {
    return false;
  }

  DoCommand(aIndex);
  return true;
}

////////////////////////////////////////////////////////////////////////////////
// XULTreeItemAccessibleBase: LocalAccessible implementation

void XULTreeItemAccessibleBase::Shutdown() {
  mTree = nullptr;
  mTreeView = nullptr;
  mRow = -1;
  mParent = nullptr;  // null-out to prevent base class's shutdown ops

  AccessibleWrap::Shutdown();
}

GroupPos XULTreeItemAccessibleBase::GroupPosition() {
  GroupPos groupPos;

  int32_t level;
  nsresult rv = mTreeView->GetLevel(mRow, &level);
  NS_ENSURE_SUCCESS(rv, groupPos);

  int32_t topCount = 1;
  for (int32_t index = mRow - 1; index >= 0; index--) {
    int32_t lvl = -1;
    if (NS_SUCCEEDED(mTreeView->GetLevel(index, &lvl))) {
      if (lvl < level) break;

      if (lvl == level) topCount++;
    }
  }

  int32_t rowCount = 0;
  rv = mTreeView->GetRowCount(&rowCount);
  NS_ENSURE_SUCCESS(rv, groupPos);

  int32_t bottomCount = 0;
  for (int32_t index = mRow + 1; index < rowCount; index++) {
    int32_t lvl = -1;
    if (NS_SUCCEEDED(mTreeView->GetLevel(index, &lvl))) {
      if (lvl < level) break;

      if (lvl == level) bottomCount++;
    }
  }

  groupPos.level = level + 1;
  groupPos.setSize = topCount + bottomCount;
  groupPos.posInSet = topCount;

  return groupPos;
}

uint64_t XULTreeItemAccessibleBase::NativeState() const {
  // focusable and selectable states
  uint64_t state = NativeInteractiveState();

  // expanded/collapsed state
  if (IsExpandable()) {
    bool isContainerOpen;
    mTreeView->IsContainerOpen(mRow, &isContainerOpen);
    state |= isContainerOpen ? states::EXPANDED : states::COLLAPSED;
  }

  // selected state
  nsCOMPtr<nsITreeSelection> selection;
  mTreeView->GetSelection(getter_AddRefs(selection));
  if (selection) {
    bool isSelected;
    selection->IsSelected(mRow, &isSelected);
    if (isSelected) state |= states::SELECTED;
  }

  // focused state
  if (FocusMgr()->IsFocused(this)) state |= states::FOCUSED;

  // invisible state
  int32_t firstVisibleRow = mTree->GetFirstVisibleRow();
  int32_t lastVisibleRow = mTree->GetLastVisibleRow();
  if (mRow < firstVisibleRow || mRow > lastVisibleRow) {
    state |= states::INVISIBLE;
  }

  return state;
}

uint64_t XULTreeItemAccessibleBase::NativeInteractiveState() const {
  return states::FOCUSABLE | states::SELECTABLE;
}

int32_t XULTreeItemAccessibleBase::IndexInParent() const {
  return mParent ? mParent->ContentChildCount() + mRow : -1;
}

////////////////////////////////////////////////////////////////////////////////
// XULTreeItemAccessibleBase: Widgets

LocalAccessible* XULTreeItemAccessibleBase::ContainerWidget() const {
  return mParent;
}

////////////////////////////////////////////////////////////////////////////////
// XULTreeItemAccessibleBase: LocalAccessible protected methods

void XULTreeItemAccessibleBase::DispatchClickEvent(
    uint32_t aActionIndex) const {
  if (IsDefunct()) return;

  RefPtr<nsTreeColumns> columns = mTree->GetColumns();
  if (!columns) return;

  // Get column and pseudo element.
  RefPtr<nsTreeColumn> column;
  nsAutoString pseudoElm;

  if (aActionIndex == eAction_Click) {
    // Key column is visible and clickable.
    column = columns->GetKeyColumn();
  } else {
    // Primary column contains a twisty we should click on.
    column = columns->GetPrimaryColumn();
    pseudoElm = u"twisty"_ns;
  }

  if (column) {
    RefPtr<dom::XULTreeElement> tree = mTree;
    nsCoreUtils::DispatchClickEvent(tree, mRow, column, pseudoElm);
  }
}

LocalAccessible* XULTreeItemAccessibleBase::GetSiblingAtOffset(
    int32_t aOffset, nsresult* aError) const {
  if (aError) *aError = NS_OK;  // fail peacefully

  return mParent->LocalChildAt(IndexInParent() + aOffset);
}

////////////////////////////////////////////////////////////////////////////////
// XULTreeItemAccessibleBase: protected implementation

bool XULTreeItemAccessibleBase::IsExpandable() const {
  bool isContainer = false;
  mTreeView->IsContainer(mRow, &isContainer);
  if (isContainer) {
    bool isEmpty = false;
    mTreeView->IsContainerEmpty(mRow, &isEmpty);
    if (!isEmpty) {
      RefPtr<nsTreeColumns> columns = mTree->GetColumns();
      if (columns) {
        nsTreeColumn* primaryColumn = columns->GetPrimaryColumn();
        if (primaryColumn && !nsCoreUtils::IsColumnHidden(primaryColumn)) {
          return true;
        }
      }
    }
  }

  return false;
}

void XULTreeItemAccessibleBase::GetCellName(nsTreeColumn* aColumn,
                                            nsAString& aName) const {
  mTreeView->GetCellText(mRow, aColumn, aName);

  // If there is still no name try the cell value:
  // This is for graphical cells. We need tree/table view implementors to
  // implement FooView::GetCellValue to return a meaningful string for cases
  // where there is something shown in the cell (non-text) such as a star icon;
  // in which case GetCellValue for that cell would return "starred" or
  // "flagged" for example.
  if (aName.IsEmpty()) mTreeView->GetCellValue(mRow, aColumn, aName);
}

////////////////////////////////////////////////////////////////////////////////
// XULTreeItemAccessible
////////////////////////////////////////////////////////////////////////////////

XULTreeItemAccessible::XULTreeItemAccessible(
    nsIContent* aContent, DocAccessible* aDoc, LocalAccessible* aParent,
    dom::XULTreeElement* aTree, nsITreeView* aTreeView, int32_t aRow)
    : XULTreeItemAccessibleBase(aContent, aDoc, aParent, aTree, aTreeView,
                                aRow) {
  mStateFlags |= eNoKidsFromDOM;
  mColumn = nsCoreUtils::GetFirstSensibleColumn(mTree, FlushType::None);
  GetCellName(mColumn, mCachedName);
}

XULTreeItemAccessible::~XULTreeItemAccessible() {}

////////////////////////////////////////////////////////////////////////////////
// XULTreeItemAccessible: nsISupports implementation

NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeItemAccessible,
                                   XULTreeItemAccessibleBase, mColumn)

NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XULTreeItemAccessible)
NS_INTERFACE_MAP_END_INHERITING(XULTreeItemAccessibleBase)
NS_IMPL_ADDREF_INHERITED(XULTreeItemAccessible, XULTreeItemAccessibleBase)
NS_IMPL_RELEASE_INHERITED(XULTreeItemAccessible, XULTreeItemAccessibleBase)

////////////////////////////////////////////////////////////////////////////////
// XULTreeItemAccessible: nsIAccessible implementation

ENameValueFlag XULTreeItemAccessible::Name(nsString& aName) const {
  aName.Truncate();

  GetCellName(mColumn, aName);
  return eNameOK;
}

////////////////////////////////////////////////////////////////////////////////
// XULTreeItemAccessible: LocalAccessible implementation

void XULTreeItemAccessible::Shutdown() {
  mColumn = nullptr;
  XULTreeItemAccessibleBase::Shutdown();
}

role XULTreeItemAccessible::NativeRole() const {
  RefPtr<nsTreeColumns> columns = mTree->GetColumns();
  if (!columns) {
    NS_ERROR("No tree columns object in the tree!");
    return roles::NOTHING;
  }

  nsTreeColumn* primaryColumn = columns->GetPrimaryColumn();

  return primaryColumn ? roles::OUTLINEITEM : roles::LISTITEM;
}

////////////////////////////////////////////////////////////////////////////////
// XULTreeItemAccessible: XULTreeItemAccessibleBase implementation

void XULTreeItemAccessible::RowInvalidated(int32_t aStartColIdx,
                                           int32_t aEndColIdx) {
  nsAutoString name;
  Name(name);

  if (name != mCachedName) {
    nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this);
    mCachedName = name;
  }
}

////////////////////////////////////////////////////////////////////////////////
//  XULTreeColumAccessible
////////////////////////////////////////////////////////////////////////////////

XULTreeColumAccessible::XULTreeColumAccessible(nsIContent* aContent,
                                               DocAccessible* aDoc)
    : XULColumAccessible(aContent, aDoc) {}

LocalAccessible* XULTreeColumAccessible::GetSiblingAtOffset(
    int32_t aOffset, nsresult* aError) const {
  if (aOffset < 0) {
    return XULColumAccessible::GetSiblingAtOffset(aOffset, aError);
  }

  if (aError) *aError = NS_OK;  // fail peacefully

  RefPtr<dom::XULTreeElement> tree = nsCoreUtils::GetTree(mContent);
  if (tree) {
    nsCOMPtr<nsITreeView> treeView = tree->GetView(FlushType::None);
    if (treeView) {
      int32_t rowCount = 0;
      treeView->GetRowCount(&rowCount);
      if (rowCount > 0 && aOffset <= rowCount) {
        XULTreeAccessible* treeAcc = LocalParent()->AsXULTree();

        if (treeAcc) return treeAcc->GetTreeItemAccessible(aOffset - 1);
      }
    }
  }

  return nullptr;
}

Messung V0.5
C=91 H=96 G=93

¤ Dauer der Verarbeitung: 0.16 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge