diff -r 000000000000 -r 6474c204b198 accessible/src/xul/XULTreeGridAccessible.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/accessible/src/xul/XULTreeGridAccessible.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,865 @@ +/* -*- 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 "XULTreeGridAccessibleWrap.h" + +#include "nsAccCache.h" +#include "nsAccessibilityService.h" +#include "nsAccUtils.h" +#include "DocAccessible.h" +#include "nsEventShell.h" +#include "Relation.h" +#include "Role.h" +#include "States.h" + +#include "nsIBoxObject.h" +#include "nsIMutableArray.h" +#include "nsIPersistentProperties2.h" +#include "nsITreeSelection.h" +#include "nsComponentManagerUtils.h" + +using namespace mozilla::a11y; + +//////////////////////////////////////////////////////////////////////////////// +// XULTreeGridAccessible: nsISupports implementation + +NS_IMPL_ISUPPORTS_INHERITED(XULTreeGridAccessible, + XULTreeAccessible, + nsIAccessibleTable) + +//////////////////////////////////////////////////////////////////////////////// +// XULTreeGridAccessible: nsIAccessibleTable implementation + +uint32_t +XULTreeGridAccessible::ColCount() +{ + 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* 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++) { + Accessible* cell = CellAt(rowIdx, colIdx); + aCells->AppendElement(cell); + } + } + } +} + +void +XULTreeGridAccessible::SelectedCellIndices(nsTArray* 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* 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* aRows) +{ + uint32_t rowCount = RowCount(); + for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) + if (IsRowSelected(rowIdx)) + aRows->AppendElement(rowIdx); +} + +Accessible* +XULTreeGridAccessible::CellAt(uint32_t aRowIndex, uint32_t aColumnIndex) +{ + Accessible* row = GetTreeItemAccessible(aRowIndex); + if (!row) + return nullptr; + + nsCOMPtr column = + nsCoreUtils::GetSensibleColumnAt(mTree, aColumnIndex); + if (!column) + return nullptr; + + nsRefPtr rowAcc = do_QueryObject(row); + if (!rowAcc) + return nullptr; + + return rowAcc->GetCellAccessible(column); +} + +void +XULTreeGridAccessible::ColDescription(uint32_t aColIdx, nsString& aDescription) +{ + aDescription.Truncate(); + + nsCOMPtr treeColumns; + Accessible::GetFirstChild(getter_AddRefs(treeColumns)); + if (treeColumns) { + nsCOMPtr treeColumnItem; + treeColumns->GetChildAt(aColIdx, getter_AddRefs(treeColumnItem)); + if (treeColumnItem) + treeColumnItem->GetName(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 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); +} + +void +XULTreeGridAccessible::SelectRow(uint32_t aRowIdx) +{ + if (!mTreeView) + return; + + nsCOMPtr selection; + mTreeView->GetSelection(getter_AddRefs(selection)); + NS_ASSERTION(selection, "GetSelection() Shouldn't fail!"); + + selection->Select(aRowIdx); +} + +void +XULTreeGridAccessible::UnselectRow(uint32_t aRowIdx) +{ + if (!mTreeView) + return; + + nsCOMPtr selection; + mTreeView->GetSelection(getter_AddRefs(selection)); + + if (selection) + selection->ClearRange(aRowIdx, aRowIdx); +} + +//////////////////////////////////////////////////////////////////////////////// +// XULTreeGridAccessible: Accessible implementation + +void +XULTreeGridAccessible::Shutdown() +{ + mTable = nullptr; + XULTreeAccessible::Shutdown(); +} + +role +XULTreeGridAccessible::NativeRole() +{ + nsCOMPtr treeColumns; + mTree->GetColumns(getter_AddRefs(treeColumns)); + if (!treeColumns) { + NS_ERROR("No treecolumns object for tree!"); + return roles::NOTHING; + } + + nsCOMPtr primaryColumn; + treeColumns->GetPrimaryColumn(getter_AddRefs(primaryColumn)); + + return primaryColumn ? roles::TREE_TABLE : roles::TABLE; +} + +//////////////////////////////////////////////////////////////////////////////// +// XULTreeGridAccessible: XULTreeAccessible implementation + +already_AddRefed +XULTreeGridAccessible::CreateTreeItemAccessible(int32_t aRow) const +{ + nsRefPtr accessible = + new XULTreeGridRowAccessible(mContent, mDoc, + const_cast(this), + mTree, mTreeView, aRow); + + return accessible.forget(); +} + + +//////////////////////////////////////////////////////////////////////////////// +// XULTreeGridRowAccessible +//////////////////////////////////////////////////////////////////////////////// + +XULTreeGridRowAccessible:: + XULTreeGridRowAccessible(nsIContent* aContent, DocAccessible* aDoc, + Accessible* aTreeAcc, nsITreeBoxObject* aTree, + nsITreeView* aTreeView, int32_t aRow) : + XULTreeItemAccessibleBase(aContent, aDoc, aTreeAcc, aTree, aTreeView, aRow), + mAccessibleCache(kDefaultTreeCacheSize) +{ + mGenericTypes |= eTableRow; +} + +//////////////////////////////////////////////////////////////////////////////// +// XULTreeGridRowAccessible: nsISupports and cycle collection implementation + +NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeGridRowAccessible, + XULTreeItemAccessibleBase, + mAccessibleCache) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(XULTreeGridRowAccessible) +NS_INTERFACE_MAP_END_INHERITING(XULTreeItemAccessibleBase) + +NS_IMPL_ADDREF_INHERITED(XULTreeGridRowAccessible, + XULTreeItemAccessibleBase) +NS_IMPL_RELEASE_INHERITED(XULTreeGridRowAccessible, + XULTreeItemAccessibleBase) + +//////////////////////////////////////////////////////////////////////////////// +// XULTreeGridRowAccessible: Accessible implementation + +void +XULTreeGridRowAccessible::Shutdown() +{ + ClearCache(mAccessibleCache); + XULTreeItemAccessibleBase::Shutdown(); +} + +role +XULTreeGridRowAccessible::NativeRole() +{ + return roles::ROW; +} + +ENameValueFlag +XULTreeGridRowAccessible::Name(nsString& aName) +{ + aName.Truncate(); + + // XXX: the row name sholdn't be a concatenation of cell names (bug 664384). + nsCOMPtr column = nsCoreUtils::GetFirstSensibleColumn(mTree); + while (column) { + if (!aName.IsEmpty()) + aName.AppendLiteral(" "); + + nsAutoString cellName; + GetCellName(column, cellName); + aName.Append(cellName); + + column = nsCoreUtils::GetNextSensibleColumn(column); + } + + return eNameOK; +} + +Accessible* +XULTreeGridRowAccessible::ChildAtPoint(int32_t aX, int32_t aY, + EWhichChildAtPoint aWhichChild) +{ + nsIFrame *frame = GetFrame(); + if (!frame) + return nullptr; + + nsPresContext *presContext = frame->PresContext(); + nsIPresShell* presShell = presContext->PresShell(); + + nsIFrame *rootFrame = presShell->GetRootFrame(); + NS_ENSURE_TRUE(rootFrame, nullptr); + + nsIntRect rootRect = rootFrame->GetScreenRect(); + + int32_t clientX = presContext->DevPixelsToIntCSSPixels(aX) - rootRect.x; + int32_t clientY = presContext->DevPixelsToIntCSSPixels(aY) - rootRect.y; + + int32_t row = -1; + nsCOMPtr column; + nsAutoCString childEltUnused; + mTree->GetCellAt(clientX, clientY, &row, getter_AddRefs(column), + childEltUnused); + + // Return if we failed to find tree cell in the row for the given point. + if (row != mRow || !column) + return nullptr; + + return GetCellAccessible(column); +} + +Accessible* +XULTreeGridRowAccessible::GetChildAt(uint32_t aIndex) const +{ + if (IsDefunct()) + return nullptr; + + nsCOMPtr column = + nsCoreUtils::GetSensibleColumnAt(mTree, aIndex); + if (!column) + return nullptr; + + return GetCellAccessible(column); +} + +uint32_t +XULTreeGridRowAccessible::ChildCount() const +{ + return nsCoreUtils::GetSensibleColumnCount(mTree); +} + +//////////////////////////////////////////////////////////////////////////////// +// XULTreeGridRowAccessible: XULTreeItemAccessibleBase implementation + +Accessible* +XULTreeGridRowAccessible::GetCellAccessible(nsITreeColumn* aColumn) const +{ + NS_PRECONDITION(aColumn, "No tree column!"); + + void* key = static_cast(aColumn); + Accessible* cachedCell = mAccessibleCache.GetWeak(key); + if (cachedCell) + return cachedCell; + + nsRefPtr cell = + new XULTreeGridCellAccessibleWrap(mContent, mDoc, + const_cast(this), + mTree, mTreeView, mRow, aColumn); + mAccessibleCache.Put(key, cell); + Document()->BindToDocument(cell, nullptr); + return cell; +} + +void +XULTreeGridRowAccessible::RowInvalidated(int32_t aStartColIdx, + int32_t aEndColIdx) +{ + nsCOMPtr treeColumns; + mTree->GetColumns(getter_AddRefs(treeColumns)); + if (!treeColumns) + return; + + bool nameChanged = false; + for (int32_t colIdx = aStartColIdx; colIdx <= aEndColIdx; ++colIdx) { + nsCOMPtr column; + treeColumns->GetColumnAt(colIdx, getter_AddRefs(column)); + if (column && !nsCoreUtils::IsColumnHidden(column)) { + Accessible* cellAccessible = GetCellAccessible(column); + if (cellAccessible) { + nsRefPtr cellAcc = do_QueryObject(cellAccessible); + + nameChanged |= cellAcc->CellInvalidated(); + } + } + } + + if (nameChanged) + nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this); + +} + +//////////////////////////////////////////////////////////////////////////////// +// XULTreeGridRowAccessible: Accessible protected implementation + +void +XULTreeGridRowAccessible::CacheChildren() +{ +} + +//////////////////////////////////////////////////////////////////////////////// +// XULTreeGridCellAccessible +//////////////////////////////////////////////////////////////////////////////// + +XULTreeGridCellAccessible:: + XULTreeGridCellAccessible(nsIContent* aContent, DocAccessible* aDoc, + XULTreeGridRowAccessible* aRowAcc, + nsITreeBoxObject* aTree, nsITreeView* aTreeView, + int32_t aRow, nsITreeColumn* aColumn) : + LeafAccessible(aContent, aDoc), xpcAccessibleTableCell(this), mTree(aTree), + mTreeView(aTreeView), mRow(aRow), mColumn(aColumn) +{ + mParent = aRowAcc; + mStateFlags |= eSharedNode; + mGenericTypes |= eTableCell; + + NS_ASSERTION(mTreeView, "mTreeView is null"); + + int16_t type = -1; + mColumn->GetType(&type); + if (type == nsITreeColumn::TYPE_CHECKBOX) + mTreeView->GetCellValue(mRow, mColumn, mCachedTextEquiv); + else + mTreeView->GetCellText(mRow, mColumn, mCachedTextEquiv); +} + +//////////////////////////////////////////////////////////////////////////////// +// XULTreeGridCellAccessible: nsISupports implementation + +NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeGridCellAccessible, LeafAccessible, + mTree, mColumn) + +NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(XULTreeGridCellAccessible) + NS_INTERFACE_TABLE_INHERITED(XULTreeGridCellAccessible, + nsIAccessibleTableCell, + XULTreeGridCellAccessible) +NS_INTERFACE_TABLE_TAIL_INHERITING(LeafAccessible) +NS_IMPL_ADDREF_INHERITED(XULTreeGridCellAccessible, LeafAccessible) +NS_IMPL_RELEASE_INHERITED(XULTreeGridCellAccessible, LeafAccessible) + +//////////////////////////////////////////////////////////////////////////////// +// XULTreeGridCellAccessible: nsIAccessible implementation + +void +XULTreeGridCellAccessible::Shutdown() +{ + mTableCell = nullptr; + LeafAccessible::Shutdown(); +} + +Accessible* +XULTreeGridCellAccessible::FocusedChild() +{ + return nullptr; +} + +ENameValueFlag +XULTreeGridCellAccessible::Name(nsString& aName) +{ + 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; +} + +NS_IMETHODIMP +XULTreeGridCellAccessible::GetBounds(int32_t* aX, int32_t* aY, + int32_t* aWidth, int32_t* aHeight) +{ + NS_ENSURE_ARG_POINTER(aX); + *aX = 0; + NS_ENSURE_ARG_POINTER(aY); + *aY = 0; + NS_ENSURE_ARG_POINTER(aWidth); + *aWidth = 0; + NS_ENSURE_ARG_POINTER(aHeight); + *aHeight = 0; + + if (IsDefunct()) + return NS_ERROR_FAILURE; + + // Get bounds for tree cell and add x and y of treechildren element to + // x and y of the cell. + nsCOMPtr boxObj = nsCoreUtils::GetTreeBodyBoxObject(mTree); + NS_ENSURE_STATE(boxObj); + + int32_t x = 0, y = 0, width = 0, height = 0; + nsresult rv = mTree->GetCoordsForCellItem(mRow, mColumn, + NS_LITERAL_CSTRING("cell"), + &x, &y, &width, &height); + NS_ENSURE_SUCCESS(rv, rv); + + int32_t tcX = 0, tcY = 0; + boxObj->GetScreenX(&tcX); + boxObj->GetScreenY(&tcY); + x += tcX; + y += tcY; + + nsPresContext* presContext = mDoc->PresContext(); + *aX = presContext->CSSPixelsToDevPixels(x); + *aY = presContext->CSSPixelsToDevPixels(y); + *aWidth = presContext->CSSPixelsToDevPixels(width); + *aHeight = presContext->CSSPixelsToDevPixels(height); + + return NS_OK; +} + +uint8_t +XULTreeGridCellAccessible::ActionCount() +{ + bool isCycler = false; + mColumn->GetCycler(&isCycler); + if (isCycler) + return 1; + + int16_t type; + mColumn->GetType(&type); + if (type == nsITreeColumn::TYPE_CHECKBOX && IsEditable()) + return 1; + + return 0; +} + +NS_IMETHODIMP +XULTreeGridCellAccessible::GetActionName(uint8_t aIndex, nsAString& aName) +{ + aName.Truncate(); + + if (aIndex != eAction_Click) + return NS_ERROR_INVALID_ARG; + + if (IsDefunct() || !mTreeView) + return NS_ERROR_FAILURE; + + bool isCycler = false; + mColumn->GetCycler(&isCycler); + if (isCycler) { + aName.AssignLiteral("cycle"); + return NS_OK; + } + + int16_t type; + mColumn->GetType(&type); + if (type == nsITreeColumn::TYPE_CHECKBOX && IsEditable()) { + nsAutoString value; + mTreeView->GetCellValue(mRow, mColumn, value); + if (value.EqualsLiteral("true")) + aName.AssignLiteral("uncheck"); + else + aName.AssignLiteral("check"); + + return NS_OK; + } + + return NS_ERROR_INVALID_ARG; +} + +NS_IMETHODIMP +XULTreeGridCellAccessible::DoAction(uint8_t aIndex) +{ + if (aIndex != eAction_Click) + return NS_ERROR_INVALID_ARG; + + if (IsDefunct()) + return NS_ERROR_FAILURE; + + bool isCycler = false; + mColumn->GetCycler(&isCycler); + if (isCycler) { + DoCommand(); + return NS_OK; + } + + int16_t type; + mColumn->GetType(&type); + if (type == nsITreeColumn::TYPE_CHECKBOX && IsEditable()) { + DoCommand(); + return NS_OK; + } + + return NS_ERROR_INVALID_ARG; +} + +//////////////////////////////////////////////////////////////////////////////// +// XULTreeGridCellAccessible: nsIAccessibleTableCell implementation + +TableAccessible* +XULTreeGridCellAccessible::Table() const +{ + Accessible* grandParent = mParent->Parent(); + if (grandParent) + return grandParent->AsTable(); + + return nullptr; +} + +uint32_t +XULTreeGridCellAccessible::ColIdx() const +{ + uint32_t colIdx = 0; + nsCOMPtr column = mColumn; + while ((column = nsCoreUtils::GetPreviousSensibleColumn(column))) + colIdx++; + + return colIdx; +} + +uint32_t +XULTreeGridCellAccessible::RowIdx() const +{ + return mRow; +} + +void +XULTreeGridCellAccessible::ColHeaderCells(nsTArray* aHeaderCells) +{ + nsCOMPtr columnElm; + mColumn->GetElement(getter_AddRefs(columnElm)); + + nsCOMPtr columnContent(do_QueryInterface(columnElm)); + Accessible* headerCell = mDoc->GetAccessible(columnContent); + if (headerCell) + aHeaderCells->AppendElement(headerCell); +} + +bool +XULTreeGridCellAccessible::Selected() +{ + nsCOMPtr selection; + nsresult rv = mTreeView->GetSelection(getter_AddRefs(selection)); + NS_ENSURE_SUCCESS(rv, false); + + bool selected = false; + selection->IsSelected(mRow, &selected); + return selected; +} + +//////////////////////////////////////////////////////////////////////////////// +// XULTreeGridCellAccessible: Accessible public implementation + +already_AddRefed +XULTreeGridCellAccessible::NativeAttributes() +{ + nsCOMPtr attributes = + do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID); + + // "table-cell-index" attribute + TableAccessible* table = Table(); + if (!table) + return attributes.forget(); + + nsAutoString stringIdx; + stringIdx.AppendInt(table->CellIndexAt(mRow, ColIdx())); + nsAccUtils::SetAccAttr(attributes, nsGkAtoms::tableCellIndex, stringIdx); + + // "cycles" attribute + bool isCycler = false; + nsresult rv = mColumn->GetCycler(&isCycler); + if (NS_SUCCEEDED(rv) && isCycler) + nsAccUtils::SetAccAttr(attributes, nsGkAtoms::cycles, + NS_LITERAL_STRING("true")); + + return attributes.forget(); +} + +role +XULTreeGridCellAccessible::NativeRole() +{ + return roles::GRID_CELL; +} + +uint64_t +XULTreeGridCellAccessible::NativeState() +{ + if (!mTreeView) + return states::DEFUNCT; + + // selectable/selected state + uint64_t states = states::SELECTABLE; // keep in sync with NativeInteractiveState + + nsCOMPtr selection; + mTreeView->GetSelection(getter_AddRefs(selection)); + if (selection) { + bool isSelected = false; + selection->IsSelected(mRow, &isSelected); + if (isSelected) + states |= states::SELECTED; + } + + // checked state + int16_t type; + mColumn->GetType(&type); + if (type == nsITreeColumn::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) +{ + return Relation(); +} + +//////////////////////////////////////////////////////////////////////////////// +// XULTreeGridCellAccessible: public implementation + +bool +XULTreeGridCellAccessible::CellInvalidated() +{ + + nsAutoString textEquiv; + + int16_t type; + mColumn->GetType(&type); + if (type == nsITreeColumn::TYPE_CHECKBOX) { + mTreeView->GetCellValue(mRow, mColumn, textEquiv); + if (mCachedTextEquiv != textEquiv) { + bool isEnabled = textEquiv.EqualsLiteral("true"); + nsRefPtr 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: Accessible protected implementation + +Accessible* +XULTreeGridCellAccessible::GetSiblingAtOffset(int32_t aOffset, + nsresult* aError) const +{ + if (aError) + *aError = NS_OK; // fail peacefully + + nsCOMPtr 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; + + nsRefPtr rowAcc = do_QueryObject(Parent()); + return rowAcc->GetCellAccessible(columnAtOffset); +} + +void +XULTreeGridCellAccessible::DispatchClickEvent(nsIContent* aContent, + uint32_t aActionIndex) +{ + if (IsDefunct()) + return; + + nsCoreUtils::DispatchClickEvent(mTree, mRow, mColumn); +} + +//////////////////////////////////////////////////////////////////////////////// +// 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; + + nsCOMPtr columnElm; + mColumn->GetElement(getter_AddRefs(columnElm)); + if (!columnElm) + return false; + + nsCOMPtr columnContent(do_QueryInterface(columnElm)); + if (!columnContent->AttrValueIs(kNameSpaceID_None, + nsGkAtoms::editable, + nsGkAtoms::_true, + eCaseMatters)) + return false; + + return mContent->AttrValueIs(kNameSpaceID_None, + nsGkAtoms::editable, + nsGkAtoms::_true, eCaseMatters); +}