Bug 308564 - No accessibility events when data in a tree row changes, r=evan.yan, olli.pettay, sr=jonas, a=mtschrep

This commit is contained in:
surkov.alexander@gmail.com 2008-02-08 04:55:57 -08:00
parent 1c2d05fb8a
commit ebda15db4d
9 changed files with 380 additions and 52 deletions

View File

@ -19,6 +19,10 @@
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Louie Zhao <Louie.Zhao@sun.com> (original author)
* Alexander Surkov <surkov.alexander@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
@ -39,11 +43,11 @@
interface nsIAccessible;
/**
* A cross-platform interface that supports cache for tree item
* A private interface to operate with tree accessible.
*
* @status UNDER_REVIEW
*/
[uuid(7cdad914-948b-4bbc-9c47-ee5e1ae6b148)]
[uuid(7e0f50b0-6444-4372-b00f-4ce81c6b058a)]
interface nsIAccessibleTreeCache : nsISupports
{
/**
@ -66,5 +70,26 @@ interface nsIAccessibleTreeCache : nsISupports
* inserted (plus) or removed (minus)
*/
void invalidateCache(in long aRow, in long aCount);
/**
* Fires name change events for invalidated area of tree.
*
* @param aStartRow row index invalidation starts from
* @param aEndRow row index invalidation ends, -1 means last row index
* @param aStartCol column index invalidation starts from
* @param aEndCol column index invalidation ends, -1 mens last column
* index
*/
void treeViewInvalidated(in long aStartRow, in long aEndRow,
in long aStartCol, in long aEndCol);
};
[uuid(b71532f9-53b2-4647-a5b2-1c5f57e9aed6)]
interface nsPIAccessibleTreeItem : nsISupports
{
/**
* Get/set cached name.
*/
attribute AString cachedName;
};

View File

@ -280,8 +280,6 @@ const char* const docEvents[] = {
"focus",
// capture Form change events
"select",
// capture NameChange events (fired whenever name changes, immediately after, whether focus moves or not)
"NameChange",
// capture ValueChange events (fired whenever value changes, immediately after, whether focus moves or not)
"ValueChange",
// capture AlertActive events (fired whenever alert pops up)
@ -289,6 +287,7 @@ const char* const docEvents[] = {
// add ourself as a TreeViewChanged listener (custom event fired in nsTreeBodyFrame.cpp)
"TreeViewChanged",
"TreeRowCountChanged",
"TreeInvalidated",
// add ourself as a OpenStateChange listener (custom event fired in tree.xml)
"OpenStateChange",
// add ourself as a CheckboxStateChange listener (custom event fired in nsHTMLInputElement.cpp)
@ -687,32 +686,11 @@ nsresult nsRootAccessible::HandleEventWithTarget(nsIDOMEvent* aEvent,
return NS_OK;
#ifdef MOZ_XUL
if (eventType.EqualsLiteral("TreeRowCountChanged")) {
if (!isTree)
return NS_OK;
nsCOMPtr<nsIDOMDataContainerEvent> dataEvent(do_QueryInterface(aEvent));
NS_ENSURE_STATE(dataEvent);
nsCOMPtr<nsIVariant> indexVariant;
dataEvent->GetData(NS_LITERAL_STRING("index"),
getter_AddRefs(indexVariant));
NS_ENSURE_STATE(indexVariant);
nsCOMPtr<nsIVariant> countVariant;
dataEvent->GetData(NS_LITERAL_STRING("count"),
getter_AddRefs(countVariant));
NS_ENSURE_STATE(countVariant);
PRInt32 index, count;
indexVariant->GetAsInt32(&index);
countVariant->GetAsInt32(&count);
nsCOMPtr<nsIAccessibleTreeCache> treeAccCache(do_QueryInterface(accessible));
NS_ENSURE_STATE(treeAccCache);
return treeAccCache->InvalidateCache(index, count);
}
if (eventType.EqualsLiteral("TreeRowCountChanged"))
return HandleTreeRowCountChangedEvent(aEvent, accessible, localName);
if (eventType.EqualsLiteral("TreeInvalidated"))
return HandleTreeInvalidatedEvent(aEvent, accessible, localName);
#endif
if (eventType.EqualsLiteral("RadioStateChange")) {
@ -852,9 +830,6 @@ nsresult nsRootAccessible::HandleEventWithTarget(nsIDOMEvent* aEvent,
}
FireAccessibleFocusEvent(accessible, focusedItem, aEvent);
}
else if (eventType.EqualsLiteral("NameChange")) {
nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, accessible);
}
else if (eventType.EqualsLiteral("AlertActive")) {
nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_ALERT, accessible);
}
@ -1104,3 +1079,82 @@ NS_IMETHODIMP nsRootAccessible::FireDocLoadEvents(PRUint32 aEventType)
return NS_OK;
}
nsresult
nsRootAccessible::HandleTreeRowCountChangedEvent(nsIDOMEvent *aEvent,
nsIAccessible *aAccessible,
const nsAString& aTargetName)
{
if (!aTargetName.EqualsLiteral("tree"))
return NS_OK;
nsCOMPtr<nsIDOMDataContainerEvent> dataEvent(do_QueryInterface(aEvent));
if (!dataEvent)
return NS_OK;
nsCOMPtr<nsIVariant> indexVariant;
dataEvent->GetData(NS_LITERAL_STRING("index"),
getter_AddRefs(indexVariant));
if (!indexVariant)
return NS_OK;
nsCOMPtr<nsIVariant> countVariant;
dataEvent->GetData(NS_LITERAL_STRING("count"),
getter_AddRefs(countVariant));
if (!countVariant)
return NS_OK;
PRInt32 index, count;
indexVariant->GetAsInt32(&index);
countVariant->GetAsInt32(&count);
nsCOMPtr<nsIAccessibleTreeCache> treeAccCache(do_QueryInterface(aAccessible));
NS_ENSURE_STATE(treeAccCache);
return treeAccCache->InvalidateCache(index, count);
}
nsresult
nsRootAccessible::HandleTreeInvalidatedEvent(nsIDOMEvent *aEvent,
nsIAccessible *aAccessible,
const nsAString& aTargetName)
{
if (!aTargetName.EqualsLiteral("tree"))
return NS_OK;
nsCOMPtr<nsIDOMDataContainerEvent> dataEvent(do_QueryInterface(aEvent));
if (!dataEvent)
return NS_OK;
PRInt32 startRow = 0, endRow = -1, startCol = 0, endCol = -1;
nsCOMPtr<nsIVariant> startRowVariant;
dataEvent->GetData(NS_LITERAL_STRING("startrow"),
getter_AddRefs(startRowVariant));
if (startRowVariant)
startRowVariant->GetAsInt32(&startRow);
nsCOMPtr<nsIVariant> endRowVariant;
dataEvent->GetData(NS_LITERAL_STRING("endrow"),
getter_AddRefs(endRowVariant));
if (endRowVariant)
endRowVariant->GetAsInt32(&endRow);
nsCOMPtr<nsIVariant> startColVariant;
dataEvent->GetData(NS_LITERAL_STRING("startcolumn"),
getter_AddRefs(startColVariant));
if (startColVariant)
startColVariant->GetAsInt32(&startCol);
nsCOMPtr<nsIVariant> endColVariant;
dataEvent->GetData(NS_LITERAL_STRING("endcolumn"),
getter_AddRefs(endColVariant));
if (endColVariant)
endColVariant->GetAsInt32(&endCol);
nsCOMPtr<nsIAccessibleTreeCache> treeAcc(do_QueryInterface(aAccessible));
NS_ENSURE_STATE(treeAcc);
return treeAcc->TreeViewInvalidated(startRow, endRow, startCol, endCol);
}

View File

@ -119,6 +119,21 @@ class nsRootAccessible : public nsDocAccessibleWrap,
void TryFireEarlyLoadEvent(nsIDOMNode *aDocNode);
void FireCurrentFocusEvent();
void GetChromeEventHandler(nsIDOMEventTarget **aChromeTarget);
/**
* Handles 'TreeRowCountChanged' event. Used in HandleEventWithTarget().
*/
nsresult HandleTreeRowCountChangedEvent(nsIDOMEvent *aEvent,
nsIAccessible *aAccessible,
const nsAString& aTargetName);
/**
* Handles 'TreeInvalidated' event. Used in HandleEventWithTarget().
*/
nsresult HandleTreeInvalidatedEvent(nsIDOMEvent *aEvent,
nsIAccessible *aAccessible,
const nsAString& aTargetName);
#ifdef MOZ_XUL
PRUint32 GetChromeFlags();
#endif

View File

@ -627,6 +627,84 @@ nsXULTreeAccessible::InvalidateCache(PRInt32 aRow, PRInt32 aCount)
return NS_OK;
}
// void nsIAccessibleTreeCache::
// treeViewInvalidated(in long aStartRow, in long aEndRow,
// in long aStartCol, in long aEndCol);
NS_IMETHODIMP
nsXULTreeAccessible::TreeViewInvalidated(PRInt32 aStartRow, PRInt32 aEndRow,
PRInt32 aStartCol, PRInt32 aEndCol)
{
NS_ENSURE_TRUE(mTree && mTreeView, NS_ERROR_FAILURE);
PRInt32 endRow = aEndRow, endCol = aEndCol;
nsresult rv;
if (endRow == -1) {
PRInt32 rowCount = 0;
rv = mTreeView->GetRowCount(&rowCount);
NS_ENSURE_SUCCESS(rv, rv);
endRow = rowCount - 1;
}
nsCOMPtr<nsITreeColumns> treeColumns;
mTree->GetColumns(getter_AddRefs(treeColumns));
NS_ENSURE_STATE(treeColumns);
#ifdef MOZ_ACCESSIBILITY_ATK
if (endCol == -1) {
PRInt32 colCount = 0;
rv = treeColumns->GetCount(&colCount);
NS_ENSURE_SUCCESS(rv, rv);
endCol = colCount - 1;
}
#else
nsCOMPtr<nsITreeColumn> col;
rv = treeColumns->GetKeyColumn(getter_AddRefs(col));
NS_ENSURE_SUCCESS(rv, rv);
PRInt32 colIdx = 0;
rv = col->GetIndex(&colIdx);
NS_ENSURE_SUCCESS(rv, rv);
#endif
for (PRInt32 rowIdx = aStartRow; rowIdx <= endRow; ++rowIdx) {
#ifdef MOZ_ACCESSIBILITY_ATK
for (PRInt32 colIdx = startCol; colIdx <= endCol; ++colIdx)
#endif
{
void *key = reinterpret_cast<void*>(rowIdx * kMaxTreeColumns + colIdx);
nsCOMPtr<nsIAccessNode> accessNode;
GetCacheEntry(*mAccessNodeCache, key, getter_AddRefs(accessNode));
if (accessNode) {
nsCOMPtr<nsIAccessible> acc(do_QueryInterface(accessNode));
NS_ENSURE_STATE(acc);
nsCOMPtr<nsPIAccessibleTreeItem> treeItemAcc(
do_QueryInterface(accessNode));
NS_ENSURE_STATE(treeItemAcc);
nsAutoString name, cachedName;
rv = acc->GetName(name);
NS_ENSURE_SUCCESS(rv, rv);
rv = treeItemAcc->GetCachedName(cachedName);
NS_ENSURE_SUCCESS(rv, rv);
if (name != cachedName) {
nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, acc);
treeItemAcc->SetCachedName(name);
}
}
}
}
return NS_OK;
}
nsresult nsXULTreeAccessible::GetColumnCount(nsITreeBoxObject* aBoxObject, PRInt32* aCount)
{
NS_ENSURE_TRUE(aBoxObject, NS_ERROR_FAILURE);
@ -660,7 +738,8 @@ nsXULTreeitemAccessible::nsXULTreeitemAccessible(nsIAccessible *aParent, nsIDOMN
}
}
NS_IMPL_ISUPPORTS_INHERITED0(nsXULTreeitemAccessible, nsLeafAccessible)
NS_IMPL_ISUPPORTS_INHERITED1(nsXULTreeitemAccessible, nsLeafAccessible,
nsPIAccessibleTreeItem);
NS_IMETHODIMP nsXULTreeitemAccessible::Shutdown()
{
@ -696,6 +775,16 @@ NS_IMETHODIMP nsXULTreeitemAccessible::GetUniqueID(void **aUniqueID)
return NS_OK;
}
// nsPIAccessNode::init()
NS_IMETHODIMP
nsXULTreeitemAccessible::Init()
{
nsresult rv = nsLeafAccessible::Init();
NS_ENSURE_SUCCESS(rv, rv);
return GetName(mCachedName);
}
NS_IMETHODIMP nsXULTreeitemAccessible::GetRole(PRUint32 *aRole)
{
PRInt32 colCount = 0;
@ -1175,6 +1264,22 @@ NS_IMETHODIMP nsXULTreeitemAccessible::GetAccessibleRelated(PRUint32 aRelationTy
#endif
}
// attribute AString nsIAccessibleTreeItem::cachedName
NS_IMETHODIMP
nsXULTreeitemAccessible::GetCachedName(nsAString &aName)
{
aName = mCachedName;
return NS_OK;
}
// attribute AString nsIAccessibleTreeItem::cachedName
NS_IMETHODIMP
nsXULTreeitemAccessible::SetCachedName(const nsAString &aName)
{
mCachedName = aName;
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// nsXULTreeColumnsAccessible
nsXULTreeColumnsAccessible::

View File

@ -93,19 +93,21 @@ protected:
/**
* Treeitems -- used in Trees
*/
class nsXULTreeitemAccessible : public nsLeafAccessible
class nsXULTreeitemAccessible : public nsLeafAccessible,
public nsPIAccessibleTreeItem
{
public:
enum { eAction_Click = 0, eAction_Expand = 1 };
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSPIACCESSIBLETREEITEM
nsXULTreeitemAccessible(nsIAccessible *aParent, nsIDOMNode *aDOMNode, nsIWeakReference *aShell, PRInt32 aRow, nsITreeColumn* aColumn = nsnull);
virtual ~nsXULTreeitemAccessible() {}
NS_IMETHOD Shutdown();
/* ----- nsIAccessible ----- */
// nsIAccessible
NS_IMETHOD GetName(nsAString& _retval);
NS_IMETHOD GetRole(PRUint32 *_retval);
NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
@ -123,9 +125,13 @@ public:
NS_IMETHOD TakeFocus(void);
NS_IMETHOD GetAccessibleRelated(PRUint32 aRelationType, nsIAccessible **aRelated);
/* ------ nsIAccessNode ----- */
// nsIAccessNode
NS_IMETHOD GetUniqueID(void **aUniqueID);
// nsPIAccessNode
NS_IMETHOD Init();
// nsAccessNode
virtual PRBool IsDefunct();
@ -135,6 +141,7 @@ protected:
nsCOMPtr<nsITreeView> mTreeView;
PRInt32 mRow;
nsCOMPtr<nsITreeColumn> mColumn;
nsString mCachedName;
};
class nsXULTreeColumnsAccessible : public nsXULColumnsAccessible

View File

@ -663,6 +663,12 @@ nsTreeBodyFrame::InvalidateColumn(nsITreeColumn* aCol)
if (!col)
return NS_ERROR_INVALID_ARG;
#ifdef ACCESSIBILITY
nsIPresShell *presShell = PresContext()->PresShell();
if (presShell->IsAccessibilityActive())
FireInvalidateEvent(-1, -1, aCol, aCol);
#endif
nsRect columnRect;
nsresult rv = col->GetRect(this, mInnerBox.y, mInnerBox.height, &columnRect);
NS_ENSURE_SUCCESS(rv, rv);
@ -696,6 +702,12 @@ nsTreeBodyFrame::InvalidateCell(PRInt32 aIndex, nsITreeColumn* aCol)
if (mUpdateBatchNest)
return NS_OK;
#ifdef ACCESSIBILITY
nsIPresShell *presShell = PresContext()->PresShell();
if (presShell->IsAccessibilityActive())
FireInvalidateEvent(aIndex, aIndex, aCol, aCol);
#endif
aIndex -= mTopRowIndex;
if (aIndex < 0 || aIndex > mPageLength)
return NS_OK;
@ -724,6 +736,12 @@ nsTreeBodyFrame::InvalidateRange(PRInt32 aStart, PRInt32 aEnd)
if (aStart == aEnd)
return InvalidateRow(aStart);
#ifdef ACCESSIBILITY
nsIPresShell *presShell = PresContext()->PresShell();
if (presShell->IsAccessibilityActive())
FireInvalidateEvent(aStart, aEnd, nsnull, nsnull);
#endif
PRInt32 last = GetLastVisibleRow();
if (aStart > aEnd || aEnd < mTopRowIndex || aStart > last)
return NS_OK;
@ -753,6 +771,12 @@ nsTreeBodyFrame::InvalidateColumnRange(PRInt32 aStart, PRInt32 aEnd, nsITreeColu
if (aStart == aEnd)
return InvalidateCell(aStart, col);
#ifdef ACCESSIBILITY
nsIPresShell *presShell = PresContext()->PresShell();
if (presShell->IsAccessibilityActive())
FireInvalidateEvent(aStart, aEnd, aCol, aCol);
#endif
PRInt32 last = GetLastVisibleRow();
if (aStart > aEnd || aEnd < mTopRowIndex || aStart > last)
return NS_OK;
@ -4363,6 +4387,7 @@ nsTreeBodyFrame::PostScrollEvent()
}
}
#ifdef ACCESSIBILITY
void
nsTreeBodyFrame::FireRowCountChangedEvent(PRInt32 aIndex, PRInt32 aCount)
{
@ -4382,12 +4407,12 @@ nsTreeBodyFrame::FireRowCountChangedEvent(PRInt32 aIndex, PRInt32 aCount)
domEventDoc->CreateEvent(NS_LITERAL_STRING("datacontainerevents"),
getter_AddRefs(event));
event->InitEvent(NS_LITERAL_STRING("TreeRowCountChanged"), PR_TRUE, PR_FALSE);
nsCOMPtr<nsIDOMDataContainerEvent> treeEvent(do_QueryInterface(event));
if (!treeEvent)
return;
event->InitEvent(NS_LITERAL_STRING("TreeRowCountChanged"), PR_TRUE, PR_FALSE);
// Set 'index' data - the row index rows are changed from.
nsCOMPtr<nsIWritableVariant> indexVariant(
do_CreateInstance("@mozilla.org/variant;1"));
@ -4420,6 +4445,96 @@ nsTreeBodyFrame::FireRowCountChangedEvent(PRInt32 aIndex, PRInt32 aCount)
plevent->PostDOMEvent();
}
void
nsTreeBodyFrame::FireInvalidateEvent(PRInt32 aStartRowIdx, PRInt32 aEndRowIdx,
nsITreeColumn *aStartCol,
nsITreeColumn *aEndCol)
{
nsCOMPtr<nsIContent> content(GetBaseElement());
if (!content)
return;
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(content));
nsCOMPtr<nsIDOMDocument> domDoc;
node->GetOwnerDocument(getter_AddRefs(domDoc));
nsCOMPtr<nsIDOMDocumentEvent> domEventDoc(do_QueryInterface(domDoc));
if (!domEventDoc)
return;
nsCOMPtr<nsIDOMEvent> event;
domEventDoc->CreateEvent(NS_LITERAL_STRING("datacontainerevents"),
getter_AddRefs(event));
nsCOMPtr<nsIDOMDataContainerEvent> treeEvent(do_QueryInterface(event));
if (!treeEvent)
return;
event->InitEvent(NS_LITERAL_STRING("TreeInvalidated"), PR_TRUE, PR_FALSE);
if (aStartRowIdx != -1 && aEndRowIdx != -1) {
// Set 'startrow' data - the start index of invalidated rows.
nsCOMPtr<nsIWritableVariant> startRowVariant(
do_CreateInstance("@mozilla.org/variant;1"));
if (!startRowVariant)
return;
startRowVariant->SetAsInt32(aStartRowIdx);
treeEvent->SetData(NS_LITERAL_STRING("startrow"), startRowVariant);
// Set 'endrow' data - the end index of invalidated rows.
nsCOMPtr<nsIWritableVariant> endRowVariant(
do_CreateInstance("@mozilla.org/variant;1"));
if (!endRowVariant)
return;
endRowVariant->SetAsInt32(aEndRowIdx);
treeEvent->SetData(NS_LITERAL_STRING("endrow"), endRowVariant);
}
if (aStartCol && aEndCol) {
// Set 'startcolumn' data - the start index of invalidated rows.
nsCOMPtr<nsIWritableVariant> startColVariant(
do_CreateInstance("@mozilla.org/variant;1"));
if (!startColVariant)
return;
PRInt32 startColIdx = 0;
nsresult rv = aStartCol->GetIndex(&startColIdx);
if (NS_FAILED(rv))
return;
startColVariant->SetAsInt32(startColIdx);
treeEvent->SetData(NS_LITERAL_STRING("column"), startColVariant);
// Set 'endcolumn' data - the start index of invalidated rows.
nsCOMPtr<nsIWritableVariant> endColVariant(
do_CreateInstance("@mozilla.org/variant;1"));
if (!endColVariant)
return;
PRInt32 endColIdx = 0;
rv = aEndCol->GetIndex(&endColIdx);
if (NS_FAILED(rv))
return;
endColVariant->SetAsInt32(endColIdx);
treeEvent->SetData(NS_LITERAL_STRING("columncount"), endColVariant);
}
// Fire an event.
nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
if (!privateEvent)
return;
privateEvent->SetTrusted(PR_TRUE);
nsRefPtr<nsPLDOMEvent> plevent = new nsPLDOMEvent(node, event);
if (plevent)
plevent->PostDOMEvent();
}
#endif
PRBool
nsTreeBodyFrame::FullScrollbarsUpdate(PRBool aNeedsFullInvalidation)
{

View File

@ -413,6 +413,7 @@ protected:
void PostScrollEvent();
void FireScrollEvent();
#ifdef ACCESSIBILITY
/**
* Fires 'treeRowCountChanged' event asynchronously. The event supports
* nsIDOMDataContainerEvent interface that is used to expose the following
@ -424,6 +425,24 @@ protected:
*/
void FireRowCountChangedEvent(PRInt32 aIndex, PRInt32 aCount);
/**
* Fires 'treeInvalidated' event asynchronously. The event supports
* nsIDOMDataContainerEvent interface that is used to expose the information
* structures described by method arguments.
*
* @param aStartRow the start index of invalidated rows, -1 means that
* columns have been invalidated only
* @param aEndRow the end index of invalidated rows, -1 means that columns
* have been invalidated only
* @param aStartCol the start invalidated column, nsnull means that only rows
* have been invalidated
* @param aEndCol the end invalidated column, nsnull means that rows have
* been invalidated only
*/
void FireInvalidateEvent(PRInt32 aStartRow, PRInt32 aEndRow,
nsITreeColumn *aStartCol, nsITreeColumn *aEndCol);
#endif
protected: // Data Members
// The cached box object parent.
nsCOMPtr<nsITreeBoxObject> mTreeBoxObject;

View File

@ -615,13 +615,7 @@ function ModifyPref(entry)
supportsString.data = result.value;
gPrefBranch.setComplexValue(entry.prefCol, nsISupportsString, supportsString);
}
gPrefService.savePrefFile(null);
// Fire event for accessibility
var event = document.createEvent('Events');
event.initEvent('NameChange', false, true);
document.getElementById("configTree").dispatchEvent(event);
gPrefService.savePrefFile(null);
return true;
}

View File

@ -614,11 +614,5 @@ function ModifyPref(entry)
}
gPrefService.savePrefFile(null);
// Fire event for accessibility
var event = document.createEvent('Events');
event.initEvent('NameChange', false, true);
document.getElementById("configTree").dispatchEvent(event);
return true;
}