michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "XULTreeGridAccessibleWrap.h" michael@0: michael@0: #include "nsAccCache.h" michael@0: #include "nsAccessibilityService.h" michael@0: #include "nsAccUtils.h" michael@0: #include "DocAccessible.h" michael@0: #include "nsEventShell.h" michael@0: #include "Relation.h" michael@0: #include "Role.h" michael@0: #include "States.h" michael@0: michael@0: #include "nsIBoxObject.h" michael@0: #include "nsIMutableArray.h" michael@0: #include "nsIPersistentProperties2.h" michael@0: #include "nsITreeSelection.h" michael@0: #include "nsComponentManagerUtils.h" michael@0: michael@0: using namespace mozilla::a11y; michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // XULTreeGridAccessible: nsISupports implementation michael@0: michael@0: NS_IMPL_ISUPPORTS_INHERITED(XULTreeGridAccessible, michael@0: XULTreeAccessible, michael@0: nsIAccessibleTable) michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // XULTreeGridAccessible: nsIAccessibleTable implementation michael@0: michael@0: uint32_t michael@0: XULTreeGridAccessible::ColCount() michael@0: { michael@0: return nsCoreUtils::GetSensibleColumnCount(mTree); michael@0: } michael@0: michael@0: uint32_t michael@0: XULTreeGridAccessible::RowCount() michael@0: { michael@0: if (!mTreeView) michael@0: return 0; michael@0: michael@0: int32_t rowCount = 0; michael@0: mTreeView->GetRowCount(&rowCount); michael@0: return rowCount >= 0 ? rowCount : 0; michael@0: } michael@0: michael@0: uint32_t michael@0: XULTreeGridAccessible::SelectedCellCount() michael@0: { michael@0: return SelectedRowCount() * ColCount(); michael@0: } michael@0: michael@0: uint32_t michael@0: XULTreeGridAccessible::SelectedColCount() michael@0: { michael@0: // If all the row has been selected, then all the columns are selected, michael@0: // because we can't select a column alone. michael@0: michael@0: uint32_t selectedRowCount = SelectedItemCount(); michael@0: return selectedRowCount > 0 && selectedRowCount == RowCount() ? ColCount() : 0; michael@0: } michael@0: michael@0: uint32_t michael@0: XULTreeGridAccessible::SelectedRowCount() michael@0: { michael@0: return SelectedItemCount(); michael@0: } michael@0: michael@0: void michael@0: XULTreeGridAccessible::SelectedCells(nsTArray* aCells) michael@0: { michael@0: uint32_t colCount = ColCount(), rowCount = RowCount(); michael@0: michael@0: for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) { michael@0: if (IsRowSelected(rowIdx)) { michael@0: for (uint32_t colIdx = 0; colIdx < colCount; colIdx++) { michael@0: Accessible* cell = CellAt(rowIdx, colIdx); michael@0: aCells->AppendElement(cell); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: void michael@0: XULTreeGridAccessible::SelectedCellIndices(nsTArray* aCells) michael@0: { michael@0: uint32_t colCount = ColCount(), rowCount = RowCount(); michael@0: michael@0: for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) michael@0: if (IsRowSelected(rowIdx)) michael@0: for (uint32_t colIdx = 0; colIdx < colCount; colIdx++) michael@0: aCells->AppendElement(rowIdx * colCount + colIdx); michael@0: } michael@0: michael@0: void michael@0: XULTreeGridAccessible::SelectedColIndices(nsTArray* aCols) michael@0: { michael@0: if (RowCount() != SelectedRowCount()) michael@0: return; michael@0: michael@0: uint32_t colCount = ColCount(); michael@0: aCols->SetCapacity(colCount); michael@0: for (uint32_t colIdx = 0; colIdx < colCount; colIdx++) michael@0: aCols->AppendElement(colIdx); michael@0: } michael@0: michael@0: void michael@0: XULTreeGridAccessible::SelectedRowIndices(nsTArray* aRows) michael@0: { michael@0: uint32_t rowCount = RowCount(); michael@0: for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) michael@0: if (IsRowSelected(rowIdx)) michael@0: aRows->AppendElement(rowIdx); michael@0: } michael@0: michael@0: Accessible* michael@0: XULTreeGridAccessible::CellAt(uint32_t aRowIndex, uint32_t aColumnIndex) michael@0: { michael@0: Accessible* row = GetTreeItemAccessible(aRowIndex); michael@0: if (!row) michael@0: return nullptr; michael@0: michael@0: nsCOMPtr column = michael@0: nsCoreUtils::GetSensibleColumnAt(mTree, aColumnIndex); michael@0: if (!column) michael@0: return nullptr; michael@0: michael@0: nsRefPtr rowAcc = do_QueryObject(row); michael@0: if (!rowAcc) michael@0: return nullptr; michael@0: michael@0: return rowAcc->GetCellAccessible(column); michael@0: } michael@0: michael@0: void michael@0: XULTreeGridAccessible::ColDescription(uint32_t aColIdx, nsString& aDescription) michael@0: { michael@0: aDescription.Truncate(); michael@0: michael@0: nsCOMPtr treeColumns; michael@0: Accessible::GetFirstChild(getter_AddRefs(treeColumns)); michael@0: if (treeColumns) { michael@0: nsCOMPtr treeColumnItem; michael@0: treeColumns->GetChildAt(aColIdx, getter_AddRefs(treeColumnItem)); michael@0: if (treeColumnItem) michael@0: treeColumnItem->GetName(aDescription); michael@0: } michael@0: } michael@0: michael@0: bool michael@0: XULTreeGridAccessible::IsColSelected(uint32_t aColIdx) michael@0: { michael@0: // If all the row has been selected, then all the columns are selected. michael@0: // Because we can't select a column alone. michael@0: return SelectedItemCount() == RowCount(); michael@0: } michael@0: michael@0: bool michael@0: XULTreeGridAccessible::IsRowSelected(uint32_t aRowIdx) michael@0: { michael@0: if (!mTreeView) michael@0: return false; michael@0: michael@0: nsCOMPtr selection; michael@0: nsresult rv = mTreeView->GetSelection(getter_AddRefs(selection)); michael@0: NS_ENSURE_SUCCESS(rv, false); michael@0: michael@0: bool isSelected = false; michael@0: selection->IsSelected(aRowIdx, &isSelected); michael@0: return isSelected; michael@0: } michael@0: michael@0: bool michael@0: XULTreeGridAccessible::IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx) michael@0: { michael@0: return IsRowSelected(aRowIdx); michael@0: } michael@0: michael@0: void michael@0: XULTreeGridAccessible::SelectRow(uint32_t aRowIdx) michael@0: { michael@0: if (!mTreeView) michael@0: return; michael@0: michael@0: nsCOMPtr selection; michael@0: mTreeView->GetSelection(getter_AddRefs(selection)); michael@0: NS_ASSERTION(selection, "GetSelection() Shouldn't fail!"); michael@0: michael@0: selection->Select(aRowIdx); michael@0: } michael@0: michael@0: void michael@0: XULTreeGridAccessible::UnselectRow(uint32_t aRowIdx) michael@0: { michael@0: if (!mTreeView) michael@0: return; michael@0: michael@0: nsCOMPtr selection; michael@0: mTreeView->GetSelection(getter_AddRefs(selection)); michael@0: michael@0: if (selection) michael@0: selection->ClearRange(aRowIdx, aRowIdx); michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // XULTreeGridAccessible: Accessible implementation michael@0: michael@0: void michael@0: XULTreeGridAccessible::Shutdown() michael@0: { michael@0: mTable = nullptr; michael@0: XULTreeAccessible::Shutdown(); michael@0: } michael@0: michael@0: role michael@0: XULTreeGridAccessible::NativeRole() michael@0: { michael@0: nsCOMPtr treeColumns; michael@0: mTree->GetColumns(getter_AddRefs(treeColumns)); michael@0: if (!treeColumns) { michael@0: NS_ERROR("No treecolumns object for tree!"); michael@0: return roles::NOTHING; michael@0: } michael@0: michael@0: nsCOMPtr primaryColumn; michael@0: treeColumns->GetPrimaryColumn(getter_AddRefs(primaryColumn)); michael@0: michael@0: return primaryColumn ? roles::TREE_TABLE : roles::TABLE; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // XULTreeGridAccessible: XULTreeAccessible implementation michael@0: michael@0: already_AddRefed michael@0: XULTreeGridAccessible::CreateTreeItemAccessible(int32_t aRow) const michael@0: { michael@0: nsRefPtr accessible = michael@0: new XULTreeGridRowAccessible(mContent, mDoc, michael@0: const_cast(this), michael@0: mTree, mTreeView, aRow); michael@0: michael@0: return accessible.forget(); michael@0: } michael@0: michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // XULTreeGridRowAccessible michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: XULTreeGridRowAccessible:: michael@0: XULTreeGridRowAccessible(nsIContent* aContent, DocAccessible* aDoc, michael@0: Accessible* aTreeAcc, nsITreeBoxObject* aTree, michael@0: nsITreeView* aTreeView, int32_t aRow) : michael@0: XULTreeItemAccessibleBase(aContent, aDoc, aTreeAcc, aTree, aTreeView, aRow), michael@0: mAccessibleCache(kDefaultTreeCacheSize) michael@0: { michael@0: mGenericTypes |= eTableRow; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // XULTreeGridRowAccessible: nsISupports and cycle collection implementation michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeGridRowAccessible, michael@0: XULTreeItemAccessibleBase, michael@0: mAccessibleCache) michael@0: michael@0: NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(XULTreeGridRowAccessible) michael@0: NS_INTERFACE_MAP_END_INHERITING(XULTreeItemAccessibleBase) michael@0: michael@0: NS_IMPL_ADDREF_INHERITED(XULTreeGridRowAccessible, michael@0: XULTreeItemAccessibleBase) michael@0: NS_IMPL_RELEASE_INHERITED(XULTreeGridRowAccessible, michael@0: XULTreeItemAccessibleBase) michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // XULTreeGridRowAccessible: Accessible implementation michael@0: michael@0: void michael@0: XULTreeGridRowAccessible::Shutdown() michael@0: { michael@0: ClearCache(mAccessibleCache); michael@0: XULTreeItemAccessibleBase::Shutdown(); michael@0: } michael@0: michael@0: role michael@0: XULTreeGridRowAccessible::NativeRole() michael@0: { michael@0: return roles::ROW; michael@0: } michael@0: michael@0: ENameValueFlag michael@0: XULTreeGridRowAccessible::Name(nsString& aName) michael@0: { michael@0: aName.Truncate(); michael@0: michael@0: // XXX: the row name sholdn't be a concatenation of cell names (bug 664384). michael@0: nsCOMPtr column = nsCoreUtils::GetFirstSensibleColumn(mTree); michael@0: while (column) { michael@0: if (!aName.IsEmpty()) michael@0: aName.AppendLiteral(" "); michael@0: michael@0: nsAutoString cellName; michael@0: GetCellName(column, cellName); michael@0: aName.Append(cellName); michael@0: michael@0: column = nsCoreUtils::GetNextSensibleColumn(column); michael@0: } michael@0: michael@0: return eNameOK; michael@0: } michael@0: michael@0: Accessible* michael@0: XULTreeGridRowAccessible::ChildAtPoint(int32_t aX, int32_t aY, michael@0: EWhichChildAtPoint aWhichChild) michael@0: { michael@0: nsIFrame *frame = GetFrame(); michael@0: if (!frame) michael@0: return nullptr; michael@0: michael@0: nsPresContext *presContext = frame->PresContext(); michael@0: nsIPresShell* presShell = presContext->PresShell(); michael@0: michael@0: nsIFrame *rootFrame = presShell->GetRootFrame(); michael@0: NS_ENSURE_TRUE(rootFrame, nullptr); michael@0: michael@0: nsIntRect rootRect = rootFrame->GetScreenRect(); michael@0: michael@0: int32_t clientX = presContext->DevPixelsToIntCSSPixels(aX) - rootRect.x; michael@0: int32_t clientY = presContext->DevPixelsToIntCSSPixels(aY) - rootRect.y; michael@0: michael@0: int32_t row = -1; michael@0: nsCOMPtr column; michael@0: nsAutoCString childEltUnused; michael@0: mTree->GetCellAt(clientX, clientY, &row, getter_AddRefs(column), michael@0: childEltUnused); michael@0: michael@0: // Return if we failed to find tree cell in the row for the given point. michael@0: if (row != mRow || !column) michael@0: return nullptr; michael@0: michael@0: return GetCellAccessible(column); michael@0: } michael@0: michael@0: Accessible* michael@0: XULTreeGridRowAccessible::GetChildAt(uint32_t aIndex) const michael@0: { michael@0: if (IsDefunct()) michael@0: return nullptr; michael@0: michael@0: nsCOMPtr column = michael@0: nsCoreUtils::GetSensibleColumnAt(mTree, aIndex); michael@0: if (!column) michael@0: return nullptr; michael@0: michael@0: return GetCellAccessible(column); michael@0: } michael@0: michael@0: uint32_t michael@0: XULTreeGridRowAccessible::ChildCount() const michael@0: { michael@0: return nsCoreUtils::GetSensibleColumnCount(mTree); michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // XULTreeGridRowAccessible: XULTreeItemAccessibleBase implementation michael@0: michael@0: Accessible* michael@0: XULTreeGridRowAccessible::GetCellAccessible(nsITreeColumn* aColumn) const michael@0: { michael@0: NS_PRECONDITION(aColumn, "No tree column!"); michael@0: michael@0: void* key = static_cast(aColumn); michael@0: Accessible* cachedCell = mAccessibleCache.GetWeak(key); michael@0: if (cachedCell) michael@0: return cachedCell; michael@0: michael@0: nsRefPtr cell = michael@0: new XULTreeGridCellAccessibleWrap(mContent, mDoc, michael@0: const_cast(this), michael@0: mTree, mTreeView, mRow, aColumn); michael@0: mAccessibleCache.Put(key, cell); michael@0: Document()->BindToDocument(cell, nullptr); michael@0: return cell; michael@0: } michael@0: michael@0: void michael@0: XULTreeGridRowAccessible::RowInvalidated(int32_t aStartColIdx, michael@0: int32_t aEndColIdx) michael@0: { michael@0: nsCOMPtr treeColumns; michael@0: mTree->GetColumns(getter_AddRefs(treeColumns)); michael@0: if (!treeColumns) michael@0: return; michael@0: michael@0: bool nameChanged = false; michael@0: for (int32_t colIdx = aStartColIdx; colIdx <= aEndColIdx; ++colIdx) { michael@0: nsCOMPtr column; michael@0: treeColumns->GetColumnAt(colIdx, getter_AddRefs(column)); michael@0: if (column && !nsCoreUtils::IsColumnHidden(column)) { michael@0: Accessible* cellAccessible = GetCellAccessible(column); michael@0: if (cellAccessible) { michael@0: nsRefPtr cellAcc = do_QueryObject(cellAccessible); michael@0: michael@0: nameChanged |= cellAcc->CellInvalidated(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (nameChanged) michael@0: nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this); michael@0: michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // XULTreeGridRowAccessible: Accessible protected implementation michael@0: michael@0: void michael@0: XULTreeGridRowAccessible::CacheChildren() michael@0: { michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // XULTreeGridCellAccessible michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: XULTreeGridCellAccessible:: michael@0: XULTreeGridCellAccessible(nsIContent* aContent, DocAccessible* aDoc, michael@0: XULTreeGridRowAccessible* aRowAcc, michael@0: nsITreeBoxObject* aTree, nsITreeView* aTreeView, michael@0: int32_t aRow, nsITreeColumn* aColumn) : michael@0: LeafAccessible(aContent, aDoc), xpcAccessibleTableCell(this), mTree(aTree), michael@0: mTreeView(aTreeView), mRow(aRow), mColumn(aColumn) michael@0: { michael@0: mParent = aRowAcc; michael@0: mStateFlags |= eSharedNode; michael@0: mGenericTypes |= eTableCell; michael@0: michael@0: NS_ASSERTION(mTreeView, "mTreeView is null"); michael@0: michael@0: int16_t type = -1; michael@0: mColumn->GetType(&type); michael@0: if (type == nsITreeColumn::TYPE_CHECKBOX) michael@0: mTreeView->GetCellValue(mRow, mColumn, mCachedTextEquiv); michael@0: else michael@0: mTreeView->GetCellText(mRow, mColumn, mCachedTextEquiv); michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // XULTreeGridCellAccessible: nsISupports implementation michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeGridCellAccessible, LeafAccessible, michael@0: mTree, mColumn) michael@0: michael@0: NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(XULTreeGridCellAccessible) michael@0: NS_INTERFACE_TABLE_INHERITED(XULTreeGridCellAccessible, michael@0: nsIAccessibleTableCell, michael@0: XULTreeGridCellAccessible) michael@0: NS_INTERFACE_TABLE_TAIL_INHERITING(LeafAccessible) michael@0: NS_IMPL_ADDREF_INHERITED(XULTreeGridCellAccessible, LeafAccessible) michael@0: NS_IMPL_RELEASE_INHERITED(XULTreeGridCellAccessible, LeafAccessible) michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // XULTreeGridCellAccessible: nsIAccessible implementation michael@0: michael@0: void michael@0: XULTreeGridCellAccessible::Shutdown() michael@0: { michael@0: mTableCell = nullptr; michael@0: LeafAccessible::Shutdown(); michael@0: } michael@0: michael@0: Accessible* michael@0: XULTreeGridCellAccessible::FocusedChild() michael@0: { michael@0: return nullptr; michael@0: } michael@0: michael@0: ENameValueFlag michael@0: XULTreeGridCellAccessible::Name(nsString& aName) michael@0: { michael@0: aName.Truncate(); michael@0: michael@0: if (!mTreeView) michael@0: return eNameOK; michael@0: michael@0: mTreeView->GetCellText(mRow, mColumn, aName); michael@0: michael@0: // If there is still no name try the cell value: michael@0: // This is for graphical cells. We need tree/table view implementors to implement michael@0: // FooView::GetCellValue to return a meaningful string for cases where there is michael@0: // something shown in the cell (non-text) such as a star icon; in which case michael@0: // GetCellValue for that cell would return "starred" or "flagged" for example. michael@0: if (aName.IsEmpty()) michael@0: mTreeView->GetCellValue(mRow, mColumn, aName); michael@0: michael@0: return eNameOK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: XULTreeGridCellAccessible::GetBounds(int32_t* aX, int32_t* aY, michael@0: int32_t* aWidth, int32_t* aHeight) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aX); michael@0: *aX = 0; michael@0: NS_ENSURE_ARG_POINTER(aY); michael@0: *aY = 0; michael@0: NS_ENSURE_ARG_POINTER(aWidth); michael@0: *aWidth = 0; michael@0: NS_ENSURE_ARG_POINTER(aHeight); michael@0: *aHeight = 0; michael@0: michael@0: if (IsDefunct()) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: // Get bounds for tree cell and add x and y of treechildren element to michael@0: // x and y of the cell. michael@0: nsCOMPtr boxObj = nsCoreUtils::GetTreeBodyBoxObject(mTree); michael@0: NS_ENSURE_STATE(boxObj); michael@0: michael@0: int32_t x = 0, y = 0, width = 0, height = 0; michael@0: nsresult rv = mTree->GetCoordsForCellItem(mRow, mColumn, michael@0: NS_LITERAL_CSTRING("cell"), michael@0: &x, &y, &width, &height); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: int32_t tcX = 0, tcY = 0; michael@0: boxObj->GetScreenX(&tcX); michael@0: boxObj->GetScreenY(&tcY); michael@0: x += tcX; michael@0: y += tcY; michael@0: michael@0: nsPresContext* presContext = mDoc->PresContext(); michael@0: *aX = presContext->CSSPixelsToDevPixels(x); michael@0: *aY = presContext->CSSPixelsToDevPixels(y); michael@0: *aWidth = presContext->CSSPixelsToDevPixels(width); michael@0: *aHeight = presContext->CSSPixelsToDevPixels(height); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: uint8_t michael@0: XULTreeGridCellAccessible::ActionCount() michael@0: { michael@0: bool isCycler = false; michael@0: mColumn->GetCycler(&isCycler); michael@0: if (isCycler) michael@0: return 1; michael@0: michael@0: int16_t type; michael@0: mColumn->GetType(&type); michael@0: if (type == nsITreeColumn::TYPE_CHECKBOX && IsEditable()) michael@0: return 1; michael@0: michael@0: return 0; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: XULTreeGridCellAccessible::GetActionName(uint8_t aIndex, nsAString& aName) michael@0: { michael@0: aName.Truncate(); michael@0: michael@0: if (aIndex != eAction_Click) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: if (IsDefunct() || !mTreeView) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: bool isCycler = false; michael@0: mColumn->GetCycler(&isCycler); michael@0: if (isCycler) { michael@0: aName.AssignLiteral("cycle"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: int16_t type; michael@0: mColumn->GetType(&type); michael@0: if (type == nsITreeColumn::TYPE_CHECKBOX && IsEditable()) { michael@0: nsAutoString value; michael@0: mTreeView->GetCellValue(mRow, mColumn, value); michael@0: if (value.EqualsLiteral("true")) michael@0: aName.AssignLiteral("uncheck"); michael@0: else michael@0: aName.AssignLiteral("check"); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: return NS_ERROR_INVALID_ARG; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: XULTreeGridCellAccessible::DoAction(uint8_t aIndex) michael@0: { michael@0: if (aIndex != eAction_Click) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: if (IsDefunct()) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: bool isCycler = false; michael@0: mColumn->GetCycler(&isCycler); michael@0: if (isCycler) { michael@0: DoCommand(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: int16_t type; michael@0: mColumn->GetType(&type); michael@0: if (type == nsITreeColumn::TYPE_CHECKBOX && IsEditable()) { michael@0: DoCommand(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: return NS_ERROR_INVALID_ARG; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // XULTreeGridCellAccessible: nsIAccessibleTableCell implementation michael@0: michael@0: TableAccessible* michael@0: XULTreeGridCellAccessible::Table() const michael@0: { michael@0: Accessible* grandParent = mParent->Parent(); michael@0: if (grandParent) michael@0: return grandParent->AsTable(); michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: uint32_t michael@0: XULTreeGridCellAccessible::ColIdx() const michael@0: { michael@0: uint32_t colIdx = 0; michael@0: nsCOMPtr column = mColumn; michael@0: while ((column = nsCoreUtils::GetPreviousSensibleColumn(column))) michael@0: colIdx++; michael@0: michael@0: return colIdx; michael@0: } michael@0: michael@0: uint32_t michael@0: XULTreeGridCellAccessible::RowIdx() const michael@0: { michael@0: return mRow; michael@0: } michael@0: michael@0: void michael@0: XULTreeGridCellAccessible::ColHeaderCells(nsTArray* aHeaderCells) michael@0: { michael@0: nsCOMPtr columnElm; michael@0: mColumn->GetElement(getter_AddRefs(columnElm)); michael@0: michael@0: nsCOMPtr columnContent(do_QueryInterface(columnElm)); michael@0: Accessible* headerCell = mDoc->GetAccessible(columnContent); michael@0: if (headerCell) michael@0: aHeaderCells->AppendElement(headerCell); michael@0: } michael@0: michael@0: bool michael@0: XULTreeGridCellAccessible::Selected() michael@0: { michael@0: nsCOMPtr selection; michael@0: nsresult rv = mTreeView->GetSelection(getter_AddRefs(selection)); michael@0: NS_ENSURE_SUCCESS(rv, false); michael@0: michael@0: bool selected = false; michael@0: selection->IsSelected(mRow, &selected); michael@0: return selected; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // XULTreeGridCellAccessible: Accessible public implementation michael@0: michael@0: already_AddRefed michael@0: XULTreeGridCellAccessible::NativeAttributes() michael@0: { michael@0: nsCOMPtr attributes = michael@0: do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID); michael@0: michael@0: // "table-cell-index" attribute michael@0: TableAccessible* table = Table(); michael@0: if (!table) michael@0: return attributes.forget(); michael@0: michael@0: nsAutoString stringIdx; michael@0: stringIdx.AppendInt(table->CellIndexAt(mRow, ColIdx())); michael@0: nsAccUtils::SetAccAttr(attributes, nsGkAtoms::tableCellIndex, stringIdx); michael@0: michael@0: // "cycles" attribute michael@0: bool isCycler = false; michael@0: nsresult rv = mColumn->GetCycler(&isCycler); michael@0: if (NS_SUCCEEDED(rv) && isCycler) michael@0: nsAccUtils::SetAccAttr(attributes, nsGkAtoms::cycles, michael@0: NS_LITERAL_STRING("true")); michael@0: michael@0: return attributes.forget(); michael@0: } michael@0: michael@0: role michael@0: XULTreeGridCellAccessible::NativeRole() michael@0: { michael@0: return roles::GRID_CELL; michael@0: } michael@0: michael@0: uint64_t michael@0: XULTreeGridCellAccessible::NativeState() michael@0: { michael@0: if (!mTreeView) michael@0: return states::DEFUNCT; michael@0: michael@0: // selectable/selected state michael@0: uint64_t states = states::SELECTABLE; // keep in sync with NativeInteractiveState michael@0: michael@0: nsCOMPtr selection; michael@0: mTreeView->GetSelection(getter_AddRefs(selection)); michael@0: if (selection) { michael@0: bool isSelected = false; michael@0: selection->IsSelected(mRow, &isSelected); michael@0: if (isSelected) michael@0: states |= states::SELECTED; michael@0: } michael@0: michael@0: // checked state michael@0: int16_t type; michael@0: mColumn->GetType(&type); michael@0: if (type == nsITreeColumn::TYPE_CHECKBOX) { michael@0: states |= states::CHECKABLE; michael@0: nsAutoString checked; michael@0: mTreeView->GetCellValue(mRow, mColumn, checked); michael@0: if (checked.EqualsIgnoreCase("true")) michael@0: states |= states::CHECKED; michael@0: } michael@0: michael@0: return states; michael@0: } michael@0: michael@0: uint64_t michael@0: XULTreeGridCellAccessible::NativeInteractiveState() const michael@0: { michael@0: return states::SELECTABLE; michael@0: } michael@0: michael@0: int32_t michael@0: XULTreeGridCellAccessible::IndexInParent() const michael@0: { michael@0: return ColIdx(); michael@0: } michael@0: michael@0: Relation michael@0: XULTreeGridCellAccessible::RelationByType(RelationType aType) michael@0: { michael@0: return Relation(); michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // XULTreeGridCellAccessible: public implementation michael@0: michael@0: bool michael@0: XULTreeGridCellAccessible::CellInvalidated() michael@0: { michael@0: michael@0: nsAutoString textEquiv; michael@0: michael@0: int16_t type; michael@0: mColumn->GetType(&type); michael@0: if (type == nsITreeColumn::TYPE_CHECKBOX) { michael@0: mTreeView->GetCellValue(mRow, mColumn, textEquiv); michael@0: if (mCachedTextEquiv != textEquiv) { michael@0: bool isEnabled = textEquiv.EqualsLiteral("true"); michael@0: nsRefPtr accEvent = michael@0: new AccStateChangeEvent(this, states::CHECKED, isEnabled); michael@0: nsEventShell::FireEvent(accEvent); michael@0: michael@0: mCachedTextEquiv = textEquiv; michael@0: return true; michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: mTreeView->GetCellText(mRow, mColumn, textEquiv); michael@0: if (mCachedTextEquiv != textEquiv) { michael@0: nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this); michael@0: mCachedTextEquiv = textEquiv; michael@0: return true; michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // XULTreeGridCellAccessible: Accessible protected implementation michael@0: michael@0: Accessible* michael@0: XULTreeGridCellAccessible::GetSiblingAtOffset(int32_t aOffset, michael@0: nsresult* aError) const michael@0: { michael@0: if (aError) michael@0: *aError = NS_OK; // fail peacefully michael@0: michael@0: nsCOMPtr columnAtOffset(mColumn), column; michael@0: if (aOffset < 0) { michael@0: for (int32_t index = aOffset; index < 0 && columnAtOffset; index++) { michael@0: column = nsCoreUtils::GetPreviousSensibleColumn(columnAtOffset); michael@0: column.swap(columnAtOffset); michael@0: } michael@0: } else { michael@0: for (int32_t index = aOffset; index > 0 && columnAtOffset; index--) { michael@0: column = nsCoreUtils::GetNextSensibleColumn(columnAtOffset); michael@0: column.swap(columnAtOffset); michael@0: } michael@0: } michael@0: michael@0: if (!columnAtOffset) michael@0: return nullptr; michael@0: michael@0: nsRefPtr rowAcc = do_QueryObject(Parent()); michael@0: return rowAcc->GetCellAccessible(columnAtOffset); michael@0: } michael@0: michael@0: void michael@0: XULTreeGridCellAccessible::DispatchClickEvent(nsIContent* aContent, michael@0: uint32_t aActionIndex) michael@0: { michael@0: if (IsDefunct()) michael@0: return; michael@0: michael@0: nsCoreUtils::DispatchClickEvent(mTree, mRow, mColumn); michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // XULTreeGridCellAccessible: protected implementation michael@0: michael@0: bool michael@0: XULTreeGridCellAccessible::IsEditable() const michael@0: { michael@0: michael@0: // XXX: logic corresponds to tree.xml, it's preferable to have interface michael@0: // method to check it. michael@0: bool isEditable = false; michael@0: nsresult rv = mTreeView->IsEditable(mRow, mColumn, &isEditable); michael@0: if (NS_FAILED(rv) || !isEditable) michael@0: return false; michael@0: michael@0: nsCOMPtr columnElm; michael@0: mColumn->GetElement(getter_AddRefs(columnElm)); michael@0: if (!columnElm) michael@0: return false; michael@0: michael@0: nsCOMPtr columnContent(do_QueryInterface(columnElm)); michael@0: if (!columnContent->AttrValueIs(kNameSpaceID_None, michael@0: nsGkAtoms::editable, michael@0: nsGkAtoms::_true, michael@0: eCaseMatters)) michael@0: return false; michael@0: michael@0: return mContent->AttrValueIs(kNameSpaceID_None, michael@0: nsGkAtoms::editable, michael@0: nsGkAtoms::_true, eCaseMatters); michael@0: }