tdf#76324 speedup copy operation with lots of comments in calc

avoid performing a sort in AddShape, and cache some data to speed up the
sort

Makes it about 3 times faster for me, but is still pretty slow for that
large test document

Change-Id: I5c847e43ad5dd66caefcf12b9a624214767371b1
Reviewed-on: https://gerrit.libreoffice.org/79630
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
diff --git a/sc/source/ui/Accessibility/AccessibleDocument.cxx b/sc/source/ui/Accessibility/AccessibleDocument.cxx
index 76e7f21..af2312c 100644
--- a/sc/source/ui/Accessibility/AccessibleDocument.cxx
+++ b/sc/source/ui/Accessibility/AccessibleDocument.cxx
@@ -87,15 +87,38 @@

struct ScAccessibleShapeData
{
    ScAccessibleShapeData() : bSelected(false), bSelectable(true) {}
    ScAccessibleShapeData(css::uno::Reference< css::drawing::XShape > xShape_);
    ~ScAccessibleShapeData();
    mutable rtl::Reference< ::accessibility::AccessibleShape > pAccShape;
    mutable boost::optional<ScAddress> xRelationCell; // if it is NULL this shape is anchored on the table
    css::uno::Reference< css::drawing::XShape > xShape;
    mutable bool            bSelected;
    bool                    bSelectable;
    // cache these to make the sorting cheaper
    boost::optional<sal_Int16> mxLayerID;
    boost::optional<sal_Int32> mxZOrder;
};

ScAccessibleShapeData::ScAccessibleShapeData(css::uno::Reference< css::drawing::XShape > xShape_)
    : xShape(xShape_),
    bSelected(false), bSelectable(true)
{
    static constexpr OUStringLiteral gsLayerId = "LayerID";
    static constexpr OUStringLiteral gsZOrder = "ZOrder";
    uno::Reference< beans::XPropertySet> xProps(xShape, uno::UNO_QUERY);
    if (xProps.is())
    {
        uno::Any aAny = xProps->getPropertyValue(gsLayerId);
        sal_Int16 nLayerID;
        if (aAny >>= nLayerID)
            mxLayerID = nLayerID;
        sal_Int32 nZOrder;
        aAny = xProps->getPropertyValue(gsZOrder);
        if (aAny >>= nZOrder)
            mxZOrder = nZOrder;
    }
}

ScAccessibleShapeData::~ScAccessibleShapeData()
{
    if (pAccShape.is())
@@ -106,9 +129,6 @@

struct ScShapeDataLess
{
    static constexpr OUStringLiteral gsLayerId = "LayerID";
    static constexpr OUStringLiteral gsZOrder = "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"
@@ -133,15 +153,10 @@
    {
        bool bResult(false);
        uno::Reference< beans::XPropertySet> xProps(pData->xShape, uno::UNO_QUERY);
        if (xProps.is())
        if (pData->mxLayerID)
        {
            uno::Any aPropAny = xProps->getPropertyValue(gsLayerId);
            sal_Int16 nLayerID = 0;
            if( aPropAny >>= nLayerID )
            {
                if (SdrLayerID(nLayerID) == SC_LAYER_BACK)
                    bResult = true;
            }
            if (SdrLayerID(*pData->mxLayerID) == SC_LAYER_BACK)
                bResult = true;
        }
        return bResult;
    }
@@ -150,31 +165,20 @@
        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())
            if( pData1->mxLayerID && pData2->mxLayerID )
            {
                uno::Any aPropAny1 = xProps1->getPropertyValue(gsLayerId);
                uno::Any aPropAny2 = xProps2->getPropertyValue(gsLayerId);
                sal_Int16 nLayerID1(0);
                sal_Int16 nLayerID2(0);
                if( (aPropAny1 >>= nLayerID1) && (aPropAny2 >>= nLayerID2) )
                sal_Int16 nLayerID1 = *pData1->mxLayerID;
                sal_Int16 nLayerID2 = *pData2->mxLayerID;
                if (nLayerID1 == nLayerID2)
                {
                    if (nLayerID1 == nLayerID2)
                    {
                        uno::Any aAny1 = xProps1->getPropertyValue(gsZOrder);
                        sal_Int32 nZOrder1 = 0;
                        uno::Any aAny2 = xProps2->getPropertyValue(gsZOrder);
                        sal_Int32 nZOrder2 = 0;
                        if ( (aAny1 >>= nZOrder1) && (aAny2 >>= nZOrder2) )
                            bResult = (nZOrder1 < nZOrder2);
                    }
                    else
                    {
                        ConvertLayerId(nLayerID1);
                        ConvertLayerId(nLayerID2);
                        bResult = (nLayerID1 < nLayerID2);
                    }
                    if ( pData1->mxZOrder && pData2->mxZOrder )
                        bResult = (*pData1->mxZOrder < *pData2->mxZOrder);
                }
                else
                {
                    ConvertLayerId(nLayerID1);
                    ConvertLayerId(nLayerID2);
                    bResult = (nLayerID1 < nLayerID2);
                }
            }
        }
@@ -911,8 +915,7 @@
            xShapes->getByIndex(i) >>= xShape;
            if (xShape.is())
            {
                ScAccessibleShapeData* pShapeData = new ScAccessibleShapeData();
                pShapeData->xShape = xShape;
                ScAccessibleShapeData* pShapeData = new ScAccessibleShapeData(xShape);
                aShapesList.push_back(pShapeData);
            }
        }
@@ -1173,70 +1176,59 @@

void ScChildrenShapes::AddShape(const uno::Reference<drawing::XShape>& xShape, bool bCommitChange) const
{
    if (mbShapesNeedSorting)
    {
        std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
        mbShapesNeedSorting = false;
    }
    SortedShapes::iterator aFindItr;
    if (!FindShape(xShape, aFindItr))
    {
        ScAccessibleShapeData* pShape = new ScAccessibleShapeData();
        pShape->xShape = xShape;
        SortedShapes::iterator aNewItr = maZOrderedShapes.insert(aFindItr, pShape);
        maShapesMap[xShape] = pShape;
        SetAnchor(xShape, pShape);
    assert( maShapesMap.find(xShape) == maShapesMap.end());

        uno::Reference< beans::XPropertySet > xShapeProp(xShape, uno::UNO_QUERY);
        if (xShapeProp.is())
    ScAccessibleShapeData* pShape = new ScAccessibleShapeData(xShape);
    maZOrderedShapes.push_back(pShape);
    mbShapesNeedSorting = true;
    maShapesMap[xShape] = 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 )
        {
            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( (SdrLayerID(nLayerID) == SC_LAYER_INTERN) || (SdrLayerID(nLayerID) == SC_LAYER_HIDDEN) )
                pShape->bSelectable = false;
            else
                pShape->bSelectable = true;
        }
    }

        if (!xSelectionSupplier.is())
            throw uno::RuntimeException();
    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<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<container::XEnumeration> xEnum = xEnumAcc->createEnumeration();
            if (xEnum.is())
            uno::Reference<drawing::XShape> xSelectedShape;
            bool bFound(false);
            while (!bFound && xEnum->hasMoreElements())
            {
                uno::Reference<drawing::XShape> xSelectedShape;
                bool bFound(false);
                while (!bFound && xEnum->hasMoreElements())
                xEnum->nextElement() >>= xSelectedShape;
                if (xShape.is() && (xShape.get() == xSelectedShape.get()))
                {
                    xEnum->nextElement() >>= xSelectedShape;
                    if (xShape.is() && (xShape.get() == xSelectedShape.get()))
                    {
                        pShape->bSelected = true;
                        bFound = true;
                    }
                    pShape->bSelected = true;
                    bFound = true;
                }
            }
        }
        if (mpAccessibleDocument && bCommitChange)
        {
            AccessibleEventObject aEvent;
            aEvent.EventId = AccessibleEventId::CHILD;
            aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument);
            aEvent.NewValue <<= Get(*aNewItr);

            mpAccessibleDocument->CommitChange(aEvent); // new child - event
        }
    }
    else
    if (mpAccessibleDocument && bCommitChange)
    {
        OSL_FAIL("shape is always in the list");
        AccessibleEventObject aEvent;
        aEvent.EventId = AccessibleEventId::CHILD;
        aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument);
        aEvent.NewValue <<= Get(pShape);

        mpAccessibleDocument->CommitChange(aEvent); // new child - event
    }
}

@@ -1286,8 +1278,7 @@
        mbShapesNeedSorting = false;
    }
    bool bResult(false);
    ScAccessibleShapeData aShape;
    aShape.xShape = xShape;
    ScAccessibleShapeData aShape(xShape);
    rItr = std::lower_bound(maZOrderedShapes.begin(), maZOrderedShapes.end(), &aShape, ScShapeDataLess());
    if ((rItr != maZOrderedShapes.end()) && (*rItr != nullptr) && ((*rItr)->xShape.get() == xShape.get()))
        bResult = true; // if the shape is found