diff options
Diffstat (limited to 'winaccessibility/source/service/AccObjectWinManager.cxx')
-rw-r--r-- | winaccessibility/source/service/AccObjectWinManager.cxx | 1321 |
1 files changed, 1321 insertions, 0 deletions
diff --git a/winaccessibility/source/service/AccObjectWinManager.cxx b/winaccessibility/source/service/AccObjectWinManager.cxx new file mode 100644 index 000000000000..08ed3efd2b43 --- /dev/null +++ b/winaccessibility/source/service/AccObjectWinManager.cxx @@ -0,0 +1,1321 @@ +/************************************************************** + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + *************************************************************/ + +#include <cassert> + +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> +#include <com/sun/star/accessibility/XAccessibleEventListener.hpp> +#include <com/sun/star/accessibility/XAccessibleComponent.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> + +#include <oleacc.h> +#ifndef _SV_AccObjectWinManager_HXX +#include "AccObjectWinManager.hxx" +#endif +#include "AccEventListener.hxx" +#include "AccComponentEventListener.hxx" +#include "AccContainerEventListener.hxx" +#include "AccDialogEventListener.hxx" +#include "AccWindowEventListener.hxx" +#include "AccFrameEventListener.hxx" +#include "AccMenuEventListener.hxx" +#include "AccObjectContainerEventListener.hxx" +#include "AccParagraphEventListener.hxx" +#include "AccTextComponentEventListener.hxx" +#include "AccListEventListener.hxx" +#include "AccTreeEventListener.hxx" +#include "AccTableEventListener.hxx" +#include "AccObject.hxx" +#include "unomsaaevent.hxx" +#include "checkmt.hxx" + +#define CHILDID_SELF 0 + + +using namespace std; +using namespace com::sun::star::accessibility; +using namespace com::sun::star::uno; + +AccObjectWinManager* g_acc_manager = NULL; +AccObjectWinManager* AccObjectWinManager::me = NULL; + +/** + * Implementation of interface XMSAAService's method getAccObjectPtr() that return the + * corresponding com interface with the MS event. + * + * @param + * @return Com interface. + */ +long GetMSComPtr(long hWnd, long lParam, long wParam) +{ + if( g_acc_manager ) + return (long)g_acc_manager->Get_ToATInterface(HWND((void*)hWnd),lParam,wParam ); + return NULL; +} + +/** + * constructor + * @param Agent The agent kept in all listeners,it's the sole interface by which + * listener communicate with windows manager. + * pEventAccObj The present event accobject. + * oldFocus Last focused object. + * isSelectionChanged flag that identifies if there is selection changed. + * selectionChildObj Selected object. + * dChildID Chile resource ID. + * hAcc TopWindowHWND + * @return + */ +AccObjectWinManager::AccObjectWinManager( AccObjectManagerAgent* Agent ): + pAgent( Agent ), + oldFocus( NULL ) +{ +} + +/** + * Public method to produce manager + * @param Agent The agent kept in all listeners,it's the sole interface by which + * listener communicate with windows manager. + * @return + */ +AccObjectWinManager* AccObjectWinManager::CreateAccObjectWinManagerInstance( AccObjectManagerAgent* Agent ) +{ + if( me == NULL ) + { + me = new AccObjectWinManager( Agent ); + g_acc_manager = me; + return me; + } + + return me; +} + + +/** + * Destructor,clear all resource. + * @param + * @return + */ +AccObjectWinManager::~AccObjectWinManager() +{ + XIdAccList.clear(); + HwndXAcc.clear(); + XResIdAccList.clear(); + XHWNDDocList.clear(); +#ifdef ACC_DEBUG + + fclose( pFile ); +#endif +} + + +/** + * Get valid com object interface when notifying some MSAA event + * @param pWND The top window handle that contains that event control. + * @param wParam Windows system interface. + * @return Com interface with event. + */ + +long AccObjectWinManager::Get_ToATInterface( HWND hWnd, long lParam, long wParam) +{ + vos::OGuard localGuard(maATInterfaceMutex);// + + IMAccessible* pRetIMAcc = NULL; + + if(lParam == OBJID_CLIENT ) + { + AccObject* topWindowAccObj = GetTopWindowAccObj(hWnd); + if(topWindowAccObj) + { + pRetIMAcc = topWindowAccObj->GetIMAccessible(); + if(pRetIMAcc) + pRetIMAcc->AddRef();//increase COM reference count + } + } + + if ( pRetIMAcc && lParam == OBJID_CLIENT ) + { + IAccessible* pTemp = dynamic_cast<IAccessible*>( pRetIMAcc ); + HRESULT result = LresultFromObject(IID_IAccessible, wParam, pTemp); + pTemp->Release(); + return result; + } + return 0; +} + +/** + * Search AccObject by XAccessible pointer from our container. + * @param pXAcc XAccessible interface. + * @return Pointer of accObject that is found. + */ +AccObject* AccObjectWinManager::GetAccObjByXAcc( XAccessible* pXAcc) +{ + if( pXAcc == NULL) + return NULL; + + XIdToAccObjHash::iterator pIndTemp = XIdAccList.find( (void*)pXAcc ); + if ( pIndTemp == XIdAccList.end() ) + return NULL; + + return &(pIndTemp->second); +} + +/** + * Search XAccessible by AccObject pointer from our container. + * @param pAccObj AccObject pointer. + * @return Pointer of XAccessible Interface. + */ +XAccessible* AccObjectWinManager::GetXAccByAccObj(AccObject* pAccObj) +{ + XIdToAccObjHash::iterator iter = XIdAccList.begin(); + while(iter!=XIdAccList.end()) + { + AccObject* tmp = &(iter->second); + if(tmp== pAccObj) + return (XAccessible*)(iter->first); + iter++; + } + return NULL; +} + +/** + * get acc object of top window by its handle + * @param hWnd, top window handle + * @return pointer to AccObject + */ +AccObject* AccObjectWinManager::GetTopWindowAccObj(HWND hWnd) +{ + XHWNDToXAccHash::iterator iterResult =HwndXAcc.find(hWnd); + if(iterResult == HwndXAcc.end()) + return NULL; + XAccessible* pXAcc = (XAccessible*)(iterResult->second); + return GetAccObjByXAcc(pXAcc); +} + +/** + * Simulate MSAA event via XAccessible interface and event type. + * @param pXAcc XAccessible interface. + * @param state Customize Interface + * @return The terminate result that identifies if the call is successful. + */ +sal_Bool AccObjectWinManager::NotifyAccEvent(XAccessible* pXAcc,short state) +{ + vos::OGuard aGuard(aNotifyMutex); + + if (!IsInMainThread()) + { + return sal_False; + } + + Reference< XAccessibleContext > pRContext; + + if( pXAcc == NULL) + return sal_False; + + + pRContext = pXAcc->getAccessibleContext(); + if( !pRContext.is() ) + return sal_False; + + + AccObject* selfAccObj= GetAccObjByXAcc(pXAcc); + + if(selfAccObj==NULL) + return sal_False; + + int selectNum =0; + + long dChildID = selfAccObj->GetResID(); + HWND hAcc = selfAccObj->GetParentHWND(); + + switch(state) + { + case UM_EVENT_STATE_FOCUSED: + { + UpdateAccFocus(pXAcc); + if( selfAccObj ) + selfAccObj->UpdateDefaultAction( ); + UpdateValue(pXAcc); + NotifyWinEvent( EVENT_OBJECT_FOCUS,hAcc, OBJID_CLIENT,dChildID ); + break; + } + case UM_EVENT_STATE_BUSY: + NotifyWinEvent( EVENT_OBJECT_STATECHANGE,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_STATE_CHECKED: + NotifyWinEvent( EVENT_OBJECT_STATECHANGE,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_STATE_PRESSED: + NotifyWinEvent( EVENT_OBJECT_STATECHANGE,hAcc, OBJID_CLIENT,dChildID ); + break; + + //Removed fire out selected event + //case UM_EVENT_STATE_SELECTED: + // NotifyWinEvent( EVENT_OBJECT_STATECHANGE,hAcc, OBJID_CLIENT,dChildID ); + // break; + case UM_EVENT_STATE_ARMED: + UpdateAccFocus(pXAcc); + NotifyWinEvent( EVENT_OBJECT_FOCUS,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_MENU_START: + NotifyWinEvent( EVENT_SYSTEM_MENUSTART,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_MENU_END: + NotifyWinEvent( EVENT_SYSTEM_MENUEND,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_MENUPOPUPSTART: + NotifyWinEvent( EVENT_SYSTEM_MENUPOPUPSTART,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_MENUPOPUPEND: + NotifyWinEvent( EVENT_SYSTEM_MENUPOPUPEND,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_SELECTION_CHANGED: + NotifyWinEvent( EVENT_OBJECT_SELECTION,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_SELECTION_CHANGED_ADD: + NotifyWinEvent( EVENT_OBJECT_SELECTIONADD,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_SELECTION_CHANGED_REMOVE: + NotifyWinEvent( EVENT_OBJECT_SELECTIONREMOVE,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_SELECTION_CHANGED_WITHIN: + NotifyWinEvent( EVENT_OBJECT_SELECTIONWITHIN,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_OBJECT_VALUECHANGE: + UpdateValue(pXAcc); + NotifyWinEvent( EVENT_OBJECT_VALUECHANGE,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_OBJECT_NAMECHANGE: + NotifyWinEvent( EVENT_OBJECT_NAMECHANGE,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_OBJECT_DESCRIPTIONCHANGE: + NotifyWinEvent( EVENT_OBJECT_DESCRIPTIONCHANGE,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_OBJECT_DEFACTIONCHANGE: + NotifyWinEvent( IA2_EVENT_ACTION_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_OBJECT_CARETCHANGE: + NotifyWinEvent( IA2_EVENT_TEXT_CARET_MOVED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_OBJECT_TEXTCHANGE: + NotifyWinEvent( IA2_EVENT_TEXT_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_ACTIVE_DESCENDANT_CHANGED: + UpdateAccFocus(pXAcc); + NotifyWinEvent( EVENT_OBJECT_FOCUS,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_BOUNDRECT_CHANGED: + NotifyWinEvent( EVENT_OBJECT_LOCATIONCHANGE,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_VISIBLE_DATA_CHANGED: + NotifyWinEvent( IA2_EVENT_VISIBLE_DATA_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_SHOW : + NotifyWinEvent( EVENT_OBJECT_SHOW,hAcc, OBJID_CLIENT,dChildID ); + NotifyWinEvent( EVENT_SYSTEM_FOREGROUND,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_TABLE_CAPTION_CHANGED: + NotifyWinEvent( IA2_EVENT_TABLE_CAPTION_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_TABLE_COLUMN_DESCRIPTION_CHANGED: + NotifyWinEvent( IA2_EVENT_TABLE_COLUMN_DESCRIPTION_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_TABLE_COLUMN_HEADER_CHANGED: + NotifyWinEvent( IA2_EVENT_TABLE_COLUMN_HEADER_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_TABLE_MODEL_CHANGED: + NotifyWinEvent( IA2_EVENT_TABLE_MODEL_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_TABLE_ROW_HEADER_CHANGED: + NotifyWinEvent( IA2_EVENT_TABLE_ROW_HEADER_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_TABLE_SUMMARY_CHANGED: + NotifyWinEvent( IA2_EVENT_TABLE_SUMMARY_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_TABLE_ROW_DESCRIPTION_CHANGED: + NotifyWinEvent( IA2_EVENT_TABLE_ROW_DESCRIPTION_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_OBJECT_REORDER: + NotifyWinEvent( EVENT_OBJECT_REORDER,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_PAGE_CHANGED: + NotifyWinEvent( IA2_EVENT_PAGE_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_CHILD_REMOVED: + NotifyWinEvent( EVENT_OBJECT_DESTROY,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_CHILD_ADDED: + NotifyWinEvent( EVENT_OBJECT_CREATE ,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_OBJECT_PAGECHANGED: + NotifyWinEvent( IA2_EVENT_PAGE_CHANGED ,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_TEXT_SELECTION_CHANGED: + NotifyWinEvent( IA2_EVENT_TEXT_SELECTION_CHANGED ,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_SECTION_CHANGED: + NotifyWinEvent( IA2_EVENT_SECTION_CHANGED ,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_COLUMN_CHANGED: + NotifyWinEvent( IA2_EVENT_TEXT_COLUMN_CHANGED ,hAcc, OBJID_CLIENT,dChildID ); + break; + default: + break; + } + + return sal_True; +} + +/** + * Get Parent XAccessible interface by XAccessible interface. + * @param pXAcc XAccessible interface. + * @return Parent XAccessible interface. + */ +XAccessible* AccObjectWinManager::GetParentXAccessible( XAccessible* pXAcc ) +{ + AccObject* pObj= GetAccObjByXAcc(pXAcc); + if( pObj ==NULL ) + return NULL; + if(pObj->GetParentObj()) + { + pObj = pObj->GetParentObj(); + return pObj->GetXAccessible().get(); + } + return NULL; +} + +/** + * Get Parent role by XAccessible interface. + * @param pXAcc XAccessible interface. + * @return Parent role. + */ +short AccObjectWinManager::GetParentRole( XAccessible* pXAcc ) +{ + AccObject* pObj= GetAccObjByXAcc(pXAcc); + if( pObj ==NULL ) + return -1; + if(pObj->GetParentObj()) + { + pObj = pObj->GetParentObj(); + if(pObj->GetXAccessible().is()) + { + XAccessible* pXAcc = pObj->GetXAccessible().get(); + Reference< XAccessibleContext > pRContext = pXAcc->getAccessibleContext(); + if(pRContext.is()) + return pRContext->getAccessibleRole(); + } + } + return -1; +} + +/** + * Update focus objcet by new focused XAccessible interface. + * @param newFocus New XAccessible interface that gets focus. + * @return + */ +void AccObjectWinManager::UpdateAccFocus(XAccessible* newFocus) +{ + AccObject* pAccObjNew = GetAccObjByXAcc(newFocus); + if(pAccObjNew) + { + AccObject* pAccObjOld = GetAccObjByXAcc(oldFocus); + oldFocus = newFocus; + pAccObjNew->setFocus(); + //if old == new, the pAccObjNew will be without focused state + if (pAccObjOld && pAccObjOld != pAccObjNew) + pAccObjOld->unsetFocus(); + } +} + +/** + * Update selected objcet by new focused XAccessible interface. + * @param pXAcc XAccessible interface that has selected child changed. + * @return Selected children count. + */ +int AccObjectWinManager::UpdateAccSelection(XAccessible* pXAcc) +{ + XAccessibleSelection* pSelection = NULL; + Reference< XAccessibleContext > pRContext; + + if( pXAcc == NULL) + return sal_False; + + pRContext = pXAcc->getAccessibleContext(); + if( !pRContext.is() ) + return sal_False; + + Reference< XAccessibleSelection > pRSelection(pRContext,UNO_QUERY); + if( !pRSelection.is() ) + return sal_False; + + AccObject* pAccObj = GetAccObjByXAcc(pXAcc); + if(pAccObj==NULL) + return sal_False; + + Reference<XAccessible> pRChild = NULL; + AccObject* pAccChildObj = NULL; + int selectNum= pRSelection->getSelectedAccessibleChildCount(); + + IAccSelectionList oldSelection = pAccObj->GetSelection(); + + if(selectNum > 4)//for selected. + return selectNum; + if(selectNum == 1 && oldSelection.size() == 0) + return 1; + + for (int i=0;i<selectNum;i++) + { + pRChild = pRSelection->getSelectedAccessibleChild(i); + if(!pRChild.is()) + { + continue; + } + Reference<XAccessibleContext> pRChildContext = pRChild->getAccessibleContext(); + if(!pRChildContext.is()) + { + continue; + } + long index = pRChildContext->getAccessibleIndexInParent(); + IAccSelectionList::iterator temp = oldSelection.find(index); + if ( temp != oldSelection.end() ) + { + oldSelection.erase(index); + continue; + } + + pAccChildObj = NULL; + pAccChildObj = GetAccObjByXAcc(pRChild.get()); + if(!pAccChildObj) + { + InsertAccObj(pRChild.get(), pXAcc,pAccObj->GetParentHWND()); + pAccChildObj = GetAccObjByXAcc(pRChild.get()); + } + + pAccObj->AddSelect(index, pAccChildObj); + + if(pAccChildObj != NULL) + NotifyWinEvent(EVENT_OBJECT_SELECTIONADD,pAccObj->GetParentHWND(), OBJID_CLIENT,pAccChildObj->GetResID()); + } + + IAccSelectionList::iterator iter = oldSelection.begin(); + while(iter!=oldSelection.end()) + { + pAccObj->GetSelection().erase(iter->first); + pAccChildObj = (AccObject*)(iter->second); + if(pAccChildObj != NULL) + NotifyWinEvent(EVENT_OBJECT_SELECTIONREMOVE,pAccObj->GetParentHWND(), OBJID_CLIENT,pAccChildObj->GetResID()); + iter++; + } + return 0; + +} + +/** + * Delete child element from children list. + * @param pObj Child element that should be removed from parant child list. + * @return + */ +void AccObjectWinManager::DeleteAccChildNode( AccObject* pObj ) +{ + AccObject *parentAccObj = pObj->GetParentObj(); + if( parentAccObj ) + parentAccObj->DeleteChild( pObj ); +} + +/** + * Delete XAccessible items in top window handle hashtable + * @param pXAcc XAccessible interface. + * @return + */ +void AccObjectWinManager::DeleteFromHwndXAcc(XAccessible* pXAcc ) +{ + XHWNDToXAccHash::iterator iter = HwndXAcc.begin(); + while(iter!=HwndXAcc.end()) + { + if(iter->second == pXAcc ) + { + HwndXAcc.erase(iter); + return; + } + iter++; + } +} + +/** + * Delete Delete all children with the tree root of XAccessible pointer + * @param pXAcc Tree root XAccessible interface. + * @return + */ +void AccObjectWinManager::DeleteChildrenAccObj(XAccessible* pXAcc) +{ + vos::OGuard aGuard( aDeleteMutex ); + AccObject* currentObj=NULL; + AccObject* childObj=NULL; + XAccessible* pTmpXAcc=NULL; + + currentObj = GetAccObjByXAcc( pXAcc); + if(currentObj) + { + childObj = currentObj->NextChild(); + while(childObj) + { + pTmpXAcc = GetXAccByAccObj(childObj); + if(pTmpXAcc) + { + DeleteChildrenAccObj(pTmpXAcc); + DeleteAccObj(pTmpXAcc); + } + childObj = currentObj->NextChild(); + } + } +} + +/** + * Delete Delete Acc object self. + * @param pXAcc The XAccessible interface. + * @return + */ +void AccObjectWinManager::DeleteAccObj( XAccessible* pXAcc ) +{ + vos::OGuard aGuard( aDeleteMutex ); + if( pXAcc == NULL ) + return; + XIdToAccObjHash::iterator temp = XIdAccList.find(pXAcc); + if( temp != XIdAccList.end() ) + { + ResIdGen.SetSub( temp->second.GetResID() ); + } + else + { + return; + } + + AccObject& accObj = temp->second; + DeleteAccChildNode( &accObj ); + DeleteAccListener( &accObj ); + if( accObj.GetIMAccessible() ) + { + accObj.GetIMAccessible()->Release(); + } + XIdAccList.erase( pXAcc ); + XResIdAccList.erase( accObj.GetResID() ); + DeleteFromHwndXAcc(pXAcc); +} + +/** + * Delete listener that inspects some XAccessible object + * @param pAccObj Accobject pointer. + * @return + */ +void AccObjectWinManager::DeleteAccListener( AccObject* pAccObj ) +{ + AccEventListener* listener = pAccObj->getListener(); + if( listener==NULL ) + return; + listener->removeMeFromBroadcaster(); + pAccObj->SetListener(NULL); +} + +/** + * Generate a child ID, which is used for AT + * @param + * @return New resource ID. + */ +inline long AccObjectWinManager::ImpleGenerateResID() +{ + return ResIdGen.GenerateNewResID(); +} + +/** + * Insert all children of the current acc object + * @param pXAcc XAccessible interface + * @param pWnd Top Window handle + * @return The calling result. + */ +sal_Bool AccObjectWinManager::InsertChildrenAccObj( com::sun::star::accessibility::XAccessible* pXAcc, + HWND pWnd) +{ + if(!IsContainer(pXAcc)) + return sal_False; + + Reference< XAccessibleContext > pRContext; + + if( pXAcc == NULL) + return sal_False; + pRContext = pXAcc->getAccessibleContext(); + if( !pRContext.is() ) + return sal_False; + + short role = pRContext->getAccessibleRole(); + + if(com::sun::star::accessibility::AccessibleRole::DOCUMENT == role ) + { + if(IsStateManageDescendant(pXAcc)) + { + return sal_True; + } + } + + int count = pRContext->getAccessibleChildCount(); + for (int i=0;i<count;i++) + { + Reference<XAccessible> mxAccessible + = pRContext->getAccessibleChild(i); + XAccessible* mpAccessible = mxAccessible.get(); + if(mpAccessible != NULL) + { + InsertAccObj( mpAccessible,pXAcc,pWnd ); + InsertChildrenAccObj(mpAccessible,pWnd); + } + } + + return sal_True; +} + +/** + * Insert child object. + * @param pCurObj The child object + * @param pParentObj The parant object + * @param pWnd Top window handle. + * @return + */ +void AccObjectWinManager::InsertAccChildNode( AccObject* pCurObj, AccObject* pParentObj, HWND /* pWnd */ ) +{ + if(pCurObj) + { + if(pParentObj) + { + pParentObj->InsertChild(pCurObj); + } + else + { + pCurObj->UpdateValidWindow(); + } + } +} + +/** + * Insert child object. + * @param pCurObj The child object + * @param pParentObj The parant object + * @param pWnd Top window handle. + * @return + */ +sal_Bool AccObjectWinManager::InsertAccObj( XAccessible* pXAcc,XAccessible* pParentXAcc,HWND pWnd ) +{ + XIdToAccObjHash::iterator itXacc = XIdAccList.find( (void*)pXAcc ); + if (itXacc != XIdAccList.end() ) + { + short nCurRole =GetRole(pXAcc); + if (AccessibleRole::SHAPE == nCurRole) + { + AccObject &objXacc = itXacc->second; + AccObject *pObjParent = objXacc.GetParentObj(); + if (pObjParent && + pObjParent->GetXAccessible().is() && + pObjParent->GetXAccessible().get() != pParentXAcc) + { + XIdToAccObjHash::iterator itXaccParent = XIdAccList.find( (void*)pParentXAcc ); + if(itXaccParent != XIdAccList.end()) + { + objXacc.SetParentObj(&(itXaccParent->second)); + } + } + } + return sal_False; + } + + + Reference< XAccessibleContext > pRContext; + + if( pXAcc == NULL) + return sal_False; + + pRContext = pXAcc->getAccessibleContext(); + if( !pRContext.is() ) + return sal_False; + + if( pWnd == NULL ) + { + if(pParentXAcc) + { + AccObject* pObj = GetAccObjByXAcc(pParentXAcc); + if(pObj) + pWnd = pObj->GetParentHWND(); + } + if( pWnd == NULL ) + return sal_False; + } + + AccObject pObj( pXAcc,pAgent ); + if( pObj.GetIMAccessible() == NULL ) + return sal_False; + pObj.SetResID( this->ImpleGenerateResID()); + pObj.SetParentHWND( pWnd ); + + //for file name support + if ( pObj.GetRole() == DOCUMENT ) + { + XHWNDToDocumentHash::iterator aIter = XHWNDDocList.find( (long)pWnd ); + if ( aIter != XHWNDDocList.end() ) + { + XHWNDDocList.erase( aIter ); + } + XHWNDDocList.insert( XHWNDToDocumentHash::value_type( (long)pWnd, pXAcc ) ); + + } + //end of file name + + AccEventListener* listener = createAccEventListener(pXAcc, pAgent); + if(listener==NULL) + return sal_False; + Reference<XAccessibleComponent> xComponent(pRContext,UNO_QUERY); + Reference<XAccessibleEventBroadcaster> broadcaster(xComponent,UNO_QUERY); + if (broadcaster.is()) + { + Reference <XAccessibleEventListener> pp ( + static_cast< XAccessibleEventListener* >(listener),UNO_QUERY ); + if(pp.is()) + { + broadcaster->addEventListener(pp); + } + else + { + delete listener; + return sal_False; + } + } + else + return sal_False; + + XIdAccList.insert( XIdToAccObjHash::value_type( (void*)pXAcc, pObj )); + XIdToAccObjHash::iterator pIndTemp = XIdAccList.find( (void*)pXAcc ); + XResIdAccList.insert(XResIdToAccObjHash::value_type(pObj.GetResID(),&(pIndTemp->second))); + + AccObject* pCurObj = GetAccObjByXAcc(pXAcc); + if( pCurObj ) + { + pCurObj->SetListener( listener ); + if(listener != NULL) + listener->acquire(); + } + + AccObject* pParentObj = GetAccObjByXAcc(pParentXAcc); + InsertAccChildNode(pCurObj,pParentObj,pWnd); + if( pCurObj ) + pCurObj->UpdateAccessibleInfoFromUnoToMSAA(); + return sal_True; +} + + +/** + * save the pair <topwindowhandle, XAccessible> + * @param hWnd, top window handle + * @param pXAcc XAccessible interface for top window + * @return void + */ +void AccObjectWinManager::SaveTopWindowHandle(HWND hWnd, com::sun::star::accessibility::XAccessible* pXAcc) +{ + HwndXAcc.insert( XHWNDToXAccHash::value_type( hWnd,(void*)pXAcc ) ); +} + + +/** + * create the corresponding listener. + * @param pXAcc XAccessible interface. + * @param Agent The agent kept in all listeners,it's the sole interface by which + * listener communicate with windows manager. + * @return + */ +AccEventListener* AccObjectWinManager::createAccEventListener(XAccessible* pXAcc, AccObjectManagerAgent* /* Agent */ ) +{ + AccEventListener* listener = NULL; + Reference<XAccessibleContext> xContext(pXAcc->getAccessibleContext(),UNO_QUERY); + if(xContext.is()) + { + switch( xContext->getAccessibleRole() ) + { + case /*AccessibleRole::*/DIALOG: + listener = new AccDialogEventListener(pXAcc,pAgent); + break; + case /*AccessibleRole::*/FRAME: + listener = new AccFrameEventListener(pXAcc,pAgent); + break; + case /*AccessibleRole::*/WINDOW: + listener = new AccWindowEventListener(pXAcc,pAgent); + break; + case /*AccessibleRole::*/ROOT_PANE: + listener = new AccFrameEventListener(pXAcc,pAgent); + break; + //Container + case /*AccessibleRole::*/CANVAS: + case /*AccessibleRole::*/COMBO_BOX: + case /*AccessibleRole::*/DOCUMENT: + case /*AccessibleRole::*/END_NOTE: + case /*AccessibleRole::*/FILLER: + case /*AccessibleRole::*/FOOTNOTE: + case /*AccessibleRole::*/FOOTER: + case /*AccessibleRole::*/HEADER: + case /*AccessibleRole::*/LAYERED_PANE: + case /*AccessibleRole::*/MENU_BAR: + case /*AccessibleRole::*/POPUP_MENU: + case /*AccessibleRole::*/OPTION_PANE: + case /*AccessibleRole::*/PAGE_TAB: + case /*AccessibleRole::*/PAGE_TAB_LIST: + case /*AccessibleRole::*/PANEL: + case /*AccessibleRole::*/SCROLL_PANE: + case /*AccessibleRole::*/SPLIT_PANE: + case /*AccessibleRole::*/STATUS_BAR: + case /*AccessibleRole::*/TABLE_CELL: + case /*AccessibleRole::*/TOOL_BAR: + case /*AccessibleRole::*/VIEW_PORT: + listener = new AccContainerEventListener(pXAcc,pAgent); + break; + case /*AccessibleRole::*/PARAGRAPH: + case /*AccessibleRole::*/HEADING: + listener = new AccParagraphEventListener(pXAcc,pAgent); + break; + //Component + case /*AccessibleRole::*/CHECK_BOX: + case /*AccessibleRole::*/ICON: + case /*AccessibleRole::*/LABEL: + case /*AccessibleRole::*/MENU_ITEM: + case /*AccessibleRole::*/CHECK_MENU_ITEM: + case /*AccessibleRole::*/RADIO_MENU_ITEM: + case /*AccessibleRole::*/PUSH_BUTTON: + case /*AccessibleRole::*/RADIO_BUTTON: + case /*AccessibleRole::*/SCROLL_BAR: + case /*AccessibleRole::*/SEPARATOR: + case /*AccessibleRole::*/TOGGLE_BUTTON: + case /*AccessibleRole::*/BUTTON_DROPDOWN: + case /*AccessibleRole::*/TOOL_TIP: + case /*AccessibleRole::*/SPIN_BOX: + case DATE_EDITOR: + listener = new AccComponentEventListener(pXAcc,pAgent); + break; + //text component + case /*AccessibleRole::*/TEXT: + listener = new AccTextComponentEventListener(pXAcc,pAgent); + break; + //menu + case /*AccessibleRole::*/MENU: + listener = new AccMenuEventListener(pXAcc,pAgent); + break; + //object container + case /*AccessibleRole::*/SHAPE: + + case /*AccessibleRole::*/EMBEDDED_OBJECT: + case /*AccessibleRole::*/GRAPHIC: + case /*AccessibleRole::*/TEXT_FRAME: + listener = new AccObjectContainerEventListener(pXAcc,pAgent); + break; + //descendmanager + case /*AccessibleRole::*/LIST: + listener = new AccListEventListener(pXAcc,pAgent); + break; + case /*AccessibleRole::*/TREE: + listener = new AccTreeEventListener(pXAcc,pAgent); + break; + //special + case /*AccessibleRole::*/COLUMN_HEADER: + case /*AccessibleRole::*/TABLE: + listener = new AccTableEventListener(pXAcc,pAgent); + break; + default: + listener = new AccContainerEventListener(pXAcc,pAgent); + break; + } + } + + return listener; +} + +/** + * state is a combination integer, each bit of which represents a single state, + * such as focused,1 for the state on,0 for the state off. Here call COM interface + * to modify the state value, including DecreaseState. + * @param pXAcc XAccessible interface. + * @param pState Changed state. + * @return + */ +void AccObjectWinManager::DecreaseState( XAccessible* pXAcc,unsigned short pState ) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->DecreaseState( pState ); +} + +/** + * state is a combination integer, each bit of which represents a single state,such as focused,1 for + * the state on,0 for the state off. Here call COM interface to modify the state value, including + * IncreaseState. + * @param pXAcc XAccessible interface. + * @param pState Changed state. + * @return + */ +void AccObjectWinManager::IncreaseState( XAccessible* pXAcc,unsigned short pState ) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->IncreaseState( pState ); +} + +void AccObjectWinManager::UpdateState( com::sun::star::accessibility::XAccessible* pXAcc ) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->UpdateState( ); +} + +/** + * Set corresponding com object's accessible name via XAccessilbe interface and new + * name + * @param pXAcc XAccessible interface. + * @return + */ +void AccObjectWinManager::UpdateAccName( XAccessible* pXAcc ) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->UpdateName(); +} + +void AccObjectWinManager::UpdateAction( XAccessible* pXAcc ) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->UpdateAction(); +} + +void AccObjectWinManager::UpdateDescription( XAccessible* pXAcc ) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if ( pAccObj ) + pAccObj->UpdateDescription(); +} + +/** + * Set corresponding com object's accessible location via XAccessilbe interface and new + * location. + * @param pXAcc XAccessible interface. + * @return + */ +void AccObjectWinManager::SetLocation( XAccessible* pXAcc, long /*top*/, long /*left*/, long /*width*/, long /*height*/ ) +{ + AccObject* pObj = GetAccObjByXAcc( pXAcc ); + //get the location from XComponent. + Reference< XAccessibleContext > pRContext = pXAcc->getAccessibleContext(); + if( pObj ) + pObj->UpdateLocation(); +} + +/** + * Set corresponding com object's value via XAccessilbe interface and new value. + * @param pXAcc XAccessible interface. + * @param pAny new value. + * @return + */ +void AccObjectWinManager::SetValue( XAccessible* pXAcc, Any pAny ) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->SetValue( pAny ); +} + +/** + * Set corresponding com object's value via XAccessilbe interface. + * @param pXAcc XAccessible interface. + * @return + */ +void AccObjectWinManager::UpdateValue( XAccessible* pXAcc ) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->UpdateValue(); +} + +/** + * Set corresponding com object's name via XAccessilbe interface and new name. + * @param pXAcc XAccessible interface. + * @param newName new name + * @return + */ +void AccObjectWinManager::SetAccName( XAccessible* pXAcc, Any newName) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->SetName( newName ); +} + +/** + * Set corresponding com object's description via XAccessilbe interface and new description. + * @param pXAcc XAccessible interface. + * @param newDesc new description + * @return + */ +void AccObjectWinManager::SetDescription( XAccessible* pXAcc, Any newDesc ) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->SetDescription( newDesc ); +} + +/** + * Set corresponding com object's role via XAccessilbe interface and new role. + * @param pXAcc XAccessible interface. + * @param Role new role + * @return + */ +void AccObjectWinManager::SetRole( XAccessible* pXAcc, long Role ) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->SetRole( (short)Role ); +} + +/** + * Judge if a XAccessible object is a container object. + * @param pAccessible XAccessible interface. + * @return If XAccessible object is container. + */ +sal_Bool AccObjectWinManager::IsContainer(XAccessible* pAccessible) +{ + try + { + if(pAccessible) + { + Reference<XAccessibleContext> xContext(pAccessible->getAccessibleContext(),UNO_QUERY); + if(xContext.is()) + { + switch( xContext->getAccessibleRole() ) + { + case /*AccessibleRole::*/DIALOG: + case /*AccessibleRole::*/FRAME: + case /*AccessibleRole::*/WINDOW: + case /*AccessibleRole::*/ROOT_PANE: + case /*AccessibleRole::*/CANVAS: + case /*AccessibleRole::*/COMBO_BOX: + case /*AccessibleRole::*/DOCUMENT: + case /*AccessibleRole::*/EMBEDDED_OBJECT: + case /*AccessibleRole::*/END_NOTE: + case /*AccessibleRole::*/FILLER: + case /*AccessibleRole::*/FOOTNOTE: + case /*AccessibleRole::*/FOOTER: + case /*AccessibleRole::*/GRAPHIC: + case /*AccessibleRole::*/GROUP_BOX: + case /*AccessibleRole::*/HEADER: + case /*AccessibleRole::*/LAYERED_PANE: + case /*AccessibleRole::*/MENU_BAR: + case /*AccessibleRole::*/POPUP_MENU: + case /*AccessibleRole::*/OPTION_PANE: + case /*AccessibleRole::*/PAGE_TAB: + case /*AccessibleRole::*/PAGE_TAB_LIST: + case /*AccessibleRole::*/PANEL: + case /*AccessibleRole::*/SCROLL_PANE: + case /*AccessibleRole::*/SPLIT_PANE: + case /*AccessibleRole::*/STATUS_BAR: + case /*AccessibleRole::*/TABLE_CELL: + case /*AccessibleRole::*/TEXT_FRAME: + case /*AccessibleRole::*/TOOL_BAR: + case /*AccessibleRole::*/VIEW_PORT: + case /*AccessibleRole::*/SHAPE: + return sal_True; + break; + case /*AccessibleRole::*/COLUMN_HEADER: + case /*AccessibleRole::*/TABLE: + if(!IsStateManageDescendant(pAccessible)) + return sal_True; + break; + case /*AccessibleRole::*/MENU: + return sal_True; + break; + default: + return sal_False; + } + } + } + } + catch(...) + { + return sal_False; + } + return sal_False; +} + +/** + * Judge if a XAccessible object has ManageDescendant event. + * @param pAccessible XAccessible interface. + * @return If XAccessible object is managedescendant. + */ +bool AccObjectWinManager::IsStateManageDescendant(XAccessible* pAccessible) +{ + if(pAccessible) + { + Reference<XAccessibleContext> xContext(pAccessible->getAccessibleContext(),UNO_QUERY); + if(xContext.is()) + { + Reference< XAccessibleStateSet > pRState = xContext->getAccessibleStateSet(); + if( !pRState.is() ) + return sal_False; + + Sequence<short> pStates = pRState->getStates(); + int count = pStates.getLength(); + for( int iIndex = 0;iIndex < count;iIndex++ ) + { + if(pStates[iIndex] == /*AccessibleStateType::*/MANAGES_DESCENDANTS) + return sal_True; + } + } + } + return sal_False; +} + +/** + * Query and get IAccessible interface by XAccessible interface from list. + * @param pXAcc XAccessible interface. + * @return Com accobject interface. + */ +IMAccessible* AccObjectWinManager::GetIMAccByXAcc(XAccessible* pXAcc) +{ + AccObject* pAccObj = GetAccObjByXAcc(pXAcc); + if(pAccObj) + { + return pAccObj->GetIMAccessible(); + } + else + { + return NULL; + } +} + +/** + * Query and get IAccessible interface by child id from list. + * @param resID, childID. + * @return Com accobject interface. + */ +IMAccessible * AccObjectWinManager::GetIAccessibleFromResID(long resID) +{ + XResIdToAccObjHash::iterator pIndTemp = XResIdAccList.find( resID ); + if ( pIndTemp == XResIdAccList.end() ) + return NULL; + + AccObject* pObj = pIndTemp->second; + + if(pObj->GetIMAccessible()) + return pObj->GetIMAccessible(); + return NULL; +} +/** + * Notify some object will be destroyed. + * @param pXAcc XAccessible interface. + * @return Com accobject interface. + */ +void AccObjectWinManager::NotifyDestroy(XAccessible* pXAcc) +{ + AccObject* accObj = GetAccObjByXAcc(pXAcc); + if(accObj) + { + accObj->NotifyDestroy(sal_True); + } +} + + +void AccObjectWinManager::UpdateChildState(com::sun::star::accessibility::XAccessible* pAccSubMenu) +{ + Reference<com::sun::star::accessibility::XAccessibleContext> xContext(pAccSubMenu,UNO_QUERY); + if (!xContext.is()) + { + return; + } + sal_Int32 nCount = xContext->getAccessibleChildCount(); + for (sal_Int32 i = 0 ; i < nCount ; ++i) + { + Reference<com::sun::star::accessibility::XAccessible> xChild = xContext->getAccessibleChild(i); + if (xChild.is()) + { + AccObject *pObj = GetAccObjByXAcc(xChild.get()); + if (pObj) + { + pObj->UpdateState(); + } + } + } +} + + +bool AccObjectWinManager::IsSpecialToolboItem(com::sun::star::accessibility::XAccessible* pXAcc) +{ + if (pXAcc && oldFocus != pXAcc) + { + if(GetParentRole(pXAcc) == TOOL_BAR) + { + Reference< XAccessibleContext > pRContext(pXAcc->getAccessibleContext()); + if (pRContext.is()) + { + if(pRContext->getAccessibleRole() == TOGGLE_BUTTON) + { + return true; + } + } + } + } + return false; +} + +short AccObjectWinManager::GetRole(com::sun::star::accessibility::XAccessible* pXAcc) +{ + assert(pXAcc != NULL); + Reference<com::sun::star::accessibility::XAccessibleContext> xContext(pXAcc->getAccessibleContext(),UNO_QUERY); + if(xContext.is()) + { + return xContext->getAccessibleRole(); + } + return -1; +} + +XAccessible* AccObjectWinManager::GetAccDocByHWND( long pWnd ) +{ + XHWNDToDocumentHash::iterator aIter; + aIter = XHWNDDocList.find( pWnd ); + if ( aIter != XHWNDDocList.end() ) + { + return aIter->second; + } + + return NULL; +} + +XAccessible* AccObjectWinManager::GetAccDocByAccTopWin( XAccessible* pXAcc ) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + long pWnd = (long)( pAccObj->GetParentHWND() ); + return GetAccDocByHWND( pWnd ); +} + +bool AccObjectWinManager::IsTopWinAcc( com::sun::star::accessibility::XAccessible* pXAcc ) +{ + bool bRet = false; + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if ( pAccObj ) + { + bRet = ( pAccObj->GetParentObj() == NULL ); + } + return bRet; +}
\ No newline at end of file |