    /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
    /*
     * This file is part of the LibreOffice project.
     *
     * This Source Code Form is subject to the terms of the Mozilla Public
     * License, v. 2.0. If a copy of the MPL was not distributed with this
     * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     *
     * This file incorporates work covered by the following license notice:
     *
     *   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 .
     */

    #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/AccessibleRole.hpp>
    #include <com/sun/star/accessibility/AccessibleStateType.hpp>

    #include <oleacc.h>
    #include <AccObjectWinManager.hxx>
    #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>

    using namespace std;
    using namespace com::sun::star::accessibility;
    using namespace com::sun::star::accessibility::AccessibleRole;
    using namespace com::sun::star::accessibility::AccessibleStateType;
    using namespace com::sun::star::uno;

    /**
       * 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 ):
            oldFocus( nullptr ),
            pAgent( Agent )
    {
    }

    /**
       * 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.
       */

    LRESULT
    AccObjectWinManager::Get_ToATInterface(HWND hWnd, long lParam, WPARAM wParam)
    {
        IMAccessible* pRetIMAcc = nullptr;

        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 );
            LRESULT 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 == nullptr)
            return nullptr;

        XIdToAccObjHash::iterator pIndTemp = XIdAccList.find( pXAcc );
        if ( pIndTemp == XIdAccList.end() )
            return nullptr;

        return &(pIndTemp->second);
    }

    /**
       * 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 nullptr;
        XAccessible* pXAcc = static_cast<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.
       */
    bool AccObjectWinManager::NotifyAccEvent(XAccessible* pXAcc,short state)
    {
        Reference< XAccessibleContext > pRContext;

        if( pXAcc == nullptr)
            return false;

        pRContext = pXAcc->getAccessibleContext();
        if( !pRContext.is() )
            return false;

        AccObject* selfAccObj= GetAccObjByXAcc(pXAcc);

        if(selfAccObj==nullptr)
            return false;

        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 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 ==nullptr )
            return nullptr;
        if(pObj->GetParentObj())
        {
            pObj = pObj->GetParentObj();
            return pObj->GetXAccessible().get();
        }
        return nullptr;
    }

    /**
       * Get Parent role by XAccessible interface.
       * @param pXAcc XAccessible interface.
       * @return Parent role.
       */
    short AccObjectWinManager::GetParentRole( XAccessible* pXAcc )
    {
        AccObject* pObj= GetAccObjByXAcc(pXAcc);
        if( pObj ==nullptr )
            return -1;
        if(pObj->GetParentObj())
        {
            pObj = pObj->GetParentObj();
            if(pObj->GetXAccessible().is())
            {
                Reference< XAccessibleContext > pRContext = pObj->GetXAccessible()->getAccessibleContext();
                if(pRContext.is())
                    return pRContext->getAccessibleRole();
            }
        }
        return -1;
    }

    /**
       * Update focus object 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 object by new focused XAccessible interface.
       * @param pXAcc XAccessible interface that has selected child changed.
       * @return Selected children count.
       */
    int AccObjectWinManager::UpdateAccSelection(XAccessible* pXAcc)
    {
        Reference< XAccessibleContext > pRContext;

        if( pXAcc == nullptr)
            return 0;

        pRContext = pXAcc->getAccessibleContext();
        if( !pRContext.is() )
            return 0;

        Reference< XAccessibleSelection > pRSelection(pRContext,UNO_QUERY);
        if( !pRSelection.is() )
            return 0;

        AccObject* pAccObj = GetAccObjByXAcc(pXAcc);
        if(pAccObj==nullptr)
            return 0;

        Reference<XAccessible> pRChild = nullptr;
        AccObject* pAccChildObj = nullptr;
        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 = GetAccObjByXAcc(pRChild.get());
            if(!pAccChildObj)
            {
                InsertAccObj(pRChild.get(), pXAcc,pAccObj->GetParentHWND());
                pAccChildObj = GetAccObjByXAcc(pRChild.get());
            }

            pAccObj->AddSelect(index, pAccChildObj);

            if(pAccChildObj != nullptr)
                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 = iter->second;
            if(pAccChildObj != nullptr)
                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 const * pXAcc )
    {
        XHWNDToXAccHash::iterator iter = HwndXAcc.begin();
        while(iter!=HwndXAcc.end())
        {
            if(iter->second == pXAcc )
            {
                HwndXAcc.erase(iter);
                return;
            }
            ++iter;
        }
    }

    /**
       * Delete all children with the tree root of XAccessible pointer
       * @param pXAcc Tree root XAccessible interface.
       * @return
       */
    void AccObjectWinManager::DeleteChildrenAccObj(XAccessible* pXAcc)
    {
        AccObject* currentObj=nullptr;
        AccObject* childObj=nullptr;

        currentObj =  GetAccObjByXAcc( pXAcc);
        if(currentObj)
        {
            childObj = currentObj->NextChild();
            while(childObj)
            {
                XAccessible *const pTmpXAcc = childObj->GetXAccessible().get();
                if(pTmpXAcc)
                {
                    DeleteChildrenAccObj(pTmpXAcc);
                    DeleteAccObj(pTmpXAcc);
                }
                childObj = currentObj->NextChild();
            }
        }
    }

    /**
       * Delete Acc object self.
       * @param pXAcc The XAccessible interface.
       * @return
       */
    void AccObjectWinManager::DeleteAccObj( XAccessible* pXAcc )
    {
        if( pXAcc == nullptr )
            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();
        }
        size_t i = XResIdAccList.erase(accObj.GetResID());
        assert(i != 0);
        DeleteFromHwndXAcc(pXAcc);
        if( accObj.GetRole() == DOCUMENT ||
            accObj.GetRole() == DOCUMENT_PRESENTATION ||
            accObj.GetRole() == DOCUMENT_SPREADSHEET ||
            accObj.GetRole() == DOCUMENT_TEXT )
        {
            XHWNDDocList.erase(accObj.GetParentHWND());
        }
        XIdAccList.erase(pXAcc); // note: this invalidates accObj so do it last!
    }

    /**
       * Delete listener that inspects some XAccessible object
       * @param pAccObj Accobject pointer.
       * @return
       */
    void AccObjectWinManager::DeleteAccListener( AccObject*  pAccObj )
    {
        AccEventListener* listener = pAccObj->getListener();
        if( listener==nullptr )
            return;
        listener->RemoveMeFromBroadcaster();
        pAccObj->SetListener(nullptr);
    }

    /**
       * 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.
       */
    bool AccObjectWinManager::InsertChildrenAccObj( css::accessibility::XAccessible* pXAcc,
            HWND pWnd)
    {
        if(!IsContainer(pXAcc))
            return false;

        Reference< XAccessibleContext > pRContext;

        if( pXAcc == nullptr)
            return false;
        pRContext = pXAcc->getAccessibleContext();
        if( !pRContext.is() )
            return false;

        short role = pRContext->getAccessibleRole();

        if(css::accessibility::AccessibleRole::DOCUMENT == role ||
                css::accessibility::AccessibleRole::DOCUMENT_PRESENTATION == role ||
                css::accessibility::AccessibleRole::DOCUMENT_SPREADSHEET == role ||
                css::accessibility::AccessibleRole::DOCUMENT_TEXT == role)
        {
            if(IsStateManageDescendant(pXAcc))
            {
                return true;
            }
        }

        int count = pRContext->getAccessibleChildCount();
        for (int i=0;i<count;i++)
        {
            Reference<XAccessible> mxAccessible
            = pRContext->getAccessibleChild(i);
            XAccessible* mpAccessible = mxAccessible.get();
            if(mpAccessible != nullptr)
            {
                InsertAccObj( mpAccessible,pXAcc,pWnd );
                InsertChildrenAccObj(mpAccessible,pWnd);
            }
        }

        return 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
       */
    bool AccObjectWinManager::InsertAccObj( XAccessible* pXAcc,XAccessible* pParentXAcc,HWND pWnd )
    {
        XIdToAccObjHash::iterator itXacc = XIdAccList.find( 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( pParentXAcc );
                    if(itXaccParent != XIdAccList.end())
                    {
                        objXacc.SetParentObj(&(itXaccParent->second));
                    }
                }
            }
            return false;
        }

        Reference< XAccessibleContext > pRContext;

        if( pXAcc == nullptr)
            return false;

        pRContext = pXAcc->getAccessibleContext();
        if( !pRContext.is() )
            return false;

        if( pWnd == nullptr )
        {
            if(pParentXAcc)
            {
                AccObject* pObj = GetAccObjByXAcc(pParentXAcc);
                if(pObj)
                    pWnd = pObj->GetParentHWND();
            }
            if( pWnd == nullptr )
                return false;
        }

        AccObject pObj( pXAcc,pAgent );
        if( pObj.GetIMAccessible() == nullptr )
            return false;
        pObj.SetResID( this->ImpleGenerateResID());
        pObj.SetParentHWND( pWnd );

        //for file name support
        if( pObj.GetRole() == DOCUMENT ||
            pObj.GetRole() == DOCUMENT_PRESENTATION ||
            pObj.GetRole() == DOCUMENT_SPREADSHEET ||
            pObj.GetRole() == DOCUMENT_TEXT )
        {
            XHWNDToDocumentHash::iterator aIter = XHWNDDocList.find(pWnd);
            if ( aIter != XHWNDDocList.end() )
            {
                XHWNDDocList.erase( aIter );
            }
            XHWNDDocList.emplace( pWnd, pXAcc );
        }
        //end of file name

        ::rtl::Reference<AccEventListener> const pListener =
            CreateAccEventListener(pXAcc);
        if (!pListener.is())
            return false;
        Reference<XAccessibleComponent> xComponent(pRContext,UNO_QUERY);
        Reference<XAccessibleEventBroadcaster> broadcaster(xComponent,UNO_QUERY);
        if (broadcaster.is())
        {
            Reference<XAccessibleEventListener> const xListener(pListener.get());
            broadcaster->addAccessibleEventListener(xListener);
        }
        else
            return false;

        XIdAccList.emplace(pXAcc, pObj);
        XIdToAccObjHash::iterator pIndTemp = XIdAccList.find( pXAcc );
        XResIdAccList.emplace(pObj.GetResID(),&(pIndTemp->second));

        AccObject* pCurObj = GetAccObjByXAcc(pXAcc);
        if( pCurObj )
        {
            pCurObj->SetListener(pListener);
        }

        AccObject* pParentObj = GetAccObjByXAcc(pParentXAcc);
        InsertAccChildNode(pCurObj,pParentObj,pWnd);
        if( pCurObj )
            pCurObj->UpdateAccessibleInfoFromUnoToMSAA();
        return 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, css::accessibility::XAccessible* pXAcc)
    {
        HwndXAcc.emplace(hWnd,pXAcc);
    }

    /** Create the corresponding listener.
     *  @param pXAcc XAccessible interface.
     */
    ::rtl::Reference<AccEventListener>
    AccObjectWinManager::CreateAccEventListener(XAccessible* pXAcc)
    {
        ::rtl::Reference<AccEventListener> pRet;
        Reference<XAccessibleContext> xContext(pXAcc->getAccessibleContext(),UNO_QUERY);
        if(xContext.is())
        {
            switch( xContext->getAccessibleRole() )
            {
            case /*AccessibleRole::*/DIALOG:
                pRet = new AccDialogEventListener(pXAcc,pAgent);
                break;
            case /*AccessibleRole::*/FRAME:
                pRet = new AccFrameEventListener(pXAcc,pAgent);
                break;
            case /*AccessibleRole::*/WINDOW:
                pRet = new AccWindowEventListener(pXAcc,pAgent);
                break;
            case /*AccessibleRole::*/ROOT_PANE:
                pRet = new AccFrameEventListener(pXAcc,pAgent);
                break;
                //Container
            case /*AccessibleRole::*/CANVAS:
            case /*AccessibleRole::*/COMBO_BOX:
            case /*AccessibleRole::*/DOCUMENT:
            case /*AccessibleRole::*/DOCUMENT_PRESENTATION:
            case /*AccessibleRole::*/DOCUMENT_SPREADSHEET:
            case /*AccessibleRole::*/DOCUMENT_TEXT:
            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:
                pRet = new AccContainerEventListener(pXAcc,pAgent);
                break;
            case /*AccessibleRole::*/PARAGRAPH:
            case /*AccessibleRole::*/HEADING:
                pRet = new AccParagraphEventListener(pXAcc,pAgent);
                break;
                //Component
            case /*AccessibleRole::*/CHECK_BOX:
            case /*AccessibleRole::*/ICON:
            case /*AccessibleRole::*/LABEL:
            case /*AccessibleRole::*/STATIC:
            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:
                pRet = new AccComponentEventListener(pXAcc,pAgent);
                break;
                //text component
            case /*AccessibleRole::*/TEXT:
                pRet = new AccTextComponentEventListener(pXAcc,pAgent);
                break;
                //menu
            case /*AccessibleRole::*/MENU:
                pRet = new AccMenuEventListener(pXAcc,pAgent);
                break;
                //object container
            case /*AccessibleRole::*/SHAPE:

            case /*AccessibleRole::*/EMBEDDED_OBJECT:
            case /*AccessibleRole::*/GRAPHIC:
            case /*AccessibleRole::*/TEXT_FRAME:
                pRet = new AccObjectContainerEventListener(pXAcc,pAgent);
                break;
                //descendmanager
            case /*AccessibleRole::*/LIST:
                pRet = new AccListEventListener(pXAcc,pAgent);
                break;
            case /*AccessibleRole::*/TREE:
                pRet = new AccTreeEventListener(pXAcc,pAgent);
                break;
                //special
            case /*AccessibleRole::*/COLUMN_HEADER:
            case /*AccessibleRole::*/TABLE:
                pRet = new AccTableEventListener(pXAcc,pAgent);
                break;
            default:
                pRet = new AccContainerEventListener(pXAcc,pAgent);
                break;
            }
        }
        return pRet;
    }

    /**
       * 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( css::accessibility::XAccessible* pXAcc )
    {
        AccObject* pAccObj = GetAccObjByXAcc( pXAcc );
        if( pAccObj )
            pAccObj->UpdateState( );
    }

    /**
       * Set corresponding com object's accessible name via XAccessible 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 XAccessible 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 XAccessible 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 XAccessible 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 XAccessible 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 XAccessible 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 XAccessible 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( static_cast<short>(Role) );
    }

    /**
       * Judge if a XAccessible object is a container object.
       * @param pAccessible XAccessible interface.
       * @return If XAccessible object is container.
       */
    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::*/DOCUMENT_PRESENTATION:
                    case /*AccessibleRole::*/DOCUMENT_SPREADSHEET:
                    case /*AccessibleRole::*/DOCUMENT_TEXT:
                    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 true;
                        break;
                    case /*AccessibleRole::*/COLUMN_HEADER:
                    case /*AccessibleRole::*/TABLE:
                        if(!IsStateManageDescendant(pAccessible))
                            return true;
                        break;
                    case /*AccessibleRole::*/MENU:
                        return true;
                        break;
                    default:
                        return false;
                    }
                }
            }
        }
        catch(...)
        {
            return false;
        }
        return 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 false;

                Sequence<short> pStates = pRState->getStates();
                int count = pStates.getLength();
                for( int iIndex = 0;iIndex < count;iIndex++ )
                {
                    if(pStates[iIndex] == /*AccessibleStateType::*/MANAGES_DESCENDANTS)
                        return true;
                }
            }
        }
        return 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 nullptr;
        }
    }

    /**
       * 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 nullptr;

        AccObject* pObj = pIndTemp->second;

        if(pObj->GetIMAccessible())
            return pObj->GetIMAccessible();
        return nullptr;
    }
    /**
       * 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(true);
        }
    }

    void AccObjectWinManager::UpdateChildState(css::accessibility::XAccessible* pAccSubMenu)
    {
        Reference<css::accessibility::XAccessibleContext> xContext(pAccSubMenu,UNO_QUERY);
        if (!xContext.is())
        {
            return;
        }
        sal_Int32 nCount = xContext->getAccessibleChildCount();
        for (sal_Int32 i = 0 ; i < nCount ; ++i)
        {
            Reference<css::accessibility::XAccessible> xChild = xContext->getAccessibleChild(i);
            if (xChild.is())
            {
                AccObject *pObj =  GetAccObjByXAcc(xChild.get());
                if (pObj)
                {
                    pObj->UpdateState();
                }
            }
        }
    }

    bool AccObjectWinManager::IsSpecialToolboItem(css::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(css::accessibility::XAccessible* pXAcc)
    {
        assert(pXAcc != nullptr);
        Reference<css::accessibility::XAccessibleContext> xContext(pXAcc->getAccessibleContext(),UNO_QUERY);
        if(xContext.is())
        {
            return xContext->getAccessibleRole();
        }
        return -1;
    }

    XAccessible* AccObjectWinManager::GetAccDocByHWND(HWND pWnd)
    {
        XHWNDToDocumentHash::iterator aIter;
        aIter = XHWNDDocList.find( pWnd );
        if ( aIter != XHWNDDocList.end() )
        {
            return aIter->second;
        }

        return nullptr;
    }

    XAccessible* AccObjectWinManager::GetAccDocByAccTopWin( XAccessible* pXAcc )
    {
        AccObject* pAccObj = GetAccObjByXAcc( pXAcc );
        HWND hWnd = pAccObj->GetParentHWND();
        return GetAccDocByHWND(hWnd);
    }

    bool AccObjectWinManager::IsTopWinAcc( css::accessibility::XAccessible* pXAcc )
    {
        bool bRet = false;
        AccObject* pAccObj = GetAccObjByXAcc( pXAcc );
        if ( pAccObj )
        {
            bRet = ( pAccObj->GetParentObj() == nullptr );
        }
        return bRet;
    }
    /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

↑ V522 There might be dereferencing of a potential null pointer 'pTemp'.

↑ V547 Expression 'selfAccObj' is always true.