Resolves: tdf#139220 with ~1000 selected shapes a11y UpdateSelection crawls
so fetch the selected shapes once and sort them for quick lookup in the
loop over maVisibleChildren.
As an aside, not changed here, SvxShapeCollection::getByIndex looks
suboptimal with a body of
std::vector<Reference<uno::XInterface>> aElements(maShapeContainer.getElements());
return uno::makeAny(Reference<drawing::XShape>(aElements[Index].get()));
Change-Id: Idec7c003e7c5ee02000d4642d4fdb0d940548d97
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120610
Tested-by: Caolán McNamara <caolanm@redhat.com>
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
diff --git a/svx/source/accessibility/ChildrenManagerImpl.cxx b/svx/source/accessibility/ChildrenManagerImpl.cxx
index 53d1e75..573427c 100644
--- a/svx/source/accessibility/ChildrenManagerImpl.cxx
+++ b/svx/source/accessibility/ChildrenManagerImpl.cxx
@@ -38,6 +38,7 @@
#include <com/sun/star/container/XChild.hpp>
#include <comphelper/types.hxx>
#include <o3tl/safeint.hxx>
#include <o3tl/sorted_vector.hxx>
#include <rtl/ustring.hxx>
#include <tools/debug.hxx>
#include <svx/SvxShapeTypes.hxx>
@@ -793,20 +794,6 @@ uno::Reference<XAccessible>
*/
void ChildrenManagerImpl::UpdateSelection()
{
Reference<frame::XController> xController(maShapeTreeInfo.GetController());
Reference<view::XSelectionSupplier> xSelectionSupplier (
xController, uno::UNO_QUERY);
// Try to cast the selection both to a multi selection and to a single
// selection.
Reference<container::XIndexAccess> xSelectedShapeAccess;
Reference<drawing::XShape> xSelectedShape;
if (xSelectionSupplier.is())
{
xSelectedShapeAccess.set( xSelectionSupplier->getSelection(), uno::UNO_QUERY);
xSelectedShape.set( xSelectionSupplier->getSelection(), uno::UNO_QUERY);
}
// Remember the current and new focused shape.
AccessibleShape* pCurrentlyFocusedShape = nullptr;
AccessibleShape* pNewFocusedShape = nullptr;
@@ -815,73 +802,101 @@ void ChildrenManagerImpl::UpdateSelection()
VEC_SHAPE vecSelect;
int nAddSelect=0;
bool bHasSelectedShape=false;
for (const auto& rChild : maVisibleChildren)
if (!maVisibleChildren.empty())
{
AccessibleShape* pAccessibleShape = rChild.GetAccessibleShape();
if (rChild.mxAccessibleShape.is() && rChild.mxShape.is() && pAccessibleShape!=nullptr)
{
short nRole = pAccessibleShape->getAccessibleRole();
bool bDrawShape = (
nRole == AccessibleRole::GRAPHIC ||
nRole == AccessibleRole::EMBEDDED_OBJECT ||
nRole == AccessibleRole::SHAPE ||
nRole == AccessibleRole::IMAGE_MAP ||
nRole == AccessibleRole::TABLE_CELL ||
nRole == AccessibleRole::TABLE );
bool bShapeIsSelected = false;
Reference<frame::XController> xController(maShapeTreeInfo.GetController());
Reference<view::XSelectionSupplier> xSelectionSupplier (
xController, uno::UNO_QUERY);
// Look up the shape in the (single or multi-) selection.
if (xSelectedShape.is())
// Try to cast the selection both to a multi selection and to a single
// selection.
Reference<container::XIndexAccess> xSelectedShapeAccess;
Reference<drawing::XShape> xSelectedShape;
if (xSelectionSupplier.is())
{
xSelectedShapeAccess.set( xSelectionSupplier->getSelection(), uno::UNO_QUERY);
xSelectedShape.set( xSelectionSupplier->getSelection(), uno::UNO_QUERY);
}
// tdf#139220 to quickly find if a given drawing::XShape is selected
o3tl::sorted_vector<css::uno::Reference<css::drawing::XShape>> aSortedSelectedShapes;
if (!xSelectedShape.is() && xSelectedShapeAccess.is())
{
sal_Int32 nCount = xSelectedShapeAccess->getCount();
aSortedSelectedShapes.reserve(nCount);
for (sal_Int32 i = 0; i < nCount; ++i)
{
if (rChild.mxShape == xSelectedShape)
{
bShapeIsSelected = true;
pNewFocusedShape = pAccessibleShape;
}
css::uno::Reference<css::drawing::XShape> xShape(xSelectedShapeAccess->getByIndex(i), uno::UNO_QUERY);
aSortedSelectedShapes.insert(xShape);
}
else if (xSelectedShapeAccess.is())
}
for (const auto& rChild : maVisibleChildren)
{
AccessibleShape* pAccessibleShape = rChild.GetAccessibleShape();
if (rChild.mxAccessibleShape.is() && rChild.mxShape.is() && pAccessibleShape!=nullptr)
{
sal_Int32 nCount=xSelectedShapeAccess->getCount();
for (sal_Int32 i=0; i<nCount&&!bShapeIsSelected; i++)
if (xSelectedShapeAccess->getByIndex(i) == rChild.mxShape)
short nRole = pAccessibleShape->getAccessibleRole();
bool bDrawShape = (
nRole == AccessibleRole::GRAPHIC ||
nRole == AccessibleRole::EMBEDDED_OBJECT ||
nRole == AccessibleRole::SHAPE ||
nRole == AccessibleRole::IMAGE_MAP ||
nRole == AccessibleRole::TABLE_CELL ||
nRole == AccessibleRole::TABLE );
bool bShapeIsSelected = false;
// Look up the shape in the (single or multi-) selection.
if (xSelectedShape.is())
{
if (rChild.mxShape == xSelectedShape)
{
bShapeIsSelected = true;
pNewFocusedShape = pAccessibleShape;
}
}
else if (!aSortedSelectedShapes.empty())
{
if (aSortedSelectedShapes.find(rChild.mxShape) != aSortedSelectedShapes.end())
{
bShapeIsSelected = true;
// In a multi-selection no shape has the focus.
if (nCount == 1)
if (aSortedSelectedShapes.size() == 1)
pNewFocusedShape = pAccessibleShape;
}
}
}
// Set or reset the SELECTED state.
if (bShapeIsSelected)
{
if (pAccessibleShape->SetState (AccessibleStateType::SELECTED))
// Set or reset the SELECTED state.
if (bShapeIsSelected)
{
if (bDrawShape)
if (pAccessibleShape->SetState (AccessibleStateType::SELECTED))
{
vecSelect.emplace_back(pAccessibleShape,true);
++nAddSelect;
if (bDrawShape)
{
vecSelect.emplace_back(pAccessibleShape,true);
++nAddSelect;
}
}
else
{//Selected not change,has selected shape before
bHasSelectedShape=true;
}
}
else
{//Selected not change,has selected shape before
bHasSelectedShape=true;
}
}
else
//pAccessibleShape->ResetState (AccessibleStateType::SELECTED);
{
if(pAccessibleShape->ResetState (AccessibleStateType::SELECTED))
//pAccessibleShape->ResetState (AccessibleStateType::SELECTED);
{
if(bDrawShape)
if(pAccessibleShape->ResetState (AccessibleStateType::SELECTED))
{
vecSelect.emplace_back(pAccessibleShape,false);
if(bDrawShape)
{
vecSelect.emplace_back(pAccessibleShape,false);
}
}
}
// Does the shape have the current selection?
if (pAccessibleShape->GetState (AccessibleStateType::FOCUSED))
pCurrentlyFocusedShape = pAccessibleShape;
}
// Does the shape have the current selection?
if (pAccessibleShape->GetState (AccessibleStateType::FOCUSED))
pCurrentlyFocusedShape = pAccessibleShape;
}
}