Back to index

lightning-sunbird  0.9+nobinonly
nsXULTreeAccessible.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Author: Kyle Yuan (kyle.yuan@sun.com)
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsIBoxObject.h"
00040 #include "nsIDOMXULElement.h"
00041 #include "nsIDOMXULMultSelectCntrlEl.h"
00042 #include "nsITreeSelection.h"
00043 #include "nsITreeColumns.h"
00044 #include "nsXULTreeAccessibleWrap.h"
00045 #include "nsArray.h"
00046 
00047 #ifdef MOZ_ACCESSIBILITY_ATK
00048 #include "nsIAccessibleTable.h"
00049 #endif
00050 
00051 #define kMaxTreeColumns 100
00052 // ---------- nsXULTreeAccessible ----------
00053 
00054 nsXULTreeAccessible::nsXULTreeAccessible(nsIDOMNode *aDOMNode, nsIWeakReference *aShell):
00055 nsXULSelectableAccessible(aDOMNode, aShell),
00056 mAccessNodeCache(nsnull)
00057 
00058 {
00059   GetTreeBoxObject(aDOMNode, getter_AddRefs(mTree));
00060   if (mTree)
00061     mTree->GetView(getter_AddRefs(mTreeView));
00062   NS_ASSERTION(mTree && mTreeView, "Can't get mTree or mTreeView!\n");
00063   mAccessNodeCache = new nsInterfaceHashtable<nsVoidHashKey, nsIAccessNode>;
00064   mAccessNodeCache->Init(kDefaultTreeCacheSize);
00065 }
00066 
00067 NS_IMPL_ISUPPORTS_INHERITED1(nsXULTreeAccessible, nsXULSelectableAccessible, nsIAccessibleTreeCache)
00068                                                                                                        
00069 
00070 
00071 // Get the nsITreeBoxObject interface from any levels DOMNode under the <tree>
00072 void nsXULTreeAccessible::GetTreeBoxObject(nsIDOMNode *aDOMNode, nsITreeBoxObject **aBoxObject)
00073 {
00074   nsAutoString name;
00075   nsCOMPtr<nsIDOMNode> parentNode, currentNode;
00076 
00077   // Find DOMNode's parents recursively until reach the <tree> tag
00078   currentNode = aDOMNode;
00079   while (currentNode) {
00080     currentNode->GetLocalName(name);
00081     if (name.EqualsLiteral("tree")) {
00082       // We will get the nsITreeBoxObject from the tree node
00083       nsCOMPtr<nsIDOMXULElement> xulElement(do_QueryInterface(currentNode));
00084       if (xulElement) {
00085         nsCOMPtr<nsIBoxObject> box;
00086         xulElement->GetBoxObject(getter_AddRefs(box));
00087         nsCOMPtr<nsITreeBoxObject> treeBox(do_QueryInterface(box));
00088         if (treeBox) {
00089           *aBoxObject = treeBox;
00090           NS_ADDREF(*aBoxObject);
00091           return;
00092         }
00093       }
00094     }
00095     currentNode->GetParentNode(getter_AddRefs(parentNode));
00096     currentNode = parentNode;
00097   }
00098 
00099   *aBoxObject = nsnull;
00100 }
00101 
00102 NS_IMETHODIMP nsXULTreeAccessible::GetState(PRUint32 *_retval)
00103 {
00104   // Get focus status from base class                                           
00105   nsAccessible::GetState(_retval);                                           
00106 
00107   // see if we are multiple select if so set ourselves as such
00108   nsCOMPtr<nsIDOMElement> element (do_QueryInterface(mDOMNode));
00109   if (element) {
00110     // the default selection type is multiple
00111     nsAutoString selType;
00112     element->GetAttribute(NS_LITERAL_STRING("seltype"), selType);
00113     if (selType.IsEmpty() || !selType.EqualsLiteral("single"))
00114       *_retval |= STATE_MULTISELECTABLE;
00115   }
00116 
00117   *_retval |= STATE_READONLY | STATE_FOCUSABLE;
00118 
00119   return NS_OK;
00120 }
00121 
00122 // The value is the first selected child
00123 NS_IMETHODIMP nsXULTreeAccessible::GetValue(nsAString& _retval)
00124 {
00125   _retval.Truncate(0);
00126 
00127   NS_ENSURE_TRUE(mTree && mTreeView, NS_ERROR_FAILURE);
00128 
00129   nsCOMPtr<nsITreeSelection> selection;
00130   mTreeView->GetSelection(getter_AddRefs(selection));
00131   if (! selection)
00132     return NS_ERROR_FAILURE;
00133 
00134   PRInt32 currentIndex;
00135   nsCOMPtr<nsIDOMElement> selectItem;
00136   selection->GetCurrentIndex(&currentIndex);
00137   if (currentIndex >= 0) {
00138     nsCOMPtr<nsITreeColumn> keyCol;
00139 
00140     nsCOMPtr<nsITreeColumns> cols;
00141     mTree->GetColumns(getter_AddRefs(cols));
00142     if (cols)
00143       cols->GetKeyColumn(getter_AddRefs(keyCol));
00144 
00145     return mTreeView->GetCellText(currentIndex, keyCol, _retval);
00146   }
00147 
00148   return NS_OK;
00149 }
00150 
00151 NS_IMETHODIMP nsXULTreeAccessible::Shutdown()
00152 {
00153   nsXULSelectableAccessible::Shutdown();
00154 
00155   if (mAccessNodeCache) {
00156     ClearCache(*mAccessNodeCache);
00157     delete mAccessNodeCache;
00158     mAccessNodeCache = nsnull;
00159   }
00160   return NS_OK;
00161 }
00162 
00163 NS_IMETHODIMP nsXULTreeAccessible::GetRole(PRUint32 *aRole)
00164 {
00165   NS_ASSERTION(mTree, "No tree view");
00166   PRInt32 colCount = 0;
00167   if (NS_SUCCEEDED(GetColumnCount(mTree, &colCount)) && (colCount > 1))
00168     *aRole = ROLE_TREE_TABLE;
00169   else
00170     *aRole = ROLE_OUTLINE;
00171   return NS_OK;
00172 }
00173 
00174 NS_IMETHODIMP nsXULTreeAccessible::GetFirstChild(nsIAccessible **aFirstChild)
00175 {
00176   nsAccessible::GetFirstChild(aFirstChild);
00177 
00178   // in normal case, tree's first child should be treecols, if it is not here, 
00179   //   use the first row as tree's first child
00180   if (*aFirstChild == nsnull) {
00181     NS_ENSURE_TRUE(mTree && mTreeView, NS_ERROR_FAILURE);
00182 
00183     PRInt32 rowCount;
00184     mTreeView->GetRowCount(&rowCount);
00185     if (rowCount > 0) {
00186       return GetCachedTreeitemAccessible(0, nsnull, aFirstChild);
00187     }
00188   }
00189 
00190   return NS_OK;
00191 }
00192 
00193 NS_IMETHODIMP nsXULTreeAccessible::GetLastChild(nsIAccessible **aLastChild)
00194 {
00195   NS_ENSURE_TRUE(mTree && mTreeView, NS_ERROR_FAILURE);
00196 
00197   PRInt32 rowCount;
00198   mTreeView->GetRowCount(&rowCount);
00199   if (rowCount > 0) {
00200     return GetCachedTreeitemAccessible(rowCount - 1, nsnull, aLastChild);
00201   }
00202   else // if there is not any rows, use treecols as tree's last child
00203     nsAccessible::GetLastChild(aLastChild);
00204 
00205   return NS_OK;
00206 }
00207 
00208 // tree's children count is row count + treecols count
00209 NS_IMETHODIMP nsXULTreeAccessible::GetChildCount(PRInt32 *aAccChildCount)
00210 {
00211   NS_ENSURE_TRUE(mTree && mTreeView, NS_ERROR_FAILURE);
00212 
00213   nsAccessible::GetChildCount(aAccChildCount);
00214 
00215   PRInt32 rowCount;
00216   mTreeView->GetRowCount(&rowCount);
00217   *aAccChildCount += rowCount;
00218 
00219   return NS_OK;
00220 }
00221 
00222 NS_IMETHODIMP nsXULTreeAccessible::GetFocusedChild(nsIAccessible **aFocusedChild) 
00223 {
00224   nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSelect =
00225     do_QueryInterface(mDOMNode);
00226   if (multiSelect) {
00227     PRInt32 row;
00228     multiSelect->GetCurrentIndex(&row);
00229     if (row >= 0) {
00230       GetCachedTreeitemAccessible(row, nsnull, aFocusedChild);
00231       if (*aFocusedChild) {
00232         return NS_OK;  // Already addref'd by getter
00233       }
00234     }
00235   }
00236   NS_ADDREF(*aFocusedChild = this);
00237   return NS_OK;
00238 }
00239 
00240 // Ask treeselection to get all selected children
00241 NS_IMETHODIMP nsXULTreeAccessible::GetSelectedChildren(nsIArray **_retval)
00242 {
00243   *_retval = nsnull;
00244 
00245   NS_ENSURE_TRUE(mTree && mTreeView, NS_ERROR_FAILURE);
00246 
00247   nsCOMPtr<nsITreeSelection> selection;
00248   mTreeView->GetSelection(getter_AddRefs(selection));
00249   if (!selection)
00250     return NS_ERROR_FAILURE;
00251   nsCOMPtr<nsIMutableArray> selectedAccessibles;
00252   NS_NewArray(getter_AddRefs(selectedAccessibles));
00253   if (!selectedAccessibles)
00254     return NS_ERROR_OUT_OF_MEMORY;
00255 
00256   PRInt32 rowIndex, rowCount;
00257   PRBool isSelected;
00258   mTreeView->GetRowCount(&rowCount);
00259   for (rowIndex = 0; rowIndex < rowCount; rowIndex++) {
00260     selection->IsSelected(rowIndex, &isSelected);
00261     if (isSelected) {
00262       nsCOMPtr<nsIAccessible> tempAccess;
00263       if (NS_FAILED(GetCachedTreeitemAccessible(rowIndex, nsnull, getter_AddRefs(tempAccess))) || !tempAccess)
00264 
00265         return NS_ERROR_OUT_OF_MEMORY;
00266       selectedAccessibles->AppendElement(tempAccess, PR_FALSE);
00267     }
00268   }
00269 
00270   PRUint32 length;
00271   selectedAccessibles->GetLength(&length);
00272   if (length != 0) {
00273     *_retval = selectedAccessibles;
00274     NS_IF_ADDREF(*_retval);
00275   }
00276 
00277   return NS_OK;
00278 }
00279 
00280 NS_IMETHODIMP nsXULTreeAccessible::GetSelectionCount(PRInt32 *aSelectionCount)
00281 {
00282   *aSelectionCount = 0;
00283 
00284   NS_ENSURE_TRUE(mTree && mTreeView, NS_ERROR_FAILURE);
00285 
00286   nsCOMPtr<nsITreeSelection> selection;
00287   mTreeView->GetSelection(getter_AddRefs(selection));
00288   if (selection)
00289     selection->GetCount(aSelectionCount);
00290 
00291   return NS_OK;
00292 }
00293 
00294 NS_IMETHODIMP nsXULTreeAccessible::ChangeSelection(PRInt32 aIndex, PRUint8 aMethod, PRBool *aSelState)
00295 {
00296   NS_ENSURE_TRUE(mTree && mTreeView, NS_ERROR_FAILURE);
00297 
00298   nsCOMPtr<nsITreeSelection> selection;
00299   mTreeView->GetSelection(getter_AddRefs(selection));
00300   if (selection) {
00301     selection->IsSelected(aIndex, aSelState);
00302     if ((!(*aSelState) && eSelection_Add == aMethod) || 
00303         ((*aSelState) && eSelection_Remove == aMethod))
00304       return selection->ToggleSelect(aIndex);
00305   }
00306 
00307   return NS_OK;
00308 }
00309 
00310 NS_IMETHODIMP nsXULTreeAccessible::AddChildToSelection(PRInt32 aIndex)
00311 {
00312   PRBool isSelected;
00313   return ChangeSelection(aIndex, eSelection_Add, &isSelected);
00314 }
00315 
00316 NS_IMETHODIMP nsXULTreeAccessible::RemoveChildFromSelection(PRInt32 aIndex)
00317 {
00318   PRBool isSelected;
00319   return ChangeSelection(aIndex, eSelection_Remove, &isSelected);
00320 }
00321 
00322 NS_IMETHODIMP nsXULTreeAccessible::IsChildSelected(PRInt32 aIndex, PRBool *_retval)
00323 {
00324   return ChangeSelection(aIndex, eSelection_GetState, _retval);
00325 }
00326 
00327 NS_IMETHODIMP nsXULTreeAccessible::ClearSelection()
00328 {
00329   NS_ENSURE_TRUE(mTree && mTreeView, NS_ERROR_FAILURE);
00330 
00331   nsCOMPtr<nsITreeSelection> selection;
00332   mTreeView->GetSelection(getter_AddRefs(selection));
00333   if (selection)
00334     selection->ClearSelection();
00335 
00336   return NS_OK;
00337 }
00338 
00339 NS_IMETHODIMP nsXULTreeAccessible::RefSelection(PRInt32 aIndex, nsIAccessible **_retval)
00340 {
00341   *_retval = nsnull;
00342 
00343   NS_ENSURE_TRUE(mTree && mTreeView, NS_ERROR_FAILURE);
00344 
00345   nsCOMPtr<nsITreeSelection> selection;
00346   mTreeView->GetSelection(getter_AddRefs(selection));
00347   if (!selection)
00348     return NS_ERROR_FAILURE;
00349 
00350   PRInt32 rowIndex, rowCount;
00351   PRInt32 selCount = 0;
00352   PRBool isSelected;
00353   mTreeView->GetRowCount(&rowCount);
00354   for (rowIndex = 0; rowIndex < rowCount; rowIndex++) {
00355     selection->IsSelected(rowIndex, &isSelected);
00356     if (isSelected) {
00357       if (selCount == aIndex) {
00358         return GetCachedTreeitemAccessible(rowIndex, nsnull, _retval);
00359       }
00360       selCount++;
00361     }
00362   }
00363 
00364   return NS_OK;
00365 }
00366 
00367 NS_IMETHODIMP nsXULTreeAccessible::SelectAllSelection(PRBool *_retval)
00368 {
00369   *_retval = PR_FALSE;
00370 
00371   NS_ENSURE_TRUE(mTree && mTreeView, NS_ERROR_FAILURE);
00372 
00373   // see if we are multiple select if so set ourselves as such
00374   nsCOMPtr<nsIDOMElement> element (do_QueryInterface(mDOMNode));
00375   if (element) {
00376     nsAutoString selType;
00377     element->GetAttribute(NS_LITERAL_STRING("seltype"), selType);
00378     if (selType.IsEmpty() || !selType.EqualsLiteral("single")) {
00379       *_retval = PR_TRUE;
00380       nsCOMPtr<nsITreeSelection> selection;
00381       mTreeView->GetSelection(getter_AddRefs(selection));
00382       if (selection)
00383         selection->SelectAll();
00384     }
00385   }
00386 
00387   return NS_OK;
00388 }
00389 
00390 NS_IMETHODIMP nsXULTreeAccessible::GetCachedTreeitemAccessible(PRInt32 aRow, nsITreeColumn* aColumn, nsIAccessible** aAccessible)
00391 {
00392   *aAccessible = nsnull;
00393 
00394   NS_ASSERTION(mAccessNodeCache, "No accessibility cache for tree");
00395   NS_ASSERTION(mTree && mTreeView, "Can't get mTree or mTreeView!\n");
00396 
00397   nsCOMPtr<nsITreeColumn> col;
00398 #ifdef MOZ_ACCESSIBILITY_ATK
00399   col = aColumn;
00400 #endif
00401   PRInt32 columnIndex = -1;
00402 
00403   if (!col && mTree) {
00404     nsCOMPtr<nsITreeColumns> cols;
00405     mTree->GetColumns(getter_AddRefs(cols));
00406     if (cols)
00407       cols->GetKeyColumn(getter_AddRefs(col));
00408   }
00409 
00410   if (col)
00411      col->GetIndex(&columnIndex);
00412 
00413   nsCOMPtr<nsIAccessNode> accessNode;
00414   GetCacheEntry(*mAccessNodeCache, (void*)(aRow * kMaxTreeColumns + columnIndex), getter_AddRefs(accessNode));
00415   if (!accessNode)
00416   {
00417     accessNode = new nsXULTreeitemAccessibleWrap(this, mDOMNode, mWeakShell, aRow, col);
00418     if (! accessNode)
00419       return NS_ERROR_OUT_OF_MEMORY;
00420     PutCacheEntry(*mAccessNodeCache, (void*)(aRow * kMaxTreeColumns + columnIndex), accessNode);
00421   }
00422   nsCOMPtr<nsIAccessible> accessible(do_QueryInterface(accessNode));
00423   NS_IF_ADDREF(*aAccessible = accessible);
00424   return NS_OK;
00425 }
00426 
00427 nsresult nsXULTreeAccessible::GetColumnCount(nsITreeBoxObject* aBoxObject, PRInt32* aCount)
00428 {
00429   NS_ENSURE_TRUE(aBoxObject, NS_ERROR_FAILURE);
00430   nsCOMPtr<nsITreeColumns> treeColumns;
00431   nsresult rv = aBoxObject->GetColumns(getter_AddRefs(treeColumns));
00432   NS_ENSURE_TRUE(treeColumns, NS_ERROR_FAILURE);
00433   return treeColumns->GetCount(aCount);
00434 }
00435 
00436 // ---------- nsXULTreeitemAccessible ---------- 
00437 
00438 nsXULTreeitemAccessible::nsXULTreeitemAccessible(nsIAccessible *aParent, nsIDOMNode *aDOMNode, nsIWeakReference *aShell, PRInt32 aRow, nsITreeColumn* aColumn)
00439   : nsLeafAccessible(aDOMNode, aShell)
00440 {
00441   Init(); // Add ourselves to cache using GetUniqueID() override
00442   mParent = aParent;  // xxx todo: do we need this? We already have mParent on nsAccessible
00443 
00444   nsXULTreeAccessible::GetTreeBoxObject(aDOMNode, getter_AddRefs(mTree));
00445   if (mTree)
00446     mTree->GetView(getter_AddRefs(mTreeView));
00447   NS_ASSERTION(mTree && mTreeView, "Can't get mTree or mTreeView!\n");
00448 
00449   // Since the real tree item does not correspond to any DOMNode, use the row index to distinguish each item
00450   mRow = aRow;
00451   mColumn = aColumn;
00452 
00453   if (!mColumn && mTree) {
00454     nsCOMPtr<nsITreeColumns> cols;
00455     mTree->GetColumns(getter_AddRefs(cols));
00456     if (cols)
00457       cols->GetKeyColumn(getter_AddRefs(mColumn));
00458   }
00459 }
00460 
00461 NS_IMPL_ISUPPORTS_INHERITED0(nsXULTreeitemAccessible, nsLeafAccessible)
00462 
00463 NS_IMETHODIMP nsXULTreeitemAccessible::Shutdown()
00464 {
00465   mTree = nsnull;
00466   mTreeView = nsnull;
00467   mColumn = nsnull;
00468   return nsLeafAccessible::Shutdown();
00469 }
00470 
00471 NS_IMETHODIMP nsXULTreeitemAccessible::GetName(nsAString& aName)
00472 {
00473   NS_ENSURE_TRUE(mTree && mTreeView, NS_ERROR_FAILURE);
00474   return mTreeView->GetCellText(mRow, mColumn, aName);
00475 }
00476 
00477 NS_IMETHODIMP nsXULTreeitemAccessible::GetUniqueID(void **aUniqueID)
00478 {
00479   // Since mDOMNode is same for all tree item, use |this| pointer as the unique Id
00480   *aUniqueID = NS_STATIC_CAST(void*, this);
00481   return NS_OK;
00482 }
00483 
00484 NS_IMETHODIMP nsXULTreeitemAccessible::GetRole(PRUint32 *aRole)
00485 {
00486   PRInt32 colCount = 0;
00487   if (NS_SUCCEEDED(nsXULTreeAccessible::GetColumnCount(mTree, &colCount)) && colCount > 1)
00488     *aRole = ROLE_CELL;
00489   else
00490     *aRole = ROLE_OUTLINEITEM;
00491   return NS_OK;
00492 }
00493 
00494 // Possible states: focused, focusable, selected, expanded/collapsed
00495 NS_IMETHODIMP nsXULTreeitemAccessible::GetState(PRUint32 *_retval)
00496 {
00497   NS_ENSURE_TRUE(mTree && mTreeView, NS_ERROR_FAILURE);
00498 
00499   *_retval = STATE_FOCUSABLE | STATE_SELECTABLE;
00500 
00501   // get expanded/collapsed state
00502   PRBool isContainer, isContainerOpen, isContainerEmpty;
00503   mTreeView->IsContainer(mRow, &isContainer);
00504   if (isContainer) {
00505     mTreeView->IsContainerEmpty(mRow, &isContainerEmpty);
00506     if (!isContainerEmpty) {
00507       mTreeView->IsContainerOpen(mRow, &isContainerOpen);
00508       *_retval |= isContainerOpen? STATE_EXPANDED: STATE_COLLAPSED;
00509     }
00510   }
00511 
00512   // get selected state
00513   nsCOMPtr<nsITreeSelection> selection;
00514   mTreeView->GetSelection(getter_AddRefs(selection));
00515   if (selection) {
00516     PRBool isSelected;
00517     selection->IsSelected(mRow, &isSelected);
00518     if (isSelected)
00519       *_retval |= STATE_SELECTED;
00520   }
00521 
00522   nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSelect =
00523     do_QueryInterface(mDOMNode);
00524   if (multiSelect) {
00525     PRInt32 currentIndex;
00526     multiSelect->GetCurrentIndex(&currentIndex);
00527     if (currentIndex == mRow) {
00528       *_retval |= STATE_FOCUSED;
00529     }
00530   }
00531 
00532   PRInt32 firstVisibleRow, lastVisibleRow;
00533   mTree->GetFirstVisibleRow(&firstVisibleRow);
00534   mTree->GetLastVisibleRow(&lastVisibleRow);
00535   if (mRow < firstVisibleRow || mRow > lastVisibleRow)
00536     *_retval |= STATE_INVISIBLE;
00537 
00538   return NS_OK;
00539 }
00540 
00541 // "activate" action is available for all treeitems
00542 // "expand/collapse" action is avaible for treeitem which is container
00543 NS_IMETHODIMP nsXULTreeitemAccessible::GetNumActions(PRUint8 *_retval)
00544 {
00545   NS_ENSURE_TRUE(mTree && mTreeView, NS_ERROR_FAILURE);
00546   PRBool isContainer;
00547   mTreeView->IsContainer(mRow, &isContainer);
00548   if (isContainer)
00549     *_retval = eDouble_Action;
00550   else
00551     *_retval = eSingle_Action;
00552 
00553   return NS_OK;
00554 }
00555 
00556 // Return the name of our actions
00557 NS_IMETHODIMP nsXULTreeitemAccessible::GetActionName(PRUint8 index, nsAString& _retval)
00558 {
00559   NS_ENSURE_TRUE(mTree && mTreeView, NS_ERROR_FAILURE);
00560 
00561   if (index == eAction_Click) {
00562     nsAccessible::GetTranslatedString(NS_LITERAL_STRING("activate"), _retval);
00563     return NS_OK;
00564   }
00565   else if (index == eAction_Expand) {
00566     PRBool isContainer, isContainerOpen;
00567     mTreeView->IsContainer(mRow, &isContainer);
00568     if (isContainer) {
00569       mTreeView->IsContainerOpen(mRow, &isContainerOpen);
00570       if (isContainerOpen)
00571         nsAccessible::GetTranslatedString(NS_LITERAL_STRING("collapse"), _retval);
00572       else
00573         nsAccessible::GetTranslatedString(NS_LITERAL_STRING("expand"), _retval);
00574     }
00575 
00576     return NS_OK;
00577   }
00578 
00579   return NS_ERROR_INVALID_ARG;
00580 }
00581 
00582 NS_IMETHODIMP nsXULTreeitemAccessible::GetParent(nsIAccessible **aParent)
00583 {
00584   *aParent = nsnull;
00585 
00586   if (mParent) {
00587     *aParent = mParent;
00588     NS_ADDREF(*aParent);
00589   }
00590 
00591   return NS_OK;
00592 }
00593 
00594 // Return the next row of tree if mColumn (if any),
00595 // otherwise return the next cell.
00596 NS_IMETHODIMP nsXULTreeitemAccessible::GetNextSibling(nsIAccessible **aNextSibling)
00597 {
00598   *aNextSibling = nsnull;
00599 
00600   NS_ENSURE_TRUE(mTree && mTreeView, NS_ERROR_FAILURE);
00601 
00602   nsCOMPtr<nsIAccessibleTreeCache> treeCache(do_QueryInterface(mParent));
00603   NS_ENSURE_TRUE(treeCache, NS_ERROR_FAILURE);
00604 
00605   PRInt32 rowCount;
00606   mTreeView->GetRowCount(&rowCount);
00607 
00608   if (!mColumn) {
00609     if (mRow < rowCount - 1)
00610       return treeCache->GetCachedTreeitemAccessible(mRow + 1, nsnull, aNextSibling);
00611     else
00612       return NS_OK;
00613   }
00614 
00615   nsresult rv = NS_OK;
00616   PRInt32 row = mRow;
00617   nsCOMPtr<nsITreeColumn> column;
00618 #ifdef MOZ_ACCESSIBILITY_ATK
00619   rv = mColumn->GetNext(getter_AddRefs(column));
00620   NS_ENSURE_SUCCESS(rv, rv);
00621   
00622   if (!column) {
00623     if (mRow < rowCount -1) {
00624       row++;
00625       nsCOMPtr<nsITreeColumns> cols;
00626       mTree->GetColumns(getter_AddRefs(cols));
00627       if (cols)
00628         cols->GetFirstColumn(getter_AddRefs(column));
00629     } else {
00630       // the next sibling of the last treeitem is null
00631       return NS_OK;
00632     }
00633   }
00634 #else
00635   if (++row >= rowCount) {
00636     return NS_ERROR_FAILURE;
00637   }
00638 #endif //MOZ_ACCESSIBILITY_ATK
00639 
00640   rv = treeCache->GetCachedTreeitemAccessible(row, column, aNextSibling);
00641   
00642   return rv;
00643 }
00644 
00645 // Return the previous row of tree if mColumn (if any),
00646 // otherwise return the previous cell.
00647 NS_IMETHODIMP nsXULTreeitemAccessible::GetPreviousSibling(nsIAccessible **aPreviousSibling)
00648 {
00649   *aPreviousSibling = nsnull;
00650 
00651   NS_ENSURE_TRUE(mTree && mTreeView, NS_ERROR_FAILURE);
00652 
00653   nsCOMPtr<nsIAccessibleTreeCache> treeCache(do_QueryInterface(mParent));
00654   NS_ENSURE_TRUE(treeCache, NS_ERROR_FAILURE);
00655 
00656   if (!mColumn && mRow > 0)
00657     return treeCache->GetCachedTreeitemAccessible(mRow - 1, nsnull, aPreviousSibling);
00658   
00659   nsresult rv = NS_OK;
00660 
00661 
00662   PRInt32 row = mRow;
00663   nsCOMPtr<nsITreeColumn> column;
00664 #ifdef MOZ_ACCESSIBILITY_ATK
00665   rv = mColumn->GetPrevious(getter_AddRefs(column));
00666   NS_ENSURE_SUCCESS(rv, rv);
00667   
00668   if (!column && mRow > 0) {
00669     row--;
00670     nsCOMPtr<nsITreeColumns> cols;
00671     mTree->GetColumns(getter_AddRefs(cols));
00672     if (cols)
00673       cols->GetLastColumn(getter_AddRefs(column));
00674   }
00675 #else
00676   if (--row < 0) {
00677     return NS_ERROR_FAILURE;
00678   }
00679 #endif
00680 
00681   rv = treeCache->GetCachedTreeitemAccessible(row, column, aPreviousSibling);
00682 
00683   return rv;
00684 }
00685 
00686 NS_IMETHODIMP nsXULTreeitemAccessible::DoAction(PRUint8 index)
00687 {
00688   NS_ENSURE_TRUE(mTree && mTreeView, NS_ERROR_FAILURE);
00689 
00690   if (index == eAction_Click) {
00691     nsCOMPtr<nsITreeSelection> selection;
00692     mTreeView->GetSelection(getter_AddRefs(selection));
00693     if (selection) {
00694       nsresult rv = selection->Select(mRow);
00695       mTree->EnsureRowIsVisible(mRow);
00696       return rv;
00697     }
00698   }
00699   else if (index == eAction_Expand) {
00700     PRBool isContainer;
00701     mTreeView->IsContainer(mRow, &isContainer);
00702     if (isContainer)
00703       return mTreeView->ToggleOpenState(mRow);
00704   }
00705 
00706   return NS_ERROR_INVALID_ARG;
00707 }
00708 
00709 NS_IMETHODIMP nsXULTreeitemAccessible::GetBounds(PRInt32 *x, PRInt32 *y, PRInt32 *width, PRInt32 *height)
00710 {
00711   *x = *y = *width = *height = 0;
00712 
00713   NS_ENSURE_TRUE(mTree && mTreeView, NS_ERROR_FAILURE);
00714 
00715   // This Bounds are based on Tree's coord
00716   mTree->GetCoordsForCellItem(mRow, mColumn, EmptyCString(), x, y, width, height);
00717 
00718   // Get treechildren's BoxObject to adjust the Bounds' upper left corner
00719   // XXXvarga consider using mTree->GetTreeBody()
00720   nsCOMPtr<nsIBoxObject> boxObject(do_QueryInterface(mTree));
00721   if (boxObject) {
00722     nsCOMPtr<nsIDOMElement> boxElement;
00723     boxObject->GetElement(getter_AddRefs(boxElement));
00724     nsCOMPtr<nsIDOMNode> boxNode(do_QueryInterface(boxElement));
00725     if (boxNode) {
00726       nsCOMPtr<nsIDOMNodeList> childNodes;
00727       boxNode->GetChildNodes(getter_AddRefs(childNodes));
00728       if (childNodes) {
00729         nsAutoString name;
00730         nsCOMPtr<nsIDOMNode> childNode;
00731         PRUint32 childCount, childIndex;
00732 
00733         childNodes->GetLength(&childCount);
00734         for (childIndex = 0; childIndex < childCount; childIndex++) {
00735           childNodes->Item(childIndex, getter_AddRefs(childNode));
00736           childNode->GetLocalName(name);
00737           if (name.EqualsLiteral("treechildren")) {
00738             nsCOMPtr<nsIDOMXULElement> xulElement(do_QueryInterface(childNode));
00739             if (xulElement) {
00740               nsCOMPtr<nsIBoxObject> box;
00741               xulElement->GetBoxObject(getter_AddRefs(box));
00742               if (box) {
00743                 PRInt32 myX, myY;
00744                 box->GetScreenX(&myX);
00745                 box->GetScreenY(&myY);
00746                 *x += myX;
00747                 *y += myY;
00748               }
00749             }
00750             break;
00751           }
00752         }
00753       }
00754     }
00755   }
00756 
00757   return NS_OK;
00758 }
00759 
00760 NS_IMETHODIMP nsXULTreeitemAccessible::RemoveSelection()
00761 {
00762   NS_ENSURE_TRUE(mTree && mTreeView, NS_ERROR_FAILURE);
00763 
00764   nsCOMPtr<nsITreeSelection> selection;
00765   mTreeView->GetSelection(getter_AddRefs(selection));
00766   if (selection) {
00767     PRBool isSelected;
00768     selection->IsSelected(mRow, &isSelected);
00769     if (isSelected)
00770       selection->ToggleSelect(mRow);
00771   }
00772 
00773   return NS_OK;
00774 }
00775 
00776 NS_IMETHODIMP nsXULTreeitemAccessible::TakeSelection()
00777 {
00778   NS_ENSURE_TRUE(mTree && mTreeView, NS_ERROR_FAILURE);
00779 
00780   nsCOMPtr<nsITreeSelection> selection;
00781   mTreeView->GetSelection(getter_AddRefs(selection));
00782   if (selection) {
00783     PRBool isSelected;
00784     selection->IsSelected(mRow, &isSelected);
00785     if (! isSelected)
00786       selection->ToggleSelect(mRow);
00787   }
00788 
00789   return NS_OK;
00790 }
00791 
00792 NS_IMETHODIMP nsXULTreeitemAccessible::TakeFocus()
00793 { 
00794   NS_ENSURE_TRUE(mTree && mTreeView, NS_ERROR_FAILURE);
00795 
00796   nsCOMPtr<nsITreeSelection> selection;
00797   mTreeView->GetSelection(getter_AddRefs(selection));
00798   if (selection)
00799     selection->SetCurrentIndex(mRow);
00800 
00801   // focus event will be fired here
00802   return nsAccessible::TakeFocus();
00803 }
00804 
00805 NS_IMETHODIMP nsXULTreeitemAccessible::GetAccessibleRelated(PRUint32 aRelationType, nsIAccessible **aRelated)
00806 {
00807   //currentlly only for ATK. and in the future, we'll sync MSAA and ATK same. 
00808   //that's why ATK specific code shows here
00809   *aRelated = nsnull;
00810 #ifdef MOZ_ACCESSIBILITY_ATK
00811   if (aRelationType == RELATION_NODE_CHILD_OF) {
00812     PRInt32 columnIndex;
00813     if (NS_SUCCEEDED(mColumn->GetIndex(&columnIndex)) && columnIndex == 0) {
00814       PRInt32 parentIndex;
00815       if (NS_SUCCEEDED(mTreeView->GetParentIndex(mRow, &parentIndex))) {
00816         if (parentIndex == -1) {
00817           NS_IF_ADDREF(*aRelated = mParent);
00818           return NS_OK;
00819         } else {
00820           nsCOMPtr<nsIAccessibleTreeCache> cache =
00821             do_QueryInterface(mParent);
00822           return cache->GetCachedTreeitemAccessible(parentIndex, mColumn, aRelated);
00823         }
00824       }
00825     }
00826     return NS_OK;
00827   } else { 
00828 #endif
00829     return nsAccessible::GetAccessibleRelated(aRelationType, aRelated);
00830 #ifdef MOZ_ACCESSIBILITY_ATK
00831   }
00832 #endif
00833 }
00834 
00835 // ---------- nsXULTreeColumnsAccessible ----------
00836 
00837 nsXULTreeColumnsAccessible::nsXULTreeColumnsAccessible(nsIDOMNode *aDOMNode, nsIWeakReference *aShell):
00838 nsAccessibleWrap(aDOMNode, aShell)
00839 {
00840 }
00841 
00842 NS_IMPL_ISUPPORTS_INHERITED0(nsXULTreeColumnsAccessible, nsAccessible)
00843 
00844 NS_IMETHODIMP nsXULTreeColumnsAccessible::GetState(PRUint32 *_retval)
00845 {
00846   *_retval = STATE_READONLY;
00847   return NS_OK;
00848 }
00849 
00850 NS_IMETHODIMP nsXULTreeColumnsAccessible::GetRole(PRUint32 *_retval)
00851 {
00852   *_retval = ROLE_LIST;
00853   return NS_OK;
00854 }
00855 
00856 NS_IMETHODIMP nsXULTreeColumnsAccessible::GetNumActions(PRUint8 *_retval)
00857 {
00858   *_retval = eSingle_Action;
00859   return NS_OK;
00860 }
00861 
00862 NS_IMETHODIMP nsXULTreeColumnsAccessible::GetActionName(PRUint8 index, nsAString& _retval)
00863 {
00864   if (index == eAction_Click) {
00865     nsAccessible::GetTranslatedString(NS_LITERAL_STRING("click"), _retval);
00866     return NS_OK;
00867   }
00868 
00869   return NS_ERROR_INVALID_ARG;
00870 }
00871 
00872 NS_IMETHODIMP nsXULTreeColumnsAccessible::GetNextSibling(nsIAccessible **aNextSibling) 
00873 {
00874   nsresult ret = nsAccessible::GetNextSibling(aNextSibling);
00875 
00876   if (*aNextSibling == nsnull) { // if there is not other sibling, use the first row as its sibling
00877     nsCOMPtr<nsITreeBoxObject> tree;
00878     nsCOMPtr<nsITreeView> treeView;
00879 
00880     nsXULTreeAccessible::GetTreeBoxObject(mDOMNode, getter_AddRefs(tree));
00881     if (tree) {
00882       tree->GetView(getter_AddRefs(treeView));
00883       if (treeView) {
00884         PRInt32 rowCount;
00885         treeView->GetRowCount(&rowCount);
00886         if (rowCount > 0) {
00887           nsCOMPtr<nsIAccessibleTreeCache> treeCache(do_QueryInterface(mParent));
00888           NS_ENSURE_TRUE(treeCache, NS_ERROR_FAILURE);
00889           ret = treeCache->GetCachedTreeitemAccessible(0, nsnull, aNextSibling);
00890         }
00891       }
00892     }
00893   }
00894 
00895   return ret;  
00896 }
00897 
00898 NS_IMETHODIMP nsXULTreeColumnsAccessible::GetPreviousSibling(nsIAccessible **aPreviousSibling) 
00899 {  
00900   return nsAccessible::GetPreviousSibling(aPreviousSibling);
00901 }
00902 
00903 NS_IMETHODIMP nsXULTreeColumnsAccessible::DoAction(PRUint8 index)
00904 {
00905   if (index == eAction_Click)
00906     return NS_OK;
00907 
00908   return NS_ERROR_INVALID_ARG;
00909 }
00910 
00911 // ---------- nsXULTreeColumnitemAccessible ----------
00912 
00913 nsXULTreeColumnitemAccessible::nsXULTreeColumnitemAccessible(nsIDOMNode *aDOMNode, nsIWeakReference *aShell):
00914 nsLeafAccessible(aDOMNode, aShell)
00915 {
00916 }
00917 
00918 NS_IMPL_ISUPPORTS_INHERITED0(nsXULTreeColumnitemAccessible, nsLeafAccessible)
00919 
00920 NS_IMETHODIMP nsXULTreeColumnitemAccessible::GetState(PRUint32 *_retval)
00921 {
00922   *_retval = STATE_READONLY;
00923   return NS_OK;
00924 }
00925 
00926 NS_IMETHODIMP nsXULTreeColumnitemAccessible::GetName(nsAString& _retval)
00927 {
00928   return GetXULName(_retval);
00929 }
00930 
00931 NS_IMETHODIMP nsXULTreeColumnitemAccessible::GetRole(PRUint32 *_retval)
00932 {
00933   *_retval = ROLE_COLUMNHEADER;
00934   return NS_OK;
00935 }
00936 
00937 NS_IMETHODIMP nsXULTreeColumnitemAccessible::GetNumActions(PRUint8 *_retval)
00938 {
00939   *_retval = eSingle_Action;
00940   return NS_OK;
00941 }
00942 
00943 NS_IMETHODIMP nsXULTreeColumnitemAccessible::GetActionName(PRUint8 index, nsAString& _retval)
00944 {
00945   if (index == eAction_Click) {
00946     nsAccessible::GetTranslatedString(NS_LITERAL_STRING("click"), _retval);
00947     return NS_OK;
00948   }
00949 
00950   return NS_ERROR_INVALID_ARG;
00951 }
00952 
00953 NS_IMETHODIMP nsXULTreeColumnitemAccessible::DoAction(PRUint8 index)
00954 {
00955   if (index == eAction_Click) {
00956     return DoCommand();
00957   }
00958 
00959   return NS_ERROR_INVALID_ARG;
00960 }