We never set this argument to anything other than the default, which meant it always used the LocalAccessible's mContent. This makes the argument unnecessary and potentially confusing in an area which is already a bit difficult to follow, so just remove it. There should be no functional change. Differential Revision: https://phabricator.services.mozilla.com/D229297
667 lines
21 KiB
C++
667 lines
21 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* 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 "XULTreeGridAccessible.h"
|
|
|
|
#include <stdint.h>
|
|
#include "AccAttributes.h"
|
|
#include "LocalAccessible-inl.h"
|
|
#include "nsAccCache.h"
|
|
#include "nsAccessibilityService.h"
|
|
#include "nsAccUtils.h"
|
|
#include "DocAccessible.h"
|
|
#include "nsEventShell.h"
|
|
#include "Relation.h"
|
|
#include "mozilla/a11y/Role.h"
|
|
#include "States.h"
|
|
#include "nsQueryObject.h"
|
|
#include "nsTreeColumns.h"
|
|
|
|
#include "nsITreeSelection.h"
|
|
#include "nsComponentManagerUtils.h"
|
|
#include "mozilla/PresShell.h"
|
|
#include "mozilla/a11y/TableAccessible.h"
|
|
#include "mozilla/dom/Element.h"
|
|
#include "mozilla/dom/TreeColumnBinding.h"
|
|
#include "mozilla/dom/XULTreeElementBinding.h"
|
|
|
|
using namespace mozilla::a11y;
|
|
using namespace mozilla;
|
|
|
|
XULTreeGridAccessible::~XULTreeGridAccessible() {}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// XULTreeGridAccessible: Table
|
|
|
|
uint32_t XULTreeGridAccessible::ColCount() const {
|
|
return nsCoreUtils::GetSensibleColumnCount(mTree);
|
|
}
|
|
|
|
uint32_t XULTreeGridAccessible::RowCount() {
|
|
if (!mTreeView) return 0;
|
|
|
|
int32_t rowCount = 0;
|
|
mTreeView->GetRowCount(&rowCount);
|
|
return rowCount >= 0 ? rowCount : 0;
|
|
}
|
|
|
|
uint32_t XULTreeGridAccessible::SelectedCellCount() {
|
|
return SelectedRowCount() * ColCount();
|
|
}
|
|
|
|
uint32_t XULTreeGridAccessible::SelectedColCount() {
|
|
// If all the row has been selected, then all the columns are selected,
|
|
// because we can't select a column alone.
|
|
|
|
uint32_t selectedRowCount = SelectedItemCount();
|
|
return selectedRowCount > 0 && selectedRowCount == RowCount() ? ColCount()
|
|
: 0;
|
|
}
|
|
|
|
uint32_t XULTreeGridAccessible::SelectedRowCount() {
|
|
return SelectedItemCount();
|
|
}
|
|
|
|
void XULTreeGridAccessible::SelectedCells(nsTArray<Accessible*>* aCells) {
|
|
uint32_t colCount = ColCount(), rowCount = RowCount();
|
|
|
|
for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) {
|
|
if (IsRowSelected(rowIdx)) {
|
|
for (uint32_t colIdx = 0; colIdx < colCount; colIdx++) {
|
|
LocalAccessible* cell = CellAt(rowIdx, colIdx);
|
|
aCells->AppendElement(cell);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void XULTreeGridAccessible::SelectedCellIndices(nsTArray<uint32_t>* aCells) {
|
|
uint32_t colCount = ColCount(), rowCount = RowCount();
|
|
|
|
for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) {
|
|
if (IsRowSelected(rowIdx)) {
|
|
for (uint32_t colIdx = 0; colIdx < colCount; colIdx++) {
|
|
aCells->AppendElement(rowIdx * colCount + colIdx);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void XULTreeGridAccessible::SelectedColIndices(nsTArray<uint32_t>* aCols) {
|
|
if (RowCount() != SelectedRowCount()) return;
|
|
|
|
uint32_t colCount = ColCount();
|
|
aCols->SetCapacity(colCount);
|
|
for (uint32_t colIdx = 0; colIdx < colCount; colIdx++) {
|
|
aCols->AppendElement(colIdx);
|
|
}
|
|
}
|
|
|
|
void XULTreeGridAccessible::SelectedRowIndices(nsTArray<uint32_t>* aRows) {
|
|
uint32_t rowCount = RowCount();
|
|
for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) {
|
|
if (IsRowSelected(rowIdx)) aRows->AppendElement(rowIdx);
|
|
}
|
|
}
|
|
|
|
LocalAccessible* XULTreeGridAccessible::CellAt(uint32_t aRowIndex,
|
|
uint32_t aColumnIndex) {
|
|
XULTreeItemAccessibleBase* rowAcc = GetTreeItemAccessible(aRowIndex);
|
|
if (!rowAcc) return nullptr;
|
|
|
|
RefPtr<nsTreeColumn> column =
|
|
nsCoreUtils::GetSensibleColumnAt(mTree, aColumnIndex);
|
|
if (!column) return nullptr;
|
|
|
|
return rowAcc->GetCellAccessible(column);
|
|
}
|
|
|
|
void XULTreeGridAccessible::ColDescription(uint32_t aColIdx,
|
|
nsString& aDescription) {
|
|
aDescription.Truncate();
|
|
|
|
LocalAccessible* treeColumns = LocalAccessible::LocalChildAt(0);
|
|
if (treeColumns) {
|
|
LocalAccessible* treeColumnItem = treeColumns->LocalChildAt(aColIdx);
|
|
if (treeColumnItem) treeColumnItem->Name(aDescription);
|
|
}
|
|
}
|
|
|
|
bool XULTreeGridAccessible::IsColSelected(uint32_t aColIdx) {
|
|
// If all the row has been selected, then all the columns are selected.
|
|
// Because we can't select a column alone.
|
|
return SelectedItemCount() == RowCount();
|
|
}
|
|
|
|
bool XULTreeGridAccessible::IsRowSelected(uint32_t aRowIdx) {
|
|
if (!mTreeView) return false;
|
|
|
|
nsCOMPtr<nsITreeSelection> selection;
|
|
nsresult rv = mTreeView->GetSelection(getter_AddRefs(selection));
|
|
NS_ENSURE_SUCCESS(rv, false);
|
|
|
|
bool isSelected = false;
|
|
selection->IsSelected(aRowIdx, &isSelected);
|
|
return isSelected;
|
|
}
|
|
|
|
bool XULTreeGridAccessible::IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx) {
|
|
return IsRowSelected(aRowIdx);
|
|
}
|
|
|
|
int32_t XULTreeGridAccessible::ColIndexAt(uint32_t aCellIdx) {
|
|
uint32_t colCount = ColCount();
|
|
if (colCount < 1 || aCellIdx >= colCount * RowCount()) {
|
|
return -1; // Error: column count is 0 or index out of bounds.
|
|
}
|
|
|
|
return static_cast<int32_t>(aCellIdx % colCount);
|
|
}
|
|
|
|
int32_t XULTreeGridAccessible::RowIndexAt(uint32_t aCellIdx) {
|
|
uint32_t colCount = ColCount();
|
|
if (colCount < 1 || aCellIdx >= colCount * RowCount()) {
|
|
return -1; // Error: column count is 0 or index out of bounds.
|
|
}
|
|
|
|
return static_cast<int32_t>(aCellIdx / colCount);
|
|
}
|
|
|
|
void XULTreeGridAccessible::RowAndColIndicesAt(uint32_t aCellIdx,
|
|
int32_t* aRowIdx,
|
|
int32_t* aColIdx) {
|
|
uint32_t colCount = ColCount();
|
|
if (colCount < 1 || aCellIdx >= colCount * RowCount()) {
|
|
*aRowIdx = -1;
|
|
*aColIdx = -1;
|
|
return; // Error: column count is 0 or index out of bounds.
|
|
}
|
|
|
|
*aRowIdx = static_cast<int32_t>(aCellIdx / colCount);
|
|
*aColIdx = static_cast<int32_t>(aCellIdx % colCount);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// XULTreeGridAccessible: LocalAccessible implementation
|
|
|
|
role XULTreeGridAccessible::NativeRole() const {
|
|
RefPtr<nsTreeColumns> treeColumns = mTree->GetColumns(FlushType::None);
|
|
if (!treeColumns) {
|
|
NS_ERROR("No treecolumns object for tree!");
|
|
return roles::NOTHING;
|
|
}
|
|
|
|
nsTreeColumn* primaryColumn = treeColumns->GetPrimaryColumn();
|
|
|
|
return primaryColumn ? roles::TREE_TABLE : roles::TABLE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// XULTreeGridAccessible: XULTreeAccessible implementation
|
|
|
|
already_AddRefed<XULTreeItemAccessibleBase>
|
|
XULTreeGridAccessible::CreateTreeItemAccessible(int32_t aRow) const {
|
|
RefPtr<XULTreeItemAccessibleBase> accessible = new XULTreeGridRowAccessible(
|
|
mContent, mDoc, const_cast<XULTreeGridAccessible*>(this), mTree,
|
|
mTreeView, aRow);
|
|
|
|
return accessible.forget();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// XULTreeGridRowAccessible
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
XULTreeGridRowAccessible::XULTreeGridRowAccessible(
|
|
nsIContent* aContent, DocAccessible* aDoc, LocalAccessible* aTreeAcc,
|
|
dom::XULTreeElement* aTree, nsITreeView* aTreeView, int32_t aRow)
|
|
: XULTreeItemAccessibleBase(aContent, aDoc, aTreeAcc, aTree, aTreeView,
|
|
aRow),
|
|
mAccessibleCache(kDefaultTreeCacheLength) {
|
|
mGenericTypes |= eTableRow;
|
|
mStateFlags |= eNoKidsFromDOM;
|
|
}
|
|
|
|
XULTreeGridRowAccessible::~XULTreeGridRowAccessible() {}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// XULTreeGridRowAccessible: nsISupports and cycle collection implementation
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeGridRowAccessible,
|
|
XULTreeItemAccessibleBase, mAccessibleCache)
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XULTreeGridRowAccessible)
|
|
NS_INTERFACE_MAP_END_INHERITING(XULTreeItemAccessibleBase)
|
|
|
|
NS_IMPL_ADDREF_INHERITED(XULTreeGridRowAccessible, XULTreeItemAccessibleBase)
|
|
NS_IMPL_RELEASE_INHERITED(XULTreeGridRowAccessible, XULTreeItemAccessibleBase)
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// XULTreeGridRowAccessible: LocalAccessible implementation
|
|
|
|
void XULTreeGridRowAccessible::Shutdown() {
|
|
if (mDoc && !mDoc->IsDefunct()) {
|
|
UnbindCacheEntriesFromDocument(mAccessibleCache);
|
|
}
|
|
|
|
XULTreeItemAccessibleBase::Shutdown();
|
|
}
|
|
|
|
role XULTreeGridRowAccessible::NativeRole() const { return roles::ROW; }
|
|
|
|
ENameValueFlag XULTreeGridRowAccessible::Name(nsString& aName) const {
|
|
aName.Truncate();
|
|
|
|
// XXX: the row name sholdn't be a concatenation of cell names (bug 664384).
|
|
RefPtr<nsTreeColumn> column = nsCoreUtils::GetFirstSensibleColumn(mTree);
|
|
while (column) {
|
|
if (!aName.IsEmpty()) aName.Append(' ');
|
|
|
|
nsAutoString cellName;
|
|
GetCellName(column, cellName);
|
|
aName.Append(cellName);
|
|
|
|
column = nsCoreUtils::GetNextSensibleColumn(column);
|
|
}
|
|
|
|
return eNameOK;
|
|
}
|
|
|
|
LocalAccessible* XULTreeGridRowAccessible::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);
|
|
|
|
// Return if we failed to find tree cell in the row for the given point.
|
|
if (cellInfo.mRow != mRow || !cellInfo.mCol) return nullptr;
|
|
|
|
return GetCellAccessible(cellInfo.mCol);
|
|
}
|
|
|
|
LocalAccessible* XULTreeGridRowAccessible::LocalChildAt(uint32_t aIndex) const {
|
|
if (IsDefunct()) return nullptr;
|
|
|
|
RefPtr<nsTreeColumn> column = nsCoreUtils::GetSensibleColumnAt(mTree, aIndex);
|
|
if (!column) return nullptr;
|
|
|
|
return GetCellAccessible(column);
|
|
}
|
|
|
|
uint32_t XULTreeGridRowAccessible::ChildCount() const {
|
|
return nsCoreUtils::GetSensibleColumnCount(mTree);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// XULTreeGridRowAccessible: XULTreeItemAccessibleBase implementation
|
|
|
|
XULTreeGridCellAccessible* XULTreeGridRowAccessible::GetCellAccessible(
|
|
nsTreeColumn* aColumn) const {
|
|
MOZ_ASSERT(aColumn, "No tree column!");
|
|
|
|
void* key = static_cast<void*>(aColumn);
|
|
XULTreeGridCellAccessible* cachedCell = mAccessibleCache.GetWeak(key);
|
|
if (cachedCell) return cachedCell;
|
|
|
|
RefPtr<XULTreeGridCellAccessible> cell = new XULTreeGridCellAccessible(
|
|
mContent, mDoc, const_cast<XULTreeGridRowAccessible*>(this), mTree,
|
|
mTreeView, mRow, aColumn);
|
|
mAccessibleCache.InsertOrUpdate(key, RefPtr{cell});
|
|
Document()->BindToDocument(cell, nullptr);
|
|
return cell;
|
|
}
|
|
|
|
void XULTreeGridRowAccessible::RowInvalidated(int32_t aStartColIdx,
|
|
int32_t aEndColIdx) {
|
|
RefPtr<nsTreeColumns> treeColumns = mTree->GetColumns(FlushType::None);
|
|
if (!treeColumns) return;
|
|
|
|
bool nameChanged = false;
|
|
for (int32_t colIdx = aStartColIdx; colIdx <= aEndColIdx; ++colIdx) {
|
|
nsTreeColumn* column = treeColumns->GetColumnAt(colIdx);
|
|
if (column && !nsCoreUtils::IsColumnHidden(column)) {
|
|
XULTreeGridCellAccessible* cell = GetCellAccessible(column);
|
|
if (cell) nameChanged |= cell->CellInvalidated();
|
|
}
|
|
}
|
|
|
|
if (nameChanged) {
|
|
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// XULTreeGridCellAccessible
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
XULTreeGridCellAccessible::XULTreeGridCellAccessible(
|
|
nsIContent* aContent, DocAccessible* aDoc,
|
|
XULTreeGridRowAccessible* aRowAcc, dom::XULTreeElement* aTree,
|
|
nsITreeView* aTreeView, int32_t aRow, nsTreeColumn* aColumn)
|
|
: LeafAccessible(aContent, aDoc),
|
|
mTree(aTree),
|
|
mTreeView(aTreeView),
|
|
mRow(aRow),
|
|
mColumn(aColumn) {
|
|
mParent = aRowAcc;
|
|
mStateFlags |= eSharedNode;
|
|
mGenericTypes |= eTableCell;
|
|
|
|
NS_ASSERTION(mTreeView, "mTreeView is null");
|
|
|
|
if (mColumn->Type() == dom::TreeColumn_Binding::TYPE_CHECKBOX) {
|
|
mTreeView->GetCellValue(mRow, mColumn, mCachedTextEquiv);
|
|
} else {
|
|
mTreeView->GetCellText(mRow, mColumn, mCachedTextEquiv);
|
|
}
|
|
}
|
|
|
|
XULTreeGridCellAccessible::~XULTreeGridCellAccessible() {}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// XULTreeGridCellAccessible: nsISupports implementation
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeGridCellAccessible, LeafAccessible,
|
|
mTree, mColumn)
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XULTreeGridCellAccessible)
|
|
NS_INTERFACE_MAP_END_INHERITING(LeafAccessible)
|
|
NS_IMPL_ADDREF_INHERITED(XULTreeGridCellAccessible, LeafAccessible)
|
|
NS_IMPL_RELEASE_INHERITED(XULTreeGridCellAccessible, LeafAccessible)
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// XULTreeGridCellAccessible: LocalAccessible
|
|
|
|
void XULTreeGridCellAccessible::Shutdown() {
|
|
mTree = nullptr;
|
|
mTreeView = nullptr;
|
|
mRow = -1;
|
|
mColumn = nullptr;
|
|
mParent = nullptr; // null-out to prevent base class's shutdown ops
|
|
|
|
LeafAccessible::Shutdown();
|
|
}
|
|
|
|
Accessible* XULTreeGridCellAccessible::FocusedChild() { return nullptr; }
|
|
|
|
ENameValueFlag XULTreeGridCellAccessible::Name(nsString& aName) const {
|
|
aName.Truncate();
|
|
|
|
if (!mTreeView) return eNameOK;
|
|
|
|
mTreeView->GetCellText(mRow, mColumn, 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, mColumn, aName);
|
|
|
|
return eNameOK;
|
|
}
|
|
|
|
nsIntRect XULTreeGridCellAccessible::BoundsInCSSPixels() const {
|
|
// Get bounds for tree cell and add x and y of treechildren element to
|
|
// x and y of the cell.
|
|
nsresult rv;
|
|
nsIntRect rect = mTree->GetCoordsForCellItem(mRow, mColumn, u"cell"_ns, rv);
|
|
if (NS_FAILED(rv)) {
|
|
return nsIntRect();
|
|
}
|
|
|
|
RefPtr<dom::Element> bodyElement = mTree->GetTreeBody();
|
|
if (!bodyElement || !bodyElement->IsXULElement()) {
|
|
return nsIntRect();
|
|
}
|
|
|
|
nsIFrame* bodyFrame = bodyElement->GetPrimaryFrame();
|
|
if (!bodyFrame) {
|
|
return nsIntRect();
|
|
}
|
|
|
|
CSSIntRect screenRect = bodyFrame->GetScreenRect();
|
|
rect.x += screenRect.x;
|
|
rect.y += screenRect.y;
|
|
return rect;
|
|
}
|
|
|
|
nsRect XULTreeGridCellAccessible::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()));
|
|
}
|
|
|
|
bool XULTreeGridCellAccessible::HasPrimaryAction() const {
|
|
return mColumn->Cycler() ||
|
|
(mColumn->Type() == dom::TreeColumn_Binding::TYPE_CHECKBOX &&
|
|
IsEditable());
|
|
}
|
|
|
|
void XULTreeGridCellAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName) {
|
|
aName.Truncate();
|
|
|
|
if (aIndex != eAction_Click || !mTreeView) return;
|
|
|
|
if (mColumn->Cycler()) {
|
|
aName.AssignLiteral("cycle");
|
|
return;
|
|
}
|
|
|
|
if (mColumn->Type() == dom::TreeColumn_Binding::TYPE_CHECKBOX &&
|
|
IsEditable()) {
|
|
nsAutoString value;
|
|
mTreeView->GetCellValue(mRow, mColumn, value);
|
|
if (value.EqualsLiteral("true")) {
|
|
aName.AssignLiteral("uncheck");
|
|
} else {
|
|
aName.AssignLiteral("check");
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// XULTreeGridCellAccessible: TableCell
|
|
|
|
TableAccessible* XULTreeGridCellAccessible::Table() const {
|
|
LocalAccessible* grandParent = mParent->LocalParent();
|
|
if (grandParent) return grandParent->AsTable();
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
uint32_t XULTreeGridCellAccessible::ColIdx() const {
|
|
uint32_t colIdx = 0;
|
|
RefPtr<nsTreeColumn> column = mColumn;
|
|
while ((column = nsCoreUtils::GetPreviousSensibleColumn(column))) colIdx++;
|
|
|
|
return colIdx;
|
|
}
|
|
|
|
uint32_t XULTreeGridCellAccessible::RowIdx() const { return mRow; }
|
|
|
|
void XULTreeGridCellAccessible::ColHeaderCells(
|
|
nsTArray<Accessible*>* aHeaderCells) {
|
|
dom::Element* columnElm = mColumn->Element();
|
|
|
|
LocalAccessible* headerCell = mDoc->GetAccessible(columnElm);
|
|
if (headerCell) aHeaderCells->AppendElement(headerCell);
|
|
}
|
|
|
|
bool XULTreeGridCellAccessible::Selected() {
|
|
nsCOMPtr<nsITreeSelection> selection;
|
|
nsresult rv = mTreeView->GetSelection(getter_AddRefs(selection));
|
|
NS_ENSURE_SUCCESS(rv, false);
|
|
|
|
bool selected = false;
|
|
selection->IsSelected(mRow, &selected);
|
|
return selected;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// XULTreeGridCellAccessible: LocalAccessible public implementation
|
|
|
|
already_AddRefed<AccAttributes> XULTreeGridCellAccessible::NativeAttributes() {
|
|
RefPtr<AccAttributes> attributes = new AccAttributes();
|
|
|
|
// "table-cell-index" attribute
|
|
TableAccessible* table = Table();
|
|
if (!table) return attributes.forget();
|
|
|
|
attributes->SetAttribute(nsGkAtoms::tableCellIndex,
|
|
table->CellIndexAt(mRow, ColIdx()));
|
|
|
|
// "cycles" attribute
|
|
if (mColumn->Cycler()) {
|
|
attributes->SetAttribute(nsGkAtoms::cycles, true);
|
|
}
|
|
|
|
return attributes.forget();
|
|
}
|
|
|
|
role XULTreeGridCellAccessible::NativeRole() const { return roles::GRID_CELL; }
|
|
|
|
uint64_t XULTreeGridCellAccessible::NativeState() const {
|
|
if (!mTreeView) return states::DEFUNCT;
|
|
|
|
// selectable/selected state
|
|
uint64_t states =
|
|
states::SELECTABLE; // keep in sync with NativeInteractiveState
|
|
|
|
nsCOMPtr<nsITreeSelection> selection;
|
|
mTreeView->GetSelection(getter_AddRefs(selection));
|
|
if (selection) {
|
|
bool isSelected = false;
|
|
selection->IsSelected(mRow, &isSelected);
|
|
if (isSelected) states |= states::SELECTED;
|
|
}
|
|
|
|
// checked state
|
|
if (mColumn->Type() == dom::TreeColumn_Binding::TYPE_CHECKBOX) {
|
|
states |= states::CHECKABLE;
|
|
nsAutoString checked;
|
|
mTreeView->GetCellValue(mRow, mColumn, checked);
|
|
if (checked.EqualsIgnoreCase("true")) states |= states::CHECKED;
|
|
}
|
|
|
|
return states;
|
|
}
|
|
|
|
uint64_t XULTreeGridCellAccessible::NativeInteractiveState() const {
|
|
return states::SELECTABLE;
|
|
}
|
|
|
|
int32_t XULTreeGridCellAccessible::IndexInParent() const { return ColIdx(); }
|
|
|
|
Relation XULTreeGridCellAccessible::RelationByType(RelationType aType) const {
|
|
return Relation();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// XULTreeGridCellAccessible: public implementation
|
|
|
|
bool XULTreeGridCellAccessible::CellInvalidated() {
|
|
nsAutoString textEquiv;
|
|
|
|
if (mColumn->Type() == dom::TreeColumn_Binding::TYPE_CHECKBOX) {
|
|
mTreeView->GetCellValue(mRow, mColumn, textEquiv);
|
|
if (mCachedTextEquiv != textEquiv) {
|
|
bool isEnabled = textEquiv.EqualsLiteral("true");
|
|
RefPtr<AccEvent> accEvent =
|
|
new AccStateChangeEvent(this, states::CHECKED, isEnabled);
|
|
nsEventShell::FireEvent(accEvent);
|
|
|
|
mCachedTextEquiv = textEquiv;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
mTreeView->GetCellText(mRow, mColumn, textEquiv);
|
|
if (mCachedTextEquiv != textEquiv) {
|
|
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this);
|
|
mCachedTextEquiv = textEquiv;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// XULTreeGridCellAccessible: LocalAccessible protected implementation
|
|
|
|
LocalAccessible* XULTreeGridCellAccessible::GetSiblingAtOffset(
|
|
int32_t aOffset, nsresult* aError) const {
|
|
if (aError) *aError = NS_OK; // fail peacefully
|
|
|
|
RefPtr<nsTreeColumn> columnAtOffset(mColumn), column;
|
|
if (aOffset < 0) {
|
|
for (int32_t index = aOffset; index < 0 && columnAtOffset; index++) {
|
|
column = nsCoreUtils::GetPreviousSensibleColumn(columnAtOffset);
|
|
column.swap(columnAtOffset);
|
|
}
|
|
} else {
|
|
for (int32_t index = aOffset; index > 0 && columnAtOffset; index--) {
|
|
column = nsCoreUtils::GetNextSensibleColumn(columnAtOffset);
|
|
column.swap(columnAtOffset);
|
|
}
|
|
}
|
|
|
|
if (!columnAtOffset) return nullptr;
|
|
|
|
XULTreeItemAccessibleBase* rowAcc =
|
|
static_cast<XULTreeItemAccessibleBase*>(LocalParent());
|
|
return rowAcc->GetCellAccessible(columnAtOffset);
|
|
}
|
|
|
|
void XULTreeGridCellAccessible::DispatchClickEvent(
|
|
uint32_t aActionIndex) const {
|
|
if (IsDefunct()) return;
|
|
|
|
RefPtr<dom::XULTreeElement> tree = mTree;
|
|
RefPtr<nsTreeColumn> column = mColumn;
|
|
nsCoreUtils::DispatchClickEvent(tree, mRow, column);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// XULTreeGridCellAccessible: protected implementation
|
|
|
|
bool XULTreeGridCellAccessible::IsEditable() const {
|
|
// XXX: logic corresponds to tree.xml, it's preferable to have interface
|
|
// method to check it.
|
|
bool isEditable = false;
|
|
nsresult rv = mTreeView->IsEditable(mRow, mColumn, &isEditable);
|
|
if (NS_FAILED(rv) || !isEditable) return false;
|
|
|
|
dom::Element* columnElm = mColumn->Element();
|
|
|
|
if (!columnElm->AttrValueIs(kNameSpaceID_None, nsGkAtoms::editable,
|
|
nsGkAtoms::_true, eCaseMatters)) {
|
|
return false;
|
|
}
|
|
|
|
return mContent->AsElement()->AttrValueIs(
|
|
kNameSpaceID_None, nsGkAtoms::editable, nsGkAtoms::_true, eCaseMatters);
|
|
}
|