    /* -*- 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 <AccessibleDocument.hxx>
    #include <AccessibleSpreadsheet.hxx>
    #include <tabvwsh.hxx>
    #include <AccessibilityHints.hxx>
    #include <document.hxx>
    #include <drwlayer.hxx>
    #include <shapeuno.hxx>
    #include <DrawModelBroadcaster.hxx>
    #include <drawview.hxx>
    #include <gridwin.hxx>
    #include <AccessibleEditObject.hxx>
    #include <userdat.hxx>
    #include <scresid.hxx>
    #include <strings.hrc>
    #include <strings.hxx>
    #include <table.hxx>
    #include <markdata.hxx>

    #include <com/sun/star/accessibility/AccessibleEventId.hpp>
    #include <com/sun/star/accessibility/AccessibleStateType.hpp>
    #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
    #include <com/sun/star/accessibility/AccessibleRole.hpp>
    #include <com/sun/star/view/XSelectionSupplier.hpp>
    #include <com/sun/star/drawing/ShapeCollection.hpp>
    #include <com/sun/star/drawing/XShape.hpp>
    #include <com/sun/star/drawing/XShapes.hpp>

    #include <unotools/accessiblestatesethelper.hxx>
    #include <tools/gen.hxx>
    #include <svx/svdpage.hxx>
    #include <svx/svdobj.hxx>
    #include <svx/ShapeTypeHandler.hxx>
    #include <svx/AccessibleShape.hxx>
    #include <svx/AccessibleShapeTreeInfo.hxx>
    #include <svx/AccessibleShapeInfo.hxx>
    #include <svx/IAccessibleParent.hxx>
    #include <comphelper/sequence.hxx>
    #include <sfx2/viewfrm.hxx>
    #include <sfx2/docfile.hxx>
    #include <svx/unoshape.hxx>
    #include <unotools/accessiblerelationsethelper.hxx>
    #include <toolkit/helper/convert.hxx>
    #include <vcl/svapp.hxx>

    #include <svx/AccessibleControlShape.hxx>
    #include <svx/SvxShapeTypes.hxx>
    #include <sfx2/objsh.hxx>
    #include <editeng/editview.hxx>
    #include <editeng/editeng.hxx>

    #include <list>
    #include <algorithm>

    #include <AccessibleCell.hxx>

    #include <svx/unoapi.hxx>
    #include <scmod.hxx>

    #ifdef indices
    #undef indices
    #endif

    #ifdef extents
    #undef extents
    #endif

    using namespace ::com::sun::star;
    using namespace ::com::sun::star::accessibility;
    using ::std::for_each;

        //=====  internal  ========================================================

    struct ScAccessibleShapeData
    {
        ScAccessibleShapeData() : pRelationCell(nullptr), bSelected(false), bSelectable(true) {}
        ~ScAccessibleShapeData();
        mutable rtl::Reference< ::accessibility::AccessibleShape > pAccShape;
        mutable ScAddress*          pRelationCell; // if it is NULL this shape is anchored on the table
        css::uno::Reference< css::drawing::XShape > xShape;
        mutable bool            bSelected;
        bool                    bSelectable;
    };

    ScAccessibleShapeData::~ScAccessibleShapeData()
    {
        if (pAccShape.is())
        {
            pAccShape->dispose();
        }
    }

    struct ScShapeDataLess
    {
        OUString msLayerId;
        OUString msZOrder;
        ScShapeDataLess()
            : msLayerId( "LayerID" ),
            msZOrder( "ZOrder" )
        {
        }
        static void ConvertLayerId(sal_Int16& rLayerID) // changes the number of the LayerId so it the accessibility order
        {
            // note: MSVC 2017 ICE's if this is written as "switch" so use "if"
            if (sal_uInt8(SC_LAYER_FRONT) == rLayerID)
            {
                rLayerID = 1;
            }
            else if (sal_uInt8(SC_LAYER_BACK) == rLayerID)
            {
                rLayerID = 0;
            }
            else if (sal_uInt8(SC_LAYER_INTERN) == rLayerID)
            {
                rLayerID = 2;
            }
            else if (sal_uInt8(SC_LAYER_CONTROLS) == rLayerID)
            {
                rLayerID = 3;
            }
        }
        bool LessThanSheet(const ScAccessibleShapeData* pData) const
        {
            bool bResult(false);
            uno::Reference< beans::XPropertySet> xProps(pData->xShape, uno::UNO_QUERY);
            if (xProps.is())
            {
                uno::Any aPropAny = xProps->getPropertyValue(msLayerId);
                sal_Int16 nLayerID = 0;
                if( aPropAny >>= nLayerID )
                {
                    if (SdrLayerID(nLayerID) == SC_LAYER_BACK)
                        bResult = true;
                }
            }
            return bResult;
        }
        bool operator()(const ScAccessibleShapeData* pData1, const ScAccessibleShapeData* pData2) const
        {
            bool bResult(false);
            if (pData1 && pData2)
            {
                uno::Reference< beans::XPropertySet> xProps1(pData1->xShape, uno::UNO_QUERY);
                uno::Reference< beans::XPropertySet> xProps2(pData2->xShape, uno::UNO_QUERY);
                if (xProps1.is() && xProps2.is())
                {
                    uno::Any aPropAny1 = xProps1->getPropertyValue(msLayerId);
                    uno::Any aPropAny2 = xProps2->getPropertyValue(msLayerId);
                    sal_Int16 nLayerID1(0);
                    sal_Int16 nLayerID2(0);
                    if( (aPropAny1 >>= nLayerID1) && (aPropAny2 >>= nLayerID2) )
                    {
                        if (nLayerID1 == nLayerID2)
                        {
                            uno::Any aAny1 = xProps1->getPropertyValue(msZOrder);
                            sal_Int32 nZOrder1 = 0;
                            uno::Any aAny2 = xProps2->getPropertyValue(msZOrder);
                            sal_Int32 nZOrder2 = 0;
                            if ( (aAny1 >>= nZOrder1) && (aAny2 >>= nZOrder2) )
                                bResult = (nZOrder1 < nZOrder2);
                        }
                        else
                        {
                            ConvertLayerId(nLayerID1);
                            ConvertLayerId(nLayerID2);
                            bResult = (nLayerID1 < nLayerID2);
                        }
                    }
                }
            }
            else if (pData1 && !pData2)
                bResult = LessThanSheet(pData1);
            else if (!pData1 && pData2)
                bResult = !LessThanSheet(pData2);
            else
                bResult = false;
            return bResult;
        }
    };

    struct DeselectShape
    {
        void operator() (const ScAccessibleShapeData* pAccShapeData) const
        {
            if (pAccShapeData)
            {
                pAccShapeData->bSelected = false;
                if (pAccShapeData->pAccShape.is())
                    pAccShapeData->pAccShape->ResetState(AccessibleStateType::SELECTED);
            }
        }
    };

    struct SelectShape
    {
        uno::Reference < drawing::XShapes > xShapes;
        explicit SelectShape(const uno::Reference<drawing::XShapes>& xTemp) : xShapes(xTemp) {}
        void operator() (const ScAccessibleShapeData* pAccShapeData) const
        {
            if (pAccShapeData && pAccShapeData->bSelectable)
            {
                pAccShapeData->bSelected = true;
                if (pAccShapeData->pAccShape.is())
                    pAccShapeData->pAccShape->SetState(AccessibleStateType::SELECTED);
                if (xShapes.is())
                    xShapes->add(pAccShapeData->xShape);
            }
        }
    };

    struct Destroy
    {
        void operator() (ScAccessibleShapeData* pData)
        {
            if (pData)
                DELETEZ(pData);
        }
    };

    class ScChildrenShapes : public SfxListener,
        public ::accessibility::IAccessibleParent
    {
    public:
        ScChildrenShapes(ScAccessibleDocument* pAccessibleDocument, ScTabViewShell* pViewShell, ScSplitPos eSplitPos);
        virtual ~ScChildrenShapes() override;

        ///=====  SfxListener  =====================================================

        virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;

        ///=====  IAccessibleParent  ===============================================

        virtual bool ReplaceChild (
            ::accessibility::AccessibleShape* pCurrentChild,
            const css::uno::Reference< css::drawing::XShape >& _rxShape,
            const long _nIndex,
            const ::accessibility::AccessibleShapeTreeInfo& _rShapeTreeInfo
        ) override;

        virtual ::accessibility::AccessibleControlShape* GetAccControlShapeFromModel
            (css::beans::XPropertySet* pSet) override;
        virtual css::uno::Reference< css::accessibility::XAccessible>
            GetAccessibleCaption (const css::uno::Reference<css::drawing::XShape>& xShape) override;
        ///=====  Internal  ========================================================
        void SetDrawBroadcaster();

        sal_Int32 GetCount() const;
        uno::Reference< XAccessible > Get(const ScAccessibleShapeData* pData) const;
        uno::Reference< XAccessible > Get(sal_Int32 nIndex) const;
        uno::Reference< XAccessible > GetAt(const awt::Point& rPoint) const;

        // gets the index of the shape starting on 0 (without the index of the table)
        // returns the selected shape
        bool IsSelected(sal_Int32 nIndex,
            css::uno::Reference<css::drawing::XShape>& rShape) const;

        bool SelectionChanged();

        void Select(sal_Int32 nIndex);
        void DeselectAll(); // deselect also the table
        void SelectAll();
        sal_Int32 GetSelectedCount() const;
        uno::Reference< XAccessible > GetSelected(sal_Int32 nSelectedChildIndex, bool bTabSelected) const;
        void Deselect(sal_Int32 nChildIndex);

        SdrPage* GetDrawPage() const;

        utl::AccessibleRelationSetHelper* GetRelationSet(const ScAddress* pAddress) const;

        void VisAreaChanged() const;
    private:
        typedef std::vector<ScAccessibleShapeData*> SortedShapes;

        mutable SortedShapes maZOrderedShapes; // a null pointer represents the sheet in the correct order

        mutable ::accessibility::AccessibleShapeTreeInfo maShapeTreeInfo;
        mutable css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier;
        mutable size_t mnSdrObjCount;
        mutable sal_uInt32 mnShapesSelected;
        ScTabViewShell* mpViewShell;
        ScAccessibleDocument* mpAccessibleDocument;
        ScSplitPos meSplitPos;

        void FillShapes(std::vector < uno::Reference < drawing::XShape > >& rShapes) const;
        bool FindSelectedShapesChanges(const css::uno::Reference<css::drawing::XShapes>& xShapes) const;

        ScAddress* GetAnchor(const uno::Reference<drawing::XShape>& xShape) const;
        uno::Reference<XAccessibleRelationSet> GetRelationSet(const ScAccessibleShapeData* pData) const;
        void CheckWhetherAnchorChanged(const uno::Reference<drawing::XShape>& xShape) const;
        void SetAnchor(const uno::Reference<drawing::XShape>& xShape, ScAccessibleShapeData* pData) const;
        void AddShape(const uno::Reference<drawing::XShape>& xShape, bool bCommitChange) const;
        void RemoveShape(const uno::Reference<drawing::XShape>& xShape) const;

        bool FindShape(const uno::Reference<drawing::XShape>& xShape, SortedShapes::iterator& rItr) const;

        static sal_Int8 Compare(const ScAccessibleShapeData* pData1,
            const ScAccessibleShapeData* pData2);
    };

    ScChildrenShapes::ScChildrenShapes(ScAccessibleDocument* pAccessibleDocument, ScTabViewShell* pViewShell, ScSplitPos eSplitPos)
        :
        mnShapesSelected(0),
        mpViewShell(pViewShell),
        mpAccessibleDocument(pAccessibleDocument),
        meSplitPos(eSplitPos)
    {
        if (mpViewShell)
        {
            SfxViewFrame* pViewFrame = mpViewShell->GetViewFrame();
            if (pViewFrame)
            {
                xSelectionSupplier = uno::Reference<view::XSelectionSupplier>(pViewFrame->GetFrame().GetController(), uno::UNO_QUERY);
                if (xSelectionSupplier.is())
                {
                    if (mpAccessibleDocument)
                        xSelectionSupplier->addSelectionChangeListener(mpAccessibleDocument);
                    uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
                    if (xShapes.is())
                        mnShapesSelected = xShapes->getCount();
                }
            }
        }

        maZOrderedShapes.push_back(nullptr); // add an element which represents the table

        GetCount(); // fill list with filtered shapes (no internal shapes)

        if (mnShapesSelected)
        {
            //set flag on every selected shape
            if (!xSelectionSupplier.is())
                throw uno::RuntimeException();

            uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
            if (xShapes.is())
                FindSelectedShapesChanges(xShapes);
        }
        if (pViewShell)
        {
            ScViewData& rViewData = pViewShell->GetViewData();
            SfxBroadcaster* pDrawBC = rViewData.GetDocument()->GetDrawBroadcaster();
            if (pDrawBC)
            {
                StartListening(*pDrawBC);

                maShapeTreeInfo.SetModelBroadcaster( new ScDrawModelBroadcaster(rViewData.GetDocument()->GetDrawLayer()) );
                maShapeTreeInfo.SetSdrView(rViewData.GetScDrawView());
                maShapeTreeInfo.SetController(nullptr);
                maShapeTreeInfo.SetWindow(pViewShell->GetWindowByPos(meSplitPos));
                maShapeTreeInfo.SetViewForwarder(mpAccessibleDocument);
            }
        }
    }

    ScChildrenShapes::~ScChildrenShapes()
    {
        std::for_each(maZOrderedShapes.begin(), maZOrderedShapes.end(), Destroy());
        if (mpViewShell)
        {
            SfxBroadcaster* pDrawBC = mpViewShell->GetViewData().GetDocument()->GetDrawBroadcaster();
            if (pDrawBC)
                EndListening(*pDrawBC);
        }
        if (mpAccessibleDocument && xSelectionSupplier.is())
            xSelectionSupplier->removeSelectionChangeListener(mpAccessibleDocument);
    }

    void ScChildrenShapes::SetDrawBroadcaster()
    {
        if (mpViewShell)
        {
            ScViewData& rViewData = mpViewShell->GetViewData();
            SfxBroadcaster* pDrawBC = rViewData.GetDocument()->GetDrawBroadcaster();
            if (pDrawBC)
            {
                StartListening(*pDrawBC, DuplicateHandling::Prevent);

                maShapeTreeInfo.SetModelBroadcaster( new ScDrawModelBroadcaster(rViewData.GetDocument()->GetDrawLayer()) );
                maShapeTreeInfo.SetSdrView(rViewData.GetScDrawView());
                maShapeTreeInfo.SetController(nullptr);
                maShapeTreeInfo.SetWindow(mpViewShell->GetWindowByPos(meSplitPos));
                maShapeTreeInfo.SetViewForwarder(mpAccessibleDocument);
            }
        }
    }

    void ScChildrenShapes::Notify(SfxBroadcaster&, const SfxHint& rHint)
    {
        const SdrHint* pSdrHint = dynamic_cast<const SdrHint*>(&rHint);
        if (pSdrHint)
        {
            SdrObject* pObj = const_cast<SdrObject*>(pSdrHint->GetObject());
            if (pObj && /*(pObj->GetLayer() != SC_LAYER_INTERN) && */(pObj->getSdrPageFromSdrObject() == GetDrawPage()) &&
                (pObj->getSdrPageFromSdrObject() == pObj->getParentSdrObjListFromSdrObject()) ) //only do something if the object lies direct on the page
            {
                switch (pSdrHint->GetKind())
                {
                    case SdrHintKind::ObjectChange :         // object changed
                    {
                        uno::Reference<drawing::XShape> xShape (pObj->getUnoShape(), uno::UNO_QUERY);
                        if (xShape.is())
                        {
                            ScShapeDataLess aLess;
                            std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), aLess); // sort, because the z index or layer could be changed
                            CheckWhetherAnchorChanged(xShape);
                        }
                    }
                    break;
                    case SdrHintKind::ObjectInserted :    // new drawing object inserted
                    {
                        uno::Reference<drawing::XShape> xShape (pObj->getUnoShape(), uno::UNO_QUERY);
                        if (xShape.is())
                            AddShape(xShape, true);
                    }
                    break;
                    case SdrHintKind::ObjectRemoved :     // Removed drawing object from list
                    {
                        uno::Reference<drawing::XShape> xShape (pObj->getUnoShape(), uno::UNO_QUERY);
                        if (xShape.is())
                            RemoveShape(xShape);
                    }
                    break;
                    default :
                    {
                        // other events are not interesting
                    }
                    break;
                }
            }
        }
    }

    bool ScChildrenShapes::ReplaceChild (::accessibility::AccessibleShape* pCurrentChild,
            const css::uno::Reference< css::drawing::XShape >& _rxShape,
            const long /*_nIndex*/, const ::accessibility::AccessibleShapeTreeInfo& _rShapeTreeInfo)
    {
        // create the new child
        rtl::Reference< ::accessibility::AccessibleShape > pReplacement(::accessibility::ShapeTypeHandler::Instance().CreateAccessibleObject (
            ::accessibility::AccessibleShapeInfo ( _rxShape, pCurrentChild->getAccessibleParent(), this ),
            _rShapeTreeInfo
        ));
        if ( pReplacement.is() )
            pReplacement->Init();

        bool bResult(false);
        if (pReplacement.is())
        {
            OSL_ENSURE(pCurrentChild->GetXShape().get() == pReplacement->GetXShape().get(), "XShape changes and should be inserted sorted");
            SortedShapes::iterator aItr;

            if (FindShape(pCurrentChild->GetXShape(), aItr) || (aItr != maZOrderedShapes.end() && (*aItr)))
            {
                if ((*aItr)->pAccShape.is())
                {
                    OSL_ENSURE((*aItr)->pAccShape == pCurrentChild, "wrong child found");
                    AccessibleEventObject aEvent;
                    aEvent.EventId = AccessibleEventId::CHILD;
                    aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument);
                    aEvent.OldValue <<= uno::Reference<XAccessible>(pCurrentChild);

                    mpAccessibleDocument->CommitChange(aEvent); // child is gone - event

                    pCurrentChild->dispose();
                }
                (*aItr)->pAccShape = pReplacement;
                AccessibleEventObject aEvent;
                aEvent.EventId = AccessibleEventId::CHILD;
                aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument);
                aEvent.NewValue <<= uno::Reference<XAccessible>(pReplacement.get());

                mpAccessibleDocument->CommitChange(aEvent); // child is new - event
                bResult = true;
            }
        }
        return bResult;
    }

    ::accessibility::AccessibleControlShape * ScChildrenShapes::GetAccControlShapeFromModel(css::beans::XPropertySet* pSet)
    {
        sal_Int32 count = GetCount();
        for (sal_Int32 index=0;index<count;index++)
        {
            ScAccessibleShapeData* pShape = maZOrderedShapes[index];
                    if (pShape)
                {
                    rtl::Reference< ::accessibility::AccessibleShape > pAccShape(pShape->pAccShape);
                    if (pAccShape.is() && ::accessibility::ShapeTypeHandler::Instance().GetTypeId (pAccShape->GetXShape()) == ::accessibility::DRAWING_CONTROL)
                    {
                    ::accessibility::AccessibleControlShape *pCtlAccShape = static_cast < ::accessibility::AccessibleControlShape* >(pAccShape.get());
                    if (pCtlAccShape && pCtlAccShape->GetControlModel() == pSet)
                        return pCtlAccShape;
                  }
                    }
        }
        return nullptr;
    }

    css::uno::Reference < css::accessibility::XAccessible >
    ScChildrenShapes::GetAccessibleCaption (const css::uno::Reference < css::drawing::XShape>& xShape)
    {
        sal_Int32 count = GetCount();
        for (sal_Int32 index=0;index<count;index++)
        {
            ScAccessibleShapeData* pShape = maZOrderedShapes[index];
                if (pShape && pShape->xShape == xShape )
                {
                    css::uno::Reference< css::accessibility::XAccessible > xNewChild(  pShape->pAccShape.get() );
                    if(xNewChild.get())
                    return xNewChild;
                }
        }
        return nullptr;
    }

    sal_Int32 ScChildrenShapes::GetCount() const
    {
        SdrPage* pDrawPage = GetDrawPage();
        if (pDrawPage && (maZOrderedShapes.size() == 1)) // the table is always in
        {
            mnSdrObjCount = pDrawPage->GetObjCount();
            maZOrderedShapes.reserve(mnSdrObjCount + 1); // the table is always in
            for (size_t i = 0; i < mnSdrObjCount; ++i)
            {
                SdrObject* pObj = pDrawPage->GetObj(i);
                if (pObj/* && (pObj->GetLayer() != SC_LAYER_INTERN)*/)
                {
                    uno::Reference< drawing::XShape > xShape (pObj->getUnoShape(), uno::UNO_QUERY);
                    AddShape(xShape, false); //inserts in the correct order
                }
            }
        }
        return maZOrderedShapes.size();
    }

    uno::Reference< XAccessible > ScChildrenShapes::Get(const ScAccessibleShapeData* pData) const
    {
        if (!pData)
            return nullptr;

        if (!pData->pAccShape.is())
        {
            ::accessibility::ShapeTypeHandler& rShapeHandler = ::accessibility::ShapeTypeHandler::Instance();
            ::accessibility::AccessibleShapeInfo aShapeInfo(pData->xShape, mpAccessibleDocument, const_cast<ScChildrenShapes*>(this));
            pData->pAccShape = rShapeHandler.CreateAccessibleObject(
                aShapeInfo, maShapeTreeInfo);
            if (pData->pAccShape.is())
            {
                pData->pAccShape->Init();
                if (pData->bSelected)
                    pData->pAccShape->SetState(AccessibleStateType::SELECTED);
                if (!pData->bSelectable)
                    pData->pAccShape->ResetState(AccessibleStateType::SELECTABLE);
                pData->pAccShape->SetRelationSet(GetRelationSet(pData));
            }
        }
        return pData->pAccShape.get();
     }

    uno::Reference< XAccessible > ScChildrenShapes::Get(sal_Int32 nIndex) const
    {
        if (maZOrderedShapes.size() <= 1)
            GetCount(); // fill list with filtered shapes (no internal shapes)

        if (static_cast<sal_uInt32>(nIndex) >= maZOrderedShapes.size())
            return nullptr;

        return Get(maZOrderedShapes[nIndex]);
    }

    uno::Reference< XAccessible > ScChildrenShapes::GetAt(const awt::Point& rPoint) const
    {
        uno::Reference<XAccessible> xAccessible;
        if(mpViewShell)
        {
            sal_Int32 i(maZOrderedShapes.size() - 1);
            bool bFound(false);
            while (!bFound && i >= 0)
            {
                ScAccessibleShapeData* pShape = maZOrderedShapes[i];
                if (pShape)
                {
                    if (!pShape->pAccShape.is())
                        Get(pShape);

                    if (pShape->pAccShape.is())
                    {
                        Point aPoint(VCLPoint(rPoint));
                        aPoint -= VCLRectangle(pShape->pAccShape->getBounds()).TopLeft();
                        if (pShape->pAccShape->containsPoint(AWTPoint(aPoint)))
                        {
                            xAccessible = pShape->pAccShape.get();
                            bFound = true;
                        }
                    }
                    else
                    {
                        OSL_FAIL("I should have an accessible shape now!");
                    }
                }
                else
                    bFound = true; // this is the sheet and it lies before the rest of the shapes which are background shapes

                --i;
            }
        }
        return xAccessible;
    }

    bool ScChildrenShapes::IsSelected(sal_Int32 nIndex,
                            uno::Reference<drawing::XShape>& rShape) const
    {
        bool bResult (false);
        if (maZOrderedShapes.size() <= 1)
            GetCount(); // fill list with filtered shapes (no internal shapes)

        if (!xSelectionSupplier.is())
            throw uno::RuntimeException();

        if (!maZOrderedShapes[nIndex])
            return false;

        bResult = maZOrderedShapes[nIndex]->bSelected;
        rShape = maZOrderedShapes[nIndex]->xShape;

    #if OSL_DEBUG_LEVEL > 0 // test whether it is truly selected by a slower method
        uno::Reference< drawing::XShape > xReturnShape;
        bool bDebugResult(false);
        uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
        uno::Reference<container::XIndexAccess> xIndexAccess(xShapes, uno::UNO_QUERY);

        if (xIndexAccess.is())
        {
            sal_Int32 nCount(xIndexAccess->getCount());
            if (nCount)
            {
                uno::Reference< drawing::XShape > xShape;
                uno::Reference< drawing::XShape > xIndexShape = maZOrderedShapes[nIndex]->xShape;
                sal_Int32 i(0);
                while (!bDebugResult && (i < nCount))
                {
                    xIndexAccess->getByIndex(i) >>= xShape;
                    if (xShape.is() && (xIndexShape.get() == xShape.get()))
                    {
                        bDebugResult = true;
                        xReturnShape = xShape;
                    }
                    else
                        ++i;
                }
            }
        }
        OSL_ENSURE((bResult == bDebugResult) && ((bResult && (rShape.get() == xReturnShape.get())) || !bResult), "found the wrong shape or result");
    #endif

        return bResult;
    }

    bool ScChildrenShapes::SelectionChanged()
    {
        bool bResult(false);
        if (!xSelectionSupplier.is())
            throw uno::RuntimeException();

        uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());

        bResult = FindSelectedShapesChanges(xShapes);

        return bResult;
    }

    void ScChildrenShapes::Select(sal_Int32 nIndex)
    {
        if (maZOrderedShapes.size() <= 1)
            GetCount(); // fill list with filtered shapes (no internal shapes)

        if (!xSelectionSupplier.is())
            throw uno::RuntimeException();

        if (!maZOrderedShapes[nIndex])
            return;

        uno::Reference<drawing::XShape> xShape;
        if (!IsSelected(nIndex, xShape) && maZOrderedShapes[nIndex]->bSelectable)
        {
            uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());

            if (!xShapes.is())
                xShapes = drawing::ShapeCollection::create(
                        comphelper::getProcessComponentContext());

            xShapes->add(maZOrderedShapes[nIndex]->xShape);

            try
            {
                xSelectionSupplier->select(uno::makeAny(xShapes));
                maZOrderedShapes[nIndex]->bSelected = true;
                if (maZOrderedShapes[nIndex]->pAccShape.is())
                    maZOrderedShapes[nIndex]->pAccShape->SetState(AccessibleStateType::SELECTED);
            }
            catch (lang::IllegalArgumentException&)
            {
            }
        }
    }

    void ScChildrenShapes::DeselectAll()
    {
        if (!xSelectionSupplier.is())
            throw uno::RuntimeException();

        bool bSomethingSelected(true);
        try
        {
            xSelectionSupplier->select(uno::Any()); //deselects all
        }
        catch (lang::IllegalArgumentException&)
        {
            OSL_FAIL("nothing selected before");
            bSomethingSelected = false;
        }

        if (bSomethingSelected)
            std::for_each(maZOrderedShapes.begin(), maZOrderedShapes.end(), DeselectShape());
    }

    void ScChildrenShapes::SelectAll()
    {
        if (!xSelectionSupplier.is())
            throw uno::RuntimeException();

        if (maZOrderedShapes.size() <= 1)
            GetCount(); // fill list with filtered shapes (no internal shapes)

        if (maZOrderedShapes.size() > 1)
        {
            uno::Reference<drawing::XShapes> xShapes = drawing::ShapeCollection::create(
                    comphelper::getProcessComponentContext());

            try
            {
                std::for_each(maZOrderedShapes.begin(), maZOrderedShapes.end(), SelectShape(xShapes));
                xSelectionSupplier->select(uno::makeAny(xShapes));
            }
            catch (lang::IllegalArgumentException&)
            {
                SelectionChanged(); // find all selected shapes and set the flags
            }
        }
    }

    void ScChildrenShapes::FillShapes(std::vector < uno::Reference < drawing::XShape > >& rShapes) const
    {
        uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
        uno::Reference<container::XIndexAccess> xIndexAccess(xShapes, uno::UNO_QUERY);
        if (xIndexAccess.is())
        {
            sal_uInt32 nCount(xIndexAccess->getCount());
            for (sal_uInt32 i = 0; i < nCount; ++i)
            {
                uno::Reference<drawing::XShape> xShape;
                xIndexAccess->getByIndex(i) >>= xShape;
                if (xShape.is())
                    rShapes.push_back(xShape);
            }
        }
    }

    sal_Int32 ScChildrenShapes::GetSelectedCount() const
    {
        if (!xSelectionSupplier.is())
            throw uno::RuntimeException();

        std::vector < uno::Reference < drawing::XShape > > aShapes;
        FillShapes(aShapes);

        return aShapes.size();
    }

    uno::Reference< XAccessible > ScChildrenShapes::GetSelected(sal_Int32 nSelectedChildIndex, bool bTabSelected) const
    {
        uno::Reference< XAccessible > xAccessible;

        if (maZOrderedShapes.size() <= 1)
            GetCount(); // fill list with shapes

        if (!bTabSelected)
        {
            std::vector < uno::Reference < drawing::XShape > > aShapes;
            FillShapes(aShapes);

            if (nSelectedChildIndex < 0 || static_cast<size_t>(nSelectedChildIndex) >= aShapes.size())
                return xAccessible;

            SortedShapes::iterator aItr;
            if (FindShape(aShapes[nSelectedChildIndex], aItr))
                xAccessible = Get(aItr - maZOrderedShapes.begin());
        }
        else
        {
            SortedShapes::iterator aItr = maZOrderedShapes.begin();
            SortedShapes::iterator aEndItr = maZOrderedShapes.end();
            bool bFound(false);
            while(!bFound && aItr != aEndItr)
            {
                if (*aItr)
                {
                    if ((*aItr)->bSelected)
                    {
                        if (nSelectedChildIndex == 0)
                            bFound = true;
                        else
                            --nSelectedChildIndex;
                    }
                }
                else
                {
                    if (nSelectedChildIndex == 0)
                        bFound = true;
                    else
                        --nSelectedChildIndex;
                }
                if (!bFound)
                    ++aItr;
            }
            if (bFound && *aItr)
                xAccessible = (*aItr)->pAccShape.get();
        }

        return xAccessible;
    }

    void ScChildrenShapes::Deselect(sal_Int32 nChildIndex)
    {
        uno::Reference<drawing::XShape> xShape;
        if (IsSelected(nChildIndex, xShape)) // returns false if it is the sheet
        {
            if (xShape.is())
            {
                uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
                if (xShapes.is())
                    xShapes->remove(xShape);

                try
                {
                    xSelectionSupplier->select(uno::makeAny(xShapes));
                }
                catch (lang::IllegalArgumentException&)
                {
                    OSL_FAIL("something not selectable");
                }

                maZOrderedShapes[nChildIndex]->bSelected = false;
                if (maZOrderedShapes[nChildIndex]->pAccShape.is())
                    maZOrderedShapes[nChildIndex]->pAccShape->ResetState(AccessibleStateType::SELECTED);
            }
        }
    }

    SdrPage* ScChildrenShapes::GetDrawPage() const
    {
        SCTAB nTab(mpAccessibleDocument->getVisibleTable());
        SdrPage* pDrawPage = nullptr;
        if (mpViewShell)
        {
            ScViewData& rViewData = mpViewShell->GetViewData();
            ScDocument* pDoc = rViewData.GetDocument();
            if (pDoc && pDoc->GetDrawLayer())
            {
                ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
                if (pDrawLayer->HasObjects() && (pDrawLayer->GetPageCount() > nTab))
                    pDrawPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(static_cast<sal_Int16>(nTab)));
            }
        }
        return pDrawPage;
    }

    struct SetRelation
    {
        const ScChildrenShapes* mpChildrenShapes;
        mutable utl::AccessibleRelationSetHelper* mpRelationSet;
        const ScAddress* mpAddress;
        SetRelation(const ScChildrenShapes* pChildrenShapes, const ScAddress* pAddress)
            :
            mpChildrenShapes(pChildrenShapes),
            mpRelationSet(nullptr),
            mpAddress(pAddress)
        {
        }
        void operator() (const ScAccessibleShapeData* pAccShapeData) const
        {
            if (pAccShapeData &&
                ((!pAccShapeData->pRelationCell && !mpAddress) ||
                (pAccShapeData->pRelationCell && mpAddress && (*(pAccShapeData->pRelationCell) == *mpAddress))))
            {
                if (!mpRelationSet)
                    mpRelationSet = new utl::AccessibleRelationSetHelper();

                AccessibleRelation aRelation;
                aRelation.TargetSet.realloc(1);
                aRelation.TargetSet[0] = mpChildrenShapes->Get(pAccShapeData);
                aRelation.RelationType = AccessibleRelationType::CONTROLLER_FOR;

                mpRelationSet->AddRelation(aRelation);
            }
        }
    };

    utl::AccessibleRelationSetHelper* ScChildrenShapes::GetRelationSet(const ScAddress* pAddress) const
    {
        SetRelation aSetRelation(this, pAddress);
        ::std::for_each(maZOrderedShapes.begin(), maZOrderedShapes.end(), aSetRelation);
        return aSetRelation.mpRelationSet;
    }

    bool ScChildrenShapes::FindSelectedShapesChanges(const uno::Reference<drawing::XShapes>& xShapes) const
    {
        bool bResult(false);
        SortedShapes aShapesList;
        uno::Reference<container::XIndexAccess> xIndexAcc(xShapes, uno::UNO_QUERY);
        if (xIndexAcc.is())
        {
            mnShapesSelected = xIndexAcc->getCount();
            for (sal_uInt32 i = 0; i < mnShapesSelected; ++i)
            {
                uno::Reference< drawing::XShape > xShape;
                xIndexAcc->getByIndex(i) >>= xShape;
                if (xShape.is())
                {
                    ScAccessibleShapeData* pShapeData = new ScAccessibleShapeData();
                    pShapeData->xShape = xShape;
                    aShapesList.push_back(pShapeData);
                }
            }
        }
        else
            mnShapesSelected = 0;
        SdrObject *pFocusedObj = nullptr;
        if( mnShapesSelected == 1 && aShapesList.size() == 1)
        {
            pFocusedObj = GetSdrObjectFromXShape(aShapesList[0]->xShape);
        }
        ScShapeDataLess aLess;
        std::sort(aShapesList.begin(), aShapesList.end(), aLess);
        SortedShapes vecSelectedShapeAdd;
        SortedShapes vecSelectedShapeRemove;
        bool bHasSelect=false;
        SortedShapes::iterator aXShapesItr(aShapesList.begin());
        SortedShapes::const_iterator aXShapesEndItr(aShapesList.end());
        SortedShapes::iterator aDataItr(maZOrderedShapes.begin());
        SortedShapes::const_iterator aDataEndItr(maZOrderedShapes.end());
        SortedShapes::const_iterator aFocusedItr = aDataEndItr;
        while(aDataItr != aDataEndItr)
        {
            if (*aDataItr) // is it really a shape or only the sheet
            {
                sal_Int8 nComp(0);
                if (aXShapesItr == aXShapesEndItr)
                    nComp = -1; // simulate that the Shape is lower, so the selection state will be removed
                else
                    nComp = Compare(*aDataItr, *aXShapesItr);
                if (nComp == 0)
                {
                    if (!(*aDataItr)->bSelected)
                    {
                        (*aDataItr)->bSelected = true;
                        if ((*aDataItr)->pAccShape.is())
                        {
                            (*aDataItr)->pAccShape->SetState(AccessibleStateType::SELECTED);
                            (*aDataItr)->pAccShape->SetState(AccessibleStateType::FOCUSED);
                            bResult = true;
                            vecSelectedShapeAdd.push_back(*aDataItr);
                        }
                        aFocusedItr = aDataItr;
                    }
                    else
                    {
                         bHasSelect = true;
                    }
                    ++aDataItr;
                    ++aXShapesItr;
                }
                else if (nComp < 0)
                {
                    if ((*aDataItr)->bSelected)
                    {
                        (*aDataItr)->bSelected = false;
                        if ((*aDataItr)->pAccShape.is())
                        {
                            (*aDataItr)->pAccShape->ResetState(AccessibleStateType::SELECTED);
                            (*aDataItr)->pAccShape->ResetState(AccessibleStateType::FOCUSED);
                            bResult = true;
                            vecSelectedShapeRemove.push_back(*aDataItr);
                        }
                    }
                    ++aDataItr;
                }
                else
                {
                    OSL_FAIL("here is a selected shape which is not in the childlist");
                    ++aXShapesItr;
                    --mnShapesSelected;
                }
            }
            else
                ++aDataItr;
        }
        bool bWinFocus=false;
        if (mpViewShell)
        {
            ScGridWindow* pWin = static_cast<ScGridWindow*>(mpViewShell->GetWindowByPos(meSplitPos));
            if (pWin)
            {
                bWinFocus = pWin->HasFocus();
            }
        }
        const SdrMarkList* pMarkList = nullptr;
        SdrObject* pMarkedObj = nullptr;
        SdrObject* pUpObj = nullptr;
        bool bIsFocuseMarked = true;
        if( mpViewShell && mnShapesSelected == 1 && bWinFocus)
        {
            ScDrawView* pScDrawView = mpViewShell->GetViewData().GetScDrawView();
            if( pScDrawView )
            {
                if( pScDrawView->GetMarkedObjectList().GetMarkCount() == 1 )
                {
                    pMarkList = &(pScDrawView->GetMarkedObjectList());
                    pMarkedObj = pMarkList->GetMark(0)->GetMarkedSdrObj();
                    uno::Reference< drawing::XShape > xMarkedXShape (pMarkedObj->getUnoShape(), uno::UNO_QUERY);
                    if( aFocusedItr != aDataEndItr &&
                        (*aFocusedItr)->xShape.is() &&
                        xMarkedXShape.is() &&
                        (*aFocusedItr)->xShape != xMarkedXShape )
                        bIsFocuseMarked = false;
                }
            }
        }
        //if ((aFocusedItr != aDataEndItr) && (*aFocusedItr)->pAccShape.is() && (mnShapesSelected == 1))
        if ( bIsFocuseMarked && (aFocusedItr != aDataEndItr) && (*aFocusedItr)->pAccShape.is() && (mnShapesSelected == 1) && bWinFocus)
        {
            (*aFocusedItr)->pAccShape->SetState(AccessibleStateType::FOCUSED);
        }
        else if( pFocusedObj && bWinFocus && pMarkList && pMarkList->GetMarkCount() == 1 && mnShapesSelected == 1 )
        {
            if( pMarkedObj )
            {
                uno::Reference< drawing::XShape > xMarkedXShape (pMarkedObj->getUnoShape(), uno::UNO_QUERY);
                pUpObj = pMarkedObj->getParentSdrObjectFromSdrObject();

                if( pMarkedObj == pFocusedObj )
                {
                    if( pUpObj )
                    {
                        uno::Reference< drawing::XShape > xUpGroupXShape (pUpObj->getUnoShape(), uno::UNO_QUERY);
                        uno::Reference < XAccessible > xAccGroupShape =
                            const_cast<ScChildrenShapes*>(this)->GetAccessibleCaption( xUpGroupXShape );
                        if( xAccGroupShape.is() )
                        {
                            ::accessibility::AccessibleShape* pAccGroupShape =
                                static_cast< ::accessibility::AccessibleShape* >(xAccGroupShape.get());
                            if( pAccGroupShape )
                            {
                                sal_Int32 nCount =  pAccGroupShape->getAccessibleChildCount();
                                for( sal_Int32 i = 0; i < nCount; i++ )
                                {
                                    uno::Reference<XAccessible> xAccShape = pAccGroupShape->getAccessibleChild(i);
                                    if (xAccShape.is())
                                    {
                                        ::accessibility::AccessibleShape* pChildAccShape =  static_cast< ::accessibility::AccessibleShape* >(xAccShape.get());
                                        uno::Reference< drawing::XShape > xChildShape = pChildAccShape->GetXShape();
                                        if (xChildShape == xMarkedXShape)
                                        {
                                            pChildAccShape->SetState(AccessibleStateType::FOCUSED);
                                        }
                                        else
                                        {
                                            pChildAccShape->ResetState(AccessibleStateType::FOCUSED);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        if (vecSelectedShapeAdd.size() >= 10 )
        {
            AccessibleEventObject aEvent;
            aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_WITHIN;
            aEvent.Source = uno::Reference< XAccessible >(mpAccessibleDocument);
            mpAccessibleDocument->CommitChange(aEvent);
        }
        else
        {
            SortedShapes::iterator vi = vecSelectedShapeAdd.begin();
            for (; vi != vecSelectedShapeAdd.end() ; ++vi )
            {
                AccessibleEventObject aEvent;
                if (bHasSelect)
                {
                    aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_ADD;
                }
                else
                {
                    aEvent.EventId = AccessibleEventId::SELECTION_CHANGED;
                }
                aEvent.Source = uno::Reference< XAccessible >(mpAccessibleDocument);
                uno::Reference< XAccessible > xChild( (*vi)->pAccShape.get());
                aEvent.NewValue <<= xChild;
                mpAccessibleDocument->CommitChange(aEvent);
            }
        }
        SortedShapes::iterator vi = vecSelectedShapeRemove.begin();
        for (; vi != vecSelectedShapeRemove.end() ; ++vi )
        {
            AccessibleEventObject aEvent;
            aEvent.EventId =  AccessibleEventId::SELECTION_CHANGED_REMOVE;
            aEvent.Source = uno::Reference< XAccessible >(mpAccessibleDocument);
            uno::Reference< XAccessible > xChild( (*vi)->pAccShape.get());
            aEvent.NewValue <<= xChild;
            mpAccessibleDocument->CommitChange(aEvent);
        }
        std::for_each(aShapesList.begin(), aShapesList.end(), Destroy());

        return bResult;
    }

    ScAddress* ScChildrenShapes::GetAnchor(const uno::Reference<drawing::XShape>& xShape) const
    {
        ScAddress* pAddress = nullptr;
        if (mpViewShell)
        {
            SvxShape* pShapeImp = SvxShape::getImplementation(xShape);
            uno::Reference<beans::XPropertySet> xShapeProp(xShape, uno::UNO_QUERY);
            if (pShapeImp && xShapeProp.is())
            {
                if (SdrObject *pSdrObj = pShapeImp->GetSdrObject())
                {
                    if (ScDrawObjData *pAnchor = ScDrawLayer::GetObjData(pSdrObj))
                        return new ScAddress(pAnchor->maStart);
                }
            }
        }

        return pAddress;
    }

    uno::Reference<XAccessibleRelationSet> ScChildrenShapes::GetRelationSet(const ScAccessibleShapeData* pData) const
    {
        utl::AccessibleRelationSetHelper* pRelationSet = new utl::AccessibleRelationSetHelper();

        if (pData && mpAccessibleDocument)
        {
            uno::Reference<XAccessible> xAccessible = mpAccessibleDocument->GetAccessibleSpreadsheet(); // should be the current table
            if (pData->pRelationCell && xAccessible.is())
            {
                uno::Reference<XAccessibleTable> xAccTable (xAccessible->getAccessibleContext(), uno::UNO_QUERY);
                if (xAccTable.is())
                    xAccessible = xAccTable->getAccessibleCellAt(pData->pRelationCell->Row(), pData->pRelationCell->Col());
            }
            AccessibleRelation aRelation;
            aRelation.TargetSet.realloc(1);
            aRelation.TargetSet[0] = xAccessible;
            aRelation.RelationType = AccessibleRelationType::CONTROLLED_BY;
            pRelationSet->AddRelation(aRelation);
        }

        return pRelationSet;
    }

    void ScChildrenShapes::CheckWhetherAnchorChanged(const uno::Reference<drawing::XShape>& xShape) const
    {
        SortedShapes::iterator aItr;
        if (FindShape(xShape, aItr))
            SetAnchor(xShape, *aItr);
    }

    void ScChildrenShapes::SetAnchor(const uno::Reference<drawing::XShape>& xShape, ScAccessibleShapeData* pData) const
    {
        if (pData)
        {
            ScAddress* pAddress = GetAnchor(xShape);
            if ((pAddress && pData->pRelationCell && (*pAddress != *(pData->pRelationCell))) ||
                (!pAddress && pData->pRelationCell) || (pAddress && !pData->pRelationCell))
            {
                delete pData->pRelationCell;
                pData->pRelationCell = pAddress;
                if (pData->pAccShape.is())
                    pData->pAccShape->SetRelationSet(GetRelationSet(pData));
            }
            else
                delete pAddress;
        }
    }

    void ScChildrenShapes::AddShape(const uno::Reference<drawing::XShape>& xShape, bool bCommitChange) const
    {
        SortedShapes::iterator aFindItr;
        if (!FindShape(xShape, aFindItr))
        {
            ScAccessibleShapeData* pShape = new ScAccessibleShapeData();
            pShape->xShape = xShape;
            SortedShapes::iterator aNewItr = maZOrderedShapes.insert(aFindItr, pShape);
            SetAnchor(xShape, pShape);

            uno::Reference< beans::XPropertySet > xShapeProp(xShape, uno::UNO_QUERY);
            if (xShapeProp.is())
            {
                uno::Any aPropAny = xShapeProp->getPropertyValue("LayerID");
                sal_Int16 nLayerID = 0;
                if( aPropAny >>= nLayerID )
                {
                    if( (SdrLayerID(nLayerID) == SC_LAYER_INTERN) || (SdrLayerID(nLayerID) == SC_LAYER_HIDDEN) )
                        pShape->bSelectable = false;
                    else
                        pShape->bSelectable = true;
                }
            }

            if (!xSelectionSupplier.is())
                throw uno::RuntimeException();

            uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
            uno::Reference<container::XEnumerationAccess> xEnumAcc(xShapes, uno::UNO_QUERY);
            if (xEnumAcc.is())
            {
                uno::Reference<container::XEnumeration> xEnum = xEnumAcc->createEnumeration();
                if (xEnum.is())
                {
                    uno::Reference<drawing::XShape> xSelectedShape;
                    bool bFound(false);
                    while (!bFound && xEnum->hasMoreElements())
                    {
                        xEnum->nextElement() >>= xSelectedShape;
                        if (xShape.is() && (xShape.get() == xSelectedShape.get()))
                        {
                            pShape->bSelected = true;
                            bFound = true;
                        }
                    }
                }
            }
            if (mpAccessibleDocument && bCommitChange)
            {
                AccessibleEventObject aEvent;
                aEvent.EventId = AccessibleEventId::CHILD;
                aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument);
                aEvent.NewValue <<= Get(aNewItr - maZOrderedShapes.begin());

                mpAccessibleDocument->CommitChange(aEvent); // new child - event
            }
        }
        else
        {
            OSL_FAIL("shape is always in the list");
        }
    }

    void ScChildrenShapes::RemoveShape(const uno::Reference<drawing::XShape>& xShape) const
    {
        SortedShapes::iterator aItr;
        if (FindShape(xShape, aItr))
        {
            if (mpAccessibleDocument)
            {
                uno::Reference<XAccessible> xOldAccessible (Get(aItr - maZOrderedShapes.begin()));

                delete *aItr;
                maZOrderedShapes.erase(aItr);

                AccessibleEventObject aEvent;
                aEvent.EventId = AccessibleEventId::CHILD;
                aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument);
                aEvent.OldValue <<= xOldAccessible;

                mpAccessibleDocument->CommitChange(aEvent); // child is gone - event
            }
            else
            {
                delete *aItr;
                maZOrderedShapes.erase(aItr);
            }
        }
        else
        {
            OSL_FAIL("shape was not in internal list");
        }
    }

    bool ScChildrenShapes::FindShape(const uno::Reference<drawing::XShape>& xShape, ScChildrenShapes::SortedShapes::iterator& rItr) const
    {
        bool bResult(false);
        ScAccessibleShapeData aShape;
        aShape.xShape = xShape;
        ScShapeDataLess aLess;
        rItr = std::lower_bound(maZOrderedShapes.begin(), maZOrderedShapes.end(), &aShape, aLess);
        if ((rItr != maZOrderedShapes.end()) && (*rItr != nullptr) && ((*rItr)->xShape.get() == xShape.get()))
            bResult = true; // if the shape is found

    #if OSL_DEBUG_LEVEL > 0 // test whether it finds truly the correct shape (perhaps it is not really sorted)
        SortedShapes::iterator aDebugItr = maZOrderedShapes.begin();
        SortedShapes::iterator aEndItr = maZOrderedShapes.end();
        bool bFound(false);
        while (!bFound && aDebugItr != aEndItr)
        {
            if (*aDebugItr && ((*aDebugItr)->xShape.get() == xShape.get()))
                bFound = true;
            else
                ++aDebugItr;
        }
        bool bResult2 = (aDebugItr != maZOrderedShapes.end());
        OSL_ENSURE((bResult == bResult2) && ((bResult && (rItr == aDebugItr)) || !bResult), "wrong Shape found");
    #endif
        return bResult;
    }

    sal_Int8 ScChildrenShapes::Compare(const ScAccessibleShapeData* pData1,
            const ScAccessibleShapeData* pData2)
    {
        ScShapeDataLess aLess;

        bool bResult1(aLess(pData1, pData2));
        bool bResult2(aLess(pData2, pData1));

        sal_Int8 nResult(0);
        if (!bResult1 && bResult2)
            nResult = 1;
        else if (bResult1 && !bResult2)
            nResult = -1;

        return nResult;
    }

    namespace
    {
        struct ScVisAreaChanged
        {
            explicit ScVisAreaChanged() {}
            void operator() (const ScAccessibleShapeData* pAccShapeData) const
            {
                if (pAccShapeData && pAccShapeData->pAccShape.is())
                {
                    pAccShapeData->pAccShape->ViewForwarderChanged();
                }
            }
        };
    }

    void ScChildrenShapes::VisAreaChanged() const
    {
        ScVisAreaChanged aVisAreaChanged;
        std::for_each(maZOrderedShapes.begin(), maZOrderedShapes.end(), aVisAreaChanged);
    }

    ScAccessibleDocument::ScAccessibleDocument(
            const uno::Reference<XAccessible>& rxParent,
            ScTabViewShell* pViewShell,
            ScSplitPos eSplitPos)
        : ScAccessibleDocumentBase(rxParent),
        mpViewShell(pViewShell),
        meSplitPos(eSplitPos),
        mpTempAccEdit(nullptr),
        mbCompleteSheetSelected(false)
    {
        maVisArea = GetVisibleArea_Impl();
    }

    void ScAccessibleDocument::PreInit()
    {
        if (mpViewShell)
        {
            mpViewShell->AddAccessibilityObject(*this);
            vcl::Window *pWin = mpViewShell->GetWindowByPos(meSplitPos);
            if( pWin )
            {
                pWin->AddChildEventListener( LINK( this, ScAccessibleDocument, WindowChildEventListener ));
                sal_uInt16 nCount =   pWin->GetChildCount();
                for( sal_uInt16 i=0; i < nCount; ++i )
                {
                    vcl::Window *pChildWin = pWin->GetChild( i );
                    if( pChildWin &&
                        AccessibleRole::EMBEDDED_OBJECT == pChildWin->GetAccessibleRole() )
                        AddChild( pChildWin->GetAccessible(), false );
                }
            }
            ScViewData& rViewData = mpViewShell->GetViewData();
            if (rViewData.HasEditView(meSplitPos))
            {
                uno::Reference<XAccessible> xAcc = new ScAccessibleEditObject(this, rViewData.GetEditView(meSplitPos),
                    mpViewShell->GetWindowByPos(meSplitPos), GetCurrentCellName(), GetCurrentCellDescription(),
                    ScAccessibleEditObject::CellInEditMode);
                AddChild(xAcc, false);
            }
        }
    }

    void ScAccessibleDocument::Init()
    {
        if(!mpChildrenShapes)
            mpChildrenShapes.reset( new ScChildrenShapes(this, mpViewShell, meSplitPos) );
    }

    ScAccessibleDocument::~ScAccessibleDocument()
    {
        if (!ScAccessibleContextBase::IsDefunc() && !rBHelper.bInDispose)
        {
            // increment refcount to prevent double call off dtor
            osl_atomic_increment( &m_refCount );
            dispose();
        }
    }

    void SAL_CALL ScAccessibleDocument::disposing()
    {
        SolarMutexGuard aGuard;
        FreeAccessibleSpreadsheet();
        if (mpViewShell)
        {
            vcl::Window *pWin = mpViewShell->GetWindowByPos(meSplitPos);
            if( pWin )
                pWin->RemoveChildEventListener( LINK( this, ScAccessibleDocument, WindowChildEventListener ));

            mpViewShell->RemoveAccessibilityObject(*this);
            mpViewShell = nullptr;
        }
        mpChildrenShapes.reset();

        ScAccessibleDocumentBase::disposing();
    }

    void SAL_CALL ScAccessibleDocument::disposing( const lang::EventObject& /* Source */ )
    {
        disposing();
    }

        //=====  SfxListener  =====================================================

    IMPL_LINK( ScAccessibleDocument, WindowChildEventListener, VclWindowEvent&, rEvent, void )
    {
        OSL_ENSURE( rEvent.GetWindow(), "Window???" );
        switch ( rEvent.GetId() )
        {
        case VclEventId::WindowShow:  // send create on show for direct accessible children
            {
                vcl::Window* pChildWin = static_cast < vcl::Window * >( rEvent.GetData() );
                if( pChildWin && AccessibleRole::EMBEDDED_OBJECT == pChildWin->GetAccessibleRole() )
                {
                    AddChild( pChildWin->GetAccessible(), true );
                }
            }
            break;
        case VclEventId::WindowHide:  // send destroy on hide for direct accessible children
            {
                vcl::Window* pChildWin = static_cast < vcl::Window * >( rEvent.GetData() );
                if( pChildWin && AccessibleRole::EMBEDDED_OBJECT == pChildWin->GetAccessibleRole() )
                {
                    RemoveChild( pChildWin->GetAccessible(), true );
                }
            }
            break;
        default: break;
        }
    }

    void ScAccessibleDocument::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
    {
        if (dynamic_cast<const ScAccGridWinFocusLostHint*>(&rHint) )
        {
            const ScAccGridWinFocusLostHint* pFocusLostHint = static_cast<const ScAccGridWinFocusLostHint *>(&rHint);
            if (pFocusLostHint->GetOldGridWin() == meSplitPos)
            {
                if (mxTempAcc.is() && mpTempAccEdit)
                    mpTempAccEdit->LostFocus();
                else if (mpAccessibleSpreadsheet.is())
                    mpAccessibleSpreadsheet->LostFocus();
                else
                    CommitFocusLost();
            }
        }
        else if (dynamic_cast<const ScAccGridWinFocusGotHint*>(&rHint) )
        {
            const ScAccGridWinFocusGotHint* pFocusGotHint = static_cast<const ScAccGridWinFocusGotHint*>(&rHint);
            if (pFocusGotHint->GetNewGridWin() == meSplitPos)
            {
                uno::Reference<XAccessible> xAccessible;
                if (mpChildrenShapes)
                {
                    bool bTabMarked(IsTableSelected());
                    xAccessible = mpChildrenShapes->GetSelected(0, bTabMarked);
                }
                if( xAccessible.is() )
                {
                    uno::Any aNewValue;
                    aNewValue<<=AccessibleStateType::FOCUSED;
                    static_cast< ::accessibility::AccessibleShape* >(xAccessible.get())->
                        CommitChange(AccessibleEventId::STATE_CHANGED,
                                    aNewValue,
                                    uno::Any() );
                }
                else
                {
                if (mxTempAcc.is() && mpTempAccEdit)
                    mpTempAccEdit->GotFocus();
                else if (mpAccessibleSpreadsheet.is())
                    mpAccessibleSpreadsheet->GotFocus();
                else
                    CommitFocusGained();
                }
            }
        }
        else
        {
            // only notify if child exist, otherwise it is not necessary
            if ((rHint.GetId() == SfxHintId::ScAccTableChanged) &&
                mpAccessibleSpreadsheet.is())
            {
                FreeAccessibleSpreadsheet();

                // Shapes / form controls after reload not accessible, rebuild the
                // mpChildrenShapes variable.
                mpChildrenShapes.reset( new ScChildrenShapes( this, mpViewShell, meSplitPos ) );

                AccessibleEventObject aEvent;
                aEvent.EventId = AccessibleEventId::INVALIDATE_ALL_CHILDREN;
                aEvent.Source = uno::Reference< XAccessibleContext >(this);
                CommitChange(aEvent); // all children changed

                if (mpAccessibleSpreadsheet.is())
                    mpAccessibleSpreadsheet->FireFirstCellFocus();
            }
            else if (rHint.GetId() == SfxHintId::ScAccMakeDrawLayer)
            {
                if (mpChildrenShapes)
                    mpChildrenShapes->SetDrawBroadcaster();
            }
            else if (rHint.GetId() == SfxHintId::ScAccEnterEditMode) // this event comes only on creating edit field of a cell
            {
                if (mpViewShell->GetViewData().GetEditActivePart() == meSplitPos)
                {
                    ScViewData& rViewData = mpViewShell->GetViewData();
                    const EditEngine* pEditEng = rViewData.GetEditView(meSplitPos)->GetEditEngine();
                    if (pEditEng && pEditEng->GetUpdateMode())
                    {
                        mpTempAccEdit = new ScAccessibleEditObject(this, rViewData.GetEditView(meSplitPos),
                            mpViewShell->GetWindowByPos(meSplitPos), GetCurrentCellName(),
                            ScResId(STR_ACC_EDITLINE_DESCR), ScAccessibleEditObject::CellInEditMode);
                        uno::Reference<XAccessible> xAcc = mpTempAccEdit;

                        AddChild(xAcc, true);

                        if (mpAccessibleSpreadsheet.is())
                            mpAccessibleSpreadsheet->LostFocus();
                        else
                            CommitFocusLost();

                        mpTempAccEdit->GotFocus();
                    }
                }
            }
            else if (rHint.GetId() == SfxHintId::ScAccLeaveEditMode)
            {
                if (mxTempAcc.is())
                {
                    if (mpTempAccEdit)
                        mpTempAccEdit->LostFocus();

                    mpTempAccEdit = nullptr;
                    RemoveChild(mxTempAcc, true);
                    if (mpAccessibleSpreadsheet.is() && mpViewShell && mpViewShell->IsActive())
                        mpAccessibleSpreadsheet->GotFocus();
                    else if( mpViewShell && mpViewShell->IsActive())
                        CommitFocusGained();
                }
            }
            else if ((rHint.GetId() == SfxHintId::ScAccVisAreaChanged) || (rHint.GetId() == SfxHintId::ScAccWindowResized))
            {
                tools::Rectangle aOldVisArea(maVisArea);
                maVisArea = GetVisibleArea_Impl();

                if (maVisArea != aOldVisArea)
                {
                    if (maVisArea.GetSize() != aOldVisArea.GetSize())
                    {
                        AccessibleEventObject aEvent;
                        aEvent.EventId = AccessibleEventId::BOUNDRECT_CHANGED;
                        aEvent.Source = uno::Reference< XAccessibleContext >(this);

                        CommitChange(aEvent);

                        if (mpAccessibleSpreadsheet.is())
                            mpAccessibleSpreadsheet->BoundingBoxChanged();
                        if (mpAccessibleSpreadsheet.is() && mpViewShell && mpViewShell->IsActive())
                            mpAccessibleSpreadsheet->FireFirstCellFocus();
                    }
                    else if (mpAccessibleSpreadsheet.is())
                    {
                        mpAccessibleSpreadsheet->VisAreaChanged();
                    }
                    if (mpChildrenShapes)
                        mpChildrenShapes->VisAreaChanged();
                }
            }
        }

        ScAccessibleDocumentBase::Notify(rBC, rHint);
    }

    void SAL_CALL ScAccessibleDocument::selectionChanged( const lang::EventObject& /* aEvent */ )
    {
        bool bSelectionChanged(false);
        if (mpAccessibleSpreadsheet.is())
        {
            bool bOldSelected(mbCompleteSheetSelected);
            mbCompleteSheetSelected = IsTableSelected();
            if (bOldSelected != mbCompleteSheetSelected)
            {
                mpAccessibleSpreadsheet->CompleteSelectionChanged(mbCompleteSheetSelected);
                bSelectionChanged = true;
            }
        }

        if (mpChildrenShapes && mpChildrenShapes->SelectionChanged())
            bSelectionChanged = true;

        if (bSelectionChanged)
        {
            AccessibleEventObject aEvent;
            aEvent.EventId = AccessibleEventId::SELECTION_CHANGED;
            aEvent.Source = uno::Reference< XAccessibleContext >(this);

            CommitChange(aEvent);
        }
    }

        //=====  XInterface  =====================================================

    uno::Any SAL_CALL ScAccessibleDocument::queryInterface( uno::Type const & rType )
    {
        uno::Any aAnyTmp;
        if(rType == cppu::UnoType<XAccessibleGetAccFlowTo>::get())
        {
             css::uno::Reference<XAccessibleGetAccFlowTo> AccFromXShape = this;
             aAnyTmp <<= AccFromXShape;
             return aAnyTmp;
        }
        uno::Any aAny (ScAccessibleDocumentImpl::queryInterface(rType));
        return aAny.hasValue() ? aAny : ScAccessibleContextBase::queryInterface(rType);
    }

    void SAL_CALL ScAccessibleDocument::acquire()
        throw ()
    {
        ScAccessibleContextBase::acquire();
    }

    void SAL_CALL ScAccessibleDocument::release()
        throw ()
    {
        ScAccessibleContextBase::release();
    }

        //=====  XAccessibleComponent  ============================================

    uno::Reference< XAccessible > SAL_CALL ScAccessibleDocument::getAccessibleAtPoint(
            const awt::Point& rPoint )
    {
        uno::Reference<XAccessible> xAccessible;
        if (containsPoint(rPoint))
        {
            SolarMutexGuard aGuard;
            IsObjectValid();
            if (mpChildrenShapes)
                xAccessible = mpChildrenShapes->GetAt(rPoint);
            if(!xAccessible.is())
            {
                if (mxTempAcc.is())
                {
                    uno::Reference< XAccessibleContext > xCont(mxTempAcc->getAccessibleContext());
                    uno::Reference< XAccessibleComponent > xComp(xCont, uno::UNO_QUERY);
                    if (xComp.is())
                    {
                        tools::Rectangle aBound(VCLRectangle(xComp->getBounds()));
                        if (aBound.IsInside(VCLPoint(rPoint)))
                            xAccessible = mxTempAcc;
                    }
                }
                if (!xAccessible.is())
                    xAccessible = GetAccessibleSpreadsheet();
            }
        }
        return xAccessible;
    }

    void SAL_CALL ScAccessibleDocument::grabFocus(  )
    {
        SolarMutexGuard aGuard;
        IsObjectValid();
        if (getAccessibleParent().is())
        {
            uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY);
            if (xAccessibleComponent.is())
            {
                xAccessibleComponent->grabFocus();
                // grab only focus if it does not have the focus and it is not hidden
                if (mpViewShell &&
                    (mpViewShell->GetViewData().GetActivePart() != meSplitPos) &&
                    mpViewShell->GetWindowByPos(meSplitPos)->IsVisible())
                {
                    mpViewShell->ActivatePart(meSplitPos);
                }
            }
        }
    }

        //=====  XAccessibleContext  ==============================================

        /// Return the number of currently visible children.
    sal_Int32 SAL_CALL
        ScAccessibleDocument::getAccessibleChildCount()
    {
        SolarMutexGuard aGuard;
        IsObjectValid();
        sal_Int32 nCount(1);
        if (mpChildrenShapes)
            nCount = mpChildrenShapes->GetCount(); // returns the count of the shapes inclusive the table

        if (mxTempAcc.is())
            ++nCount;

        return nCount;
    }

        /// Return the specified child or NULL if index is invalid.
    uno::Reference<XAccessible> SAL_CALL
        ScAccessibleDocument::getAccessibleChild(sal_Int32 nIndex)
    {
        SolarMutexGuard aGuard;
        IsObjectValid();
        uno::Reference<XAccessible> xAccessible;
        if (nIndex >= 0)
        {
            sal_Int32 nCount(1);
            if (mpChildrenShapes)
            {
                xAccessible = mpChildrenShapes->Get(nIndex); // returns NULL if it is the table or out of range
                nCount = mpChildrenShapes->GetCount(); //there is always a table
            }
            if (!xAccessible.is())
            {
                if (nIndex < nCount)
                    xAccessible = GetAccessibleSpreadsheet();
                else if (nIndex == nCount && mxTempAcc.is())
                    xAccessible = mxTempAcc;
            }
        }

        if (!xAccessible.is())
            throw lang::IndexOutOfBoundsException();

        return xAccessible;
    }

        /// Return the set of current states.
    uno::Reference<XAccessibleStateSet> SAL_CALL
        ScAccessibleDocument::getAccessibleStateSet()
    {
        SolarMutexGuard aGuard;
        uno::Reference<XAccessibleStateSet> xParentStates;
        if (getAccessibleParent().is())
        {
            uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext();
            xParentStates = xParentContext->getAccessibleStateSet();
        }
        utl::AccessibleStateSetHelper* pStateSet = new utl::AccessibleStateSetHelper();
        if (IsDefunc(xParentStates))
            pStateSet->AddState(AccessibleStateType::DEFUNC);
        else
        {
            pStateSet->AddState(AccessibleStateType::EDITABLE);
            pStateSet->AddState(AccessibleStateType::ENABLED);
            pStateSet->AddState(AccessibleStateType::OPAQUE);
            if (isShowing())
                pStateSet->AddState(AccessibleStateType::SHOWING);
            if (isVisible())
                pStateSet->AddState(AccessibleStateType::VISIBLE);
        }
        return pStateSet;
    }

    OUString SAL_CALL
        ScAccessibleDocument::getAccessibleName()
    {
        SolarMutexGuard g;

        OUString aName = ScResId(STR_ACC_DOC_SPREADSHEET);
        ScDocument* pScDoc = GetDocument();
        if (!pScDoc)
            return aName;

        SfxObjectShell* pObjSh = pScDoc->GetDocumentShell();
        if (!pObjSh)
            return aName;

        OUString aFileName;
        SfxMedium* pMed = pObjSh->GetMedium();
        if (pMed)
            aFileName = pMed->GetName();

        if (aFileName.isEmpty())
            aFileName = pObjSh->GetTitle(SFX_TITLE_APINAME);

        if (!aFileName.isEmpty())
        {
            OUString aReadOnly;
            if (pObjSh->IsReadOnly())
                aReadOnly = ScResId(STR_ACC_DOC_SPREADSHEET_READONLY);

            aName = aFileName + aReadOnly + " - " + aName;
        }
        return aName;
    }

    ///=====  XAccessibleSelection  ===========================================

    void SAL_CALL
        ScAccessibleDocument::selectAccessibleChild( sal_Int32 nChildIndex )
    {
        SolarMutexGuard aGuard;
        IsObjectValid();

        if (mpChildrenShapes && mpViewShell)
        {
            sal_Int32 nCount(mpChildrenShapes->GetCount()); // all shapes and the table
            if (mxTempAcc.is())
                ++nCount;
            if (nChildIndex < 0 || nChildIndex >= nCount)
                throw lang::IndexOutOfBoundsException();

            uno::Reference < XAccessible > xAccessible = mpChildrenShapes->Get(nChildIndex);
            if (xAccessible.is())
            {
                bool bWasTableSelected(IsTableSelected());

                if (mpChildrenShapes)
                    mpChildrenShapes->Select(nChildIndex); // throws no lang::IndexOutOfBoundsException if Index is too high

                if (bWasTableSelected)
                    mpViewShell->SelectAll();
            }
            else
            {
                if (mpViewShell)
                    mpViewShell->SelectAll();
            }
        }
    }

    sal_Bool SAL_CALL
        ScAccessibleDocument::isAccessibleChildSelected( sal_Int32 nChildIndex )
    {
        SolarMutexGuard aGuard;
        IsObjectValid();
        bool bResult(false);

        if (mpChildrenShapes)
        {
            sal_Int32 nCount(mpChildrenShapes->GetCount()); // all shapes and the table
            if (mxTempAcc.is())
                ++nCount;
            if (nChildIndex < 0 || nChildIndex >= nCount)
                throw lang::IndexOutOfBoundsException();

            uno::Reference < XAccessible > xAccessible = mpChildrenShapes->Get(nChildIndex);
            if (xAccessible.is())
            {
                uno::Reference<drawing::XShape> xShape;
                bResult = mpChildrenShapes->IsSelected(nChildIndex, xShape); // throws no lang::IndexOutOfBoundsException if Index is too high
            }
            else
            {
                if (mxTempAcc.is() && nChildIndex == nCount)
                    bResult = true;
                else
                    bResult = IsTableSelected();
            }
        }
        return bResult;
    }

    void SAL_CALL
        ScAccessibleDocument::clearAccessibleSelection(  )
    {
        SolarMutexGuard aGuard;
        IsObjectValid();

        if (mpChildrenShapes)
            mpChildrenShapes->DeselectAll(); //deselects all (also the table)
    }

    void SAL_CALL
        ScAccessibleDocument::selectAllAccessibleChildren(  )
    {
        SolarMutexGuard aGuard;
        IsObjectValid();

        if (mpChildrenShapes)
            mpChildrenShapes->SelectAll();

        // select table after shapes, because while selecting shapes the table will be deselected
        if (mpViewShell)
        {
            mpViewShell->SelectAll();
        }
    }

    sal_Int32 SAL_CALL
        ScAccessibleDocument::getSelectedAccessibleChildCount(  )
    {
        SolarMutexGuard aGuard;
        IsObjectValid();
        sal_Int32 nCount(0);

        if (mpChildrenShapes)
            nCount = mpChildrenShapes->GetSelectedCount();

        if (IsTableSelected())
            ++nCount;

        if (mxTempAcc.is())
            ++nCount;

        return nCount;
    }

    uno::Reference<XAccessible > SAL_CALL
        ScAccessibleDocument::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex )
    {
        SolarMutexGuard aGuard;
        IsObjectValid();
        uno::Reference<XAccessible> xAccessible;
        if (mpChildrenShapes)
        {
            sal_Int32 nCount(getSelectedAccessibleChildCount()); //all shapes and the table
            if (nSelectedChildIndex < 0 || nSelectedChildIndex >= nCount)
                throw lang::IndexOutOfBoundsException();

            bool bTabMarked(IsTableSelected());

            if (mpChildrenShapes)
                xAccessible = mpChildrenShapes->GetSelected(nSelectedChildIndex, bTabMarked); // throws no lang::IndexOutOfBoundsException if Index is too high
            if (mxTempAcc.is() && nSelectedChildIndex == nCount - 1)
                xAccessible = mxTempAcc;
            else if (bTabMarked)
                xAccessible = GetAccessibleSpreadsheet();
        }

        OSL_ENSURE(xAccessible.is(), "here should always be an accessible object or an exception thrown");

        return xAccessible;
    }

    void SAL_CALL
        ScAccessibleDocument::deselectAccessibleChild( sal_Int32 nChildIndex )
    {
        SolarMutexGuard aGuard;
        IsObjectValid();

        if (mpChildrenShapes && mpViewShell)
        {
            sal_Int32 nCount(mpChildrenShapes->GetCount()); // all shapes and the table
            if (mxTempAcc.is())
                ++nCount;
            if (nChildIndex < 0 || nChildIndex >= nCount)
                throw lang::IndexOutOfBoundsException();

            bool bTabMarked(IsTableSelected());

            uno::Reference < XAccessible > xAccessible = mpChildrenShapes->Get(nChildIndex);
            if (xAccessible.is())
            {
                if (mpChildrenShapes)
                    mpChildrenShapes->Deselect(nChildIndex); // throws no lang::IndexOutOfBoundsException if Index is too high

                if (bTabMarked)
                    mpViewShell->SelectAll(); // select the table again
            }
            else if (bTabMarked)
                mpViewShell->Unmark();
        }
    }

        //=====  XServiceInfo  ====================================================

    OUString SAL_CALL
        ScAccessibleDocument::getImplementationName()
    {
        return OUString("ScAccessibleDocument");
    }

    uno::Sequence< OUString> SAL_CALL
        ScAccessibleDocument::getSupportedServiceNames()
    {
        uno::Sequence< OUString > aSequence = ScAccessibleContextBase::getSupportedServiceNames();
        sal_Int32 nOldSize(aSequence.getLength());
        aSequence.realloc(nOldSize + 1);

        aSequence[nOldSize] = "com.sun.star.AccessibleSpreadsheetDocumentView";

        return aSequence;
    }

    //=====  XTypeProvider  =======================================================

    uno::Sequence< uno::Type > SAL_CALL ScAccessibleDocument::getTypes()
    {
        return comphelper::concatSequences(ScAccessibleDocumentImpl::getTypes(), ScAccessibleContextBase::getTypes());
    }

    uno::Sequence<sal_Int8> SAL_CALL
        ScAccessibleDocument::getImplementationId()
    {
        return css::uno::Sequence<sal_Int8>();
    }

    ///=====  IAccessibleViewForwarder  ========================================

    tools::Rectangle ScAccessibleDocument::GetVisibleArea_Impl() const
    {
        tools::Rectangle aVisRect(GetBoundingBox());

        if (mpViewShell)
        {
            Point aPoint(mpViewShell->GetViewData().GetPixPos(meSplitPos)); // returns a negative Point
            aPoint.setX(-aPoint.getX());
            aPoint.setY(-aPoint.getY());
            aVisRect.SetPos(aPoint);

            ScGridWindow* pWin = static_cast<ScGridWindow*>(mpViewShell->GetWindowByPos(meSplitPos));
            if (pWin)
                aVisRect = pWin->PixelToLogic(aVisRect, pWin->GetDrawMapMode());
        }

        return aVisRect;
    }

    tools::Rectangle ScAccessibleDocument::GetVisibleArea() const
    {
        SolarMutexGuard aGuard;
        IsObjectValid();
        return maVisArea;
    }

    Point ScAccessibleDocument::LogicToPixel (const Point& rPoint) const
    {
        SolarMutexGuard aGuard;
        IsObjectValid();
        Point aPoint;
        ScGridWindow* pWin = static_cast<ScGridWindow*>(mpViewShell->GetWindowByPos(meSplitPos));
        if (pWin)
        {
            aPoint = pWin->LogicToPixel(rPoint, pWin->GetDrawMapMode());
            aPoint += pWin->GetWindowExtentsRelative(nullptr).TopLeft();
        }
        return aPoint;
    }

    Size ScAccessibleDocument::LogicToPixel (const Size& rSize) const
    {
        SolarMutexGuard aGuard;
        IsObjectValid();
        Size aSize;
        ScGridWindow* pWin = static_cast<ScGridWindow*>(mpViewShell->GetWindowByPos(meSplitPos));
        if (pWin)
            aSize = pWin->LogicToPixel(rSize, pWin->GetDrawMapMode());
        return aSize;
    }

        //=====  internal  ========================================================

    utl::AccessibleRelationSetHelper* ScAccessibleDocument::GetRelationSet(const ScAddress* pAddress) const
    {
        utl::AccessibleRelationSetHelper* pRelationSet = nullptr;
        if (mpChildrenShapes)
            pRelationSet = mpChildrenShapes->GetRelationSet(pAddress);
        return pRelationSet;
    }

    OUString
        ScAccessibleDocument::createAccessibleDescription()
    {
        OUString sDescription = STR_ACC_DOC_DESCR;
        return sDescription;
    }

    OUString
        ScAccessibleDocument::createAccessibleName()
    {
        SolarMutexGuard aGuard;
        IsObjectValid();
        OUString sName = ScResId(STR_ACC_DOC_NAME);
        sal_Int32 nNumber(sal_Int32(meSplitPos) + 1);
        sName += OUString::number(nNumber);
        return sName;
    }

    tools::Rectangle ScAccessibleDocument::GetBoundingBoxOnScreen() const
    {
        tools::Rectangle aRect;
        if (mpViewShell)
        {
            vcl::Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos);
            if (pWindow)
                aRect = pWindow->GetWindowExtentsRelative(nullptr);
        }
        return aRect;
    }

    tools::Rectangle ScAccessibleDocument::GetBoundingBox() const
    {
        tools::Rectangle aRect;
        if (mpViewShell)
        {
            vcl::Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos);
            if (pWindow)
                aRect = pWindow->GetWindowExtentsRelative(pWindow->GetAccessibleParentWindow());
        }
        return aRect;
    }

    SCTAB ScAccessibleDocument::getVisibleTable() const
    {
        SCTAB nVisibleTable(0);
        if (mpViewShell)
            nVisibleTable = mpViewShell->GetViewData().GetTabNo();
        return nVisibleTable;
    }

    uno::Reference < XAccessible >
        ScAccessibleDocument::GetAccessibleSpreadsheet()
    {
        if (!mpAccessibleSpreadsheet.is() && mpViewShell)
        {
            mpAccessibleSpreadsheet = new ScAccessibleSpreadsheet(this, mpViewShell, getVisibleTable(), meSplitPos);
            mpAccessibleSpreadsheet->Init();
            mbCompleteSheetSelected = IsTableSelected();
        }
        return mpAccessibleSpreadsheet.get();
    }

    void ScAccessibleDocument::FreeAccessibleSpreadsheet()
    {
        if (mpAccessibleSpreadsheet.is())
        {
            mpAccessibleSpreadsheet->dispose();
            mpAccessibleSpreadsheet.clear();
        }
    }

    bool ScAccessibleDocument::IsTableSelected() const
    {
        bool bResult (false);
        if(mpViewShell)
        {
            SCTAB nTab(getVisibleTable());
            //#103800#; use a copy of MarkData
            ScMarkData aMarkData(mpViewShell->GetViewData().GetMarkData());
            aMarkData.MarkToMulti();
            if (aMarkData.IsAllMarked( ScRange( 0, 0, nTab, MAXCOL, MAXROW, nTab)))
                bResult = true;
        }
        return bResult;
    }

    bool ScAccessibleDocument::IsDefunc(
        const uno::Reference<XAccessibleStateSet>& rxParentStates)
    {
        return ScAccessibleContextBase::IsDefunc() || (mpViewShell == nullptr) || !getAccessibleParent().is() ||
            (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC));
    }

    void ScAccessibleDocument::AddChild(const uno::Reference<XAccessible>& xAcc, bool bFireEvent)
    {
        OSL_ENSURE(!mxTempAcc.is(), "this object should be removed before");
        if (xAcc.is())
        {
            mxTempAcc = xAcc;
            if( bFireEvent )
            {
                AccessibleEventObject aEvent;
                            aEvent.Source = uno::Reference<XAccessibleContext>(this);
                aEvent.EventId = AccessibleEventId::CHILD;
                aEvent.NewValue <<= mxTempAcc;
                CommitChange( aEvent );
            }
        }
    }

    void ScAccessibleDocument::RemoveChild(const uno::Reference<XAccessible>& xAcc, bool bFireEvent)
    {
        OSL_ENSURE(mxTempAcc.is(), "this object should be added before");
        if (xAcc.is())
        {
            OSL_ENSURE(xAcc.get() == mxTempAcc.get(), "only the same object should be removed");
            if( bFireEvent )
            {
                AccessibleEventObject aEvent;
                            aEvent.Source = uno::Reference<XAccessibleContext>(this);
                aEvent.EventId = AccessibleEventId::CHILD;
                aEvent.OldValue <<= mxTempAcc;
                CommitChange( aEvent );
            }
            mxTempAcc = nullptr;
        }
    }

    OUString ScAccessibleDocument::GetCurrentCellName() const
    {
        OUString sName(ScResId(STR_ACC_CELL_NAME));
        if (mpViewShell)
        {
            // Document not needed, because only the cell address, but not the tablename is needed
            OUString sAddress(mpViewShell->GetViewData().GetCurPos().Format(ScRefFlags::VALID));
            sName = sName.replaceFirst("%1", sAddress);
        }
        return sName;
    }

    OUString ScAccessibleDocument::GetCurrentCellDescription()
    {
        return OUString();
    }

    ScDocument *ScAccessibleDocument::GetDocument() const
    {
        return mpViewShell ? mpViewShell->GetViewData().GetDocument() : nullptr;
    }

    ScAddress   ScAccessibleDocument::GetCurCellAddress() const
    {
        return mpViewShell ? mpViewShell->GetViewData().GetCurPos() : ScAddress();
    }

    uno::Any SAL_CALL ScAccessibleDocument::getExtendedAttributes()
    {
        SolarMutexGuard g;

        uno::Any anyAtrribute;

        OUString sName;
        OUString sValue;
        sal_uInt16 sheetIndex;
        OUString sSheetName;
        sheetIndex = getVisibleTable();
        if(GetDocument()==nullptr)
            return anyAtrribute;
        GetDocument()->GetName(sheetIndex,sSheetName);
        sName = "page-name:";
        sValue = sName + sSheetName ;
        sName = ";page-number:";
        sValue += sName;
        sValue += OUString::number(sheetIndex+1) ;
        sName = ";total-pages:";
        sValue += sName;
        sValue += OUString::number(GetDocument()->GetTableCount());
        sValue += ";";
        anyAtrribute <<= sValue;
        return anyAtrribute;
    }

    css::uno::Sequence< css::uno::Any > ScAccessibleDocument::GetScAccFlowToSequence()
    {
        if ( getAccessibleChildCount() )
        {
            uno::Reference < XAccessible > xSCTableAcc = getAccessibleChild( 0 ); // table
            if ( xSCTableAcc.is() )
            {
                uno::Reference < XAccessibleSelection > xAccSelection( xSCTableAcc, uno::UNO_QUERY );
                sal_Int32 nSelCount = xAccSelection->getSelectedAccessibleChildCount();
                if( nSelCount )
                {
                    uno::Reference < XAccessible > xSel = xAccSelection->getSelectedAccessibleChild( 0 ); // selected cell
                    if ( xSel.is() )
                    {
                        uno::Reference < XAccessibleContext > xSelContext( xSel->getAccessibleContext() );
                        if ( xSelContext.is() )
                        {
                            if ( xSelContext->getAccessibleRole() == AccessibleRole::TABLE_CELL )
                            {
                                sal_Int32 nParaCount = 0;
                                uno::Sequence <uno::Any> aSequence(nSelCount);
                                for ( sal_Int32 i = 0; i < nSelCount; i++ )
                                {
                                    xSel = xAccSelection->getSelectedAccessibleChild( i )   ;
                                    if ( xSel.is() )
                                    {
                                        xSelContext = xSel->getAccessibleContext();
                                        if ( xSelContext.is() )
                                        {
                                            if ( xSelContext->getAccessibleRole() == AccessibleRole::TABLE_CELL )
                                            {
                                                aSequence[nParaCount] <<= xSel;
                                                nParaCount++;
                                            }
                                        }
                                    }
                                }
                                return aSequence;
                            }
                        }
                    }
                }
            }
        }
        uno::Sequence <uno::Any> aEmpty;
        return aEmpty;
    }

    css::uno::Sequence< css::uno::Any >
            SAL_CALL ScAccessibleDocument::getAccFlowTo(const css::uno::Any& rAny, sal_Int32 nType)
    {
        SolarMutexGuard g;

        const sal_Int32 SPELLCHECKFLOWTO = 1;
        const sal_Int32 FINDREPLACEFLOWTO = 2;
        if ( nType == SPELLCHECKFLOWTO )
        {
            uno::Reference< css::drawing::XShape > xShape;
            rAny >>= xShape;
            if ( xShape.is() )
            {
                uno::Reference < XAccessible > xAcc = mpChildrenShapes->GetAccessibleCaption(xShape);
                uno::Reference < XAccessibleSelection > xAccSelection( xAcc, uno::UNO_QUERY );
                if ( xAccSelection.is() )
                {
                    if ( xAccSelection->getSelectedAccessibleChildCount() )
                    {
                        uno::Reference < XAccessible > xSel = xAccSelection->getSelectedAccessibleChild( 0 );
                        if ( xSel.is() )
                        {
                            uno::Reference < XAccessibleContext > xSelContext( xSel->getAccessibleContext() );
                            if ( xSelContext.is() )
                            {
                                //if in sw we find the selected paragraph here
                                if ( xSelContext->getAccessibleRole() == AccessibleRole::PARAGRAPH )
                                {
                                    uno::Sequence<uno::Any> aRet( 1 );
                                    aRet[0] <<= xSel;
                                    return aRet;
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                if ( getSelectedAccessibleChildCount() )
                {
                    uno::Reference < XAccessible > xSel = getSelectedAccessibleChild( 0 );
                    if ( xSel.is() )
                    {
                        uno::Reference < XAccessibleContext > xSelContext( xSel->getAccessibleContext() );
                        if ( xSelContext.is() )
                        {
                            uno::Reference < XAccessibleSelection > xAccChildSelection( xSel, uno::UNO_QUERY );
                            if ( xAccChildSelection.is() )
                            {
                                if ( xAccChildSelection->getSelectedAccessibleChildCount() )
                                {
                                    uno::Reference < XAccessible > xChildSel = xAccChildSelection->getSelectedAccessibleChild( 0 );
                                    if ( xChildSel.is() )
                                    {
                                        uno::Reference < css::accessibility::XAccessibleContext > xChildSelContext( xChildSel->getAccessibleContext() );
                                        if ( xChildSelContext.is() &&
                                            xChildSelContext->getAccessibleRole() == css::accessibility::AccessibleRole::PARAGRAPH )
                                        {
                                            uno::Sequence<uno::Any> aRet( 1 );
                                            aRet[0] <<= xChildSel;
                                            return aRet;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        else if ( nType == FINDREPLACEFLOWTO )
        {
            bool bSuccess(false);
            rAny >>= bSuccess;
            if ( bSuccess )
            {
                uno::Sequence< uno::Any> aSeq = GetScAccFlowToSequence();
                if ( aSeq.getLength() )
                {
                    return aSeq;
                }
                else if( mpAccessibleSpreadsheet.is() )
                {
                    uno::Reference < XAccessible > xFindCellAcc = mpAccessibleSpreadsheet->GetActiveCell();
                    // add xFindCellAcc to the return the Sequence
                    uno::Sequence< uno::Any> aSeq2(1);
                    aSeq2[0] <<= xFindCellAcc;
                    return aSeq2;
                }
            }
        }
        uno::Sequence< uno::Any> aEmpty;
        return aEmpty;
    }

    sal_Int32 SAL_CALL ScAccessibleDocument::getForeground(  )
    {
        return sal_Int32(COL_BLACK);
    }

    sal_Int32 SAL_CALL ScAccessibleDocument::getBackground(  )
    {
        SolarMutexGuard aGuard;
        IsObjectValid();
        return sal_Int32(SC_MOD()->GetColorConfig().GetColorValue( ::svtools::DOCCOLOR ).nColor);
    }

    /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

↑ V547 Expression 'mpChildrenShapes' is always true.

↑ V1019 Compound assignment expression 'aPropAny2 >>= nLayerID2' is used inside condition.

↑ V1019 Compound assignment expression 'aAny2 >>= nZOrder2' is used inside condition.

↑ V547 Expression 'mpChildrenShapes' is always true.

↑ V547 Expression 'mpViewShell' is always true.