tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / ui / Accessibility / AccessibleDocument.cxx
blob5658ee2a27a925b4954787990a4c059ec39bac75
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <AccessibleDocument.hxx>
21 #include <AccessibleSpreadsheet.hxx>
22 #include <tabvwsh.hxx>
23 #include <AccessibilityHints.hxx>
24 #include <document.hxx>
25 #include <drwlayer.hxx>
26 #include <DrawModelBroadcaster.hxx>
27 #include <drawview.hxx>
28 #include <gridwin.hxx>
29 #include <AccessibleEditObject.hxx>
30 #include <userdat.hxx>
31 #include <scresid.hxx>
32 #include <strings.hrc>
33 #include <strings.hxx>
34 #include <markdata.hxx>
36 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
37 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
38 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
39 #include <com/sun/star/accessibility/AccessibleRole.hpp>
40 #include <com/sun/star/view/XSelectionSupplier.hpp>
41 #include <com/sun/star/drawing/ShapeCollection.hpp>
42 #include <com/sun/star/drawing/XShape.hpp>
43 #include <com/sun/star/drawing/XShapes.hpp>
44 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
45 #include <o3tl/safeint.hxx>
46 #include <tools/gen.hxx>
47 #include <svx/svdpage.hxx>
48 #include <svx/svdobj.hxx>
49 #include <svx/ShapeTypeHandler.hxx>
50 #include <svx/AccessibleShape.hxx>
51 #include <svx/AccessibleShapeTreeInfo.hxx>
52 #include <svx/AccessibleShapeInfo.hxx>
53 #include <svx/IAccessibleParent.hxx>
54 #include <comphelper/sequence.hxx>
55 #include <sfx2/viewfrm.hxx>
56 #include <sfx2/docfile.hxx>
57 #include <toolkit/helper/vclunohelper.hxx>
58 #include <unotools/accessiblerelationsethelper.hxx>
59 #include <utility>
60 #include <vcl/svapp.hxx>
61 #include <vcl/unohelp.hxx>
63 #include <svx/AccessibleControlShape.hxx>
64 #include <svx/SvxShapeTypes.hxx>
65 #include <sfx2/objsh.hxx>
66 #include <editeng/editview.hxx>
67 #include <editeng/editeng.hxx>
68 #include <comphelper/processfactory.hxx>
70 #include <algorithm>
72 #include <scmod.hxx>
74 #ifdef indices
75 #undef indices
76 #endif
78 #ifdef extents
79 #undef extents
80 #endif
82 using namespace ::com::sun::star;
83 using namespace ::com::sun::star::accessibility;
85 //===== internal ========================================================
87 namespace {
89 struct ScAccessibleShapeData
91 ScAccessibleShapeData(css::uno::Reference< css::drawing::XShape > xShape_);
92 ~ScAccessibleShapeData();
93 mutable rtl::Reference< ::accessibility::AccessibleShape > pAccShape;
94 std::optional<ScAddress> xRelationCell; // if it is NULL this shape is anchored on the table
95 css::uno::Reference< css::drawing::XShape > xShape;
96 bool bSelected;
97 bool bSelectable;
98 // cache these to make the sorting cheaper
99 std::optional<sal_Int16> mxLayerID;
100 std::optional<sal_Int32> mxZOrder;
105 ScAccessibleShapeData::ScAccessibleShapeData(css::uno::Reference< css::drawing::XShape > xShape_)
106 : xShape(std::move(xShape_)),
107 bSelected(false), bSelectable(true)
109 static constexpr OUStringLiteral gsLayerId = u"LayerID";
110 static constexpr OUStringLiteral gsZOrder = u"ZOrder";
111 uno::Reference< beans::XPropertySet> xProps(xShape, uno::UNO_QUERY);
112 if (xProps.is())
114 uno::Any aAny = xProps->getPropertyValue(gsLayerId);
115 sal_Int16 nLayerID;
116 if (aAny >>= nLayerID)
117 mxLayerID = nLayerID;
118 sal_Int32 nZOrder;
119 aAny = xProps->getPropertyValue(gsZOrder);
120 if (aAny >>= nZOrder)
121 mxZOrder = nZOrder;
125 ScAccessibleShapeData::~ScAccessibleShapeData()
127 if (pAccShape.is())
129 pAccShape->dispose();
133 namespace {
135 struct ScShapeDataLess
137 static void ConvertLayerId(sal_Int16& rLayerID) // changes the number of the LayerId so it the accessibility order
139 // note: MSVC 2017 ICE's if this is written as "switch" so use "if"
140 if (SC_LAYER_FRONT.get() == rLayerID)
142 rLayerID = 1;
144 else if (SC_LAYER_BACK.get() == rLayerID)
146 rLayerID = 0;
148 else if (SC_LAYER_INTERN.get() == rLayerID)
150 rLayerID = 2;
152 else if (SC_LAYER_CONTROLS.get() == rLayerID)
154 rLayerID = 3;
157 static bool LessThanSheet(const ScAccessibleShapeData* pData)
159 bool bResult(false);
160 if (pData->mxLayerID)
162 if (SdrLayerID(*pData->mxLayerID) == SC_LAYER_BACK)
163 bResult = true;
165 return bResult;
167 bool operator()(const ScAccessibleShapeData* pData1, const ScAccessibleShapeData* pData2) const
169 bool bResult(false);
170 if (pData1 && pData2)
172 if( pData1->mxLayerID && pData2->mxLayerID )
174 sal_Int16 nLayerID1 = *pData1->mxLayerID;
175 sal_Int16 nLayerID2 = *pData2->mxLayerID;
176 if (nLayerID1 == nLayerID2)
178 if ( pData1->mxZOrder && pData2->mxZOrder )
179 bResult = (*pData1->mxZOrder < *pData2->mxZOrder);
181 else
183 ConvertLayerId(nLayerID1);
184 ConvertLayerId(nLayerID2);
185 bResult = (nLayerID1 < nLayerID2);
189 else if (pData1 && !pData2)
190 bResult = LessThanSheet(pData1);
191 else if (!pData1 && pData2)
192 bResult = !LessThanSheet(pData2);
193 else
194 bResult = false;
195 return bResult;
201 class ScChildrenShapes : public SfxListener,
202 public ::accessibility::IAccessibleParent
204 public:
205 ScChildrenShapes(ScAccessibleDocument* pAccessibleDocument, ScTabViewShell* pViewShell, ScSplitPos eSplitPos);
206 virtual ~ScChildrenShapes() override;
208 ///===== SfxListener =====================================================
210 virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
212 ///===== IAccessibleParent ===============================================
214 virtual bool ReplaceChild (
215 ::accessibility::AccessibleShape* pCurrentChild,
216 const css::uno::Reference< css::drawing::XShape >& _rxShape,
217 const tools::Long _nIndex,
218 const ::accessibility::AccessibleShapeTreeInfo& _rShapeTreeInfo
219 ) override;
221 virtual ::accessibility::AccessibleControlShape* GetAccControlShapeFromModel
222 (css::beans::XPropertySet* pSet) override;
223 virtual css::uno::Reference< css::accessibility::XAccessible>
224 GetAccessibleCaption (const css::uno::Reference<css::drawing::XShape>& xShape) override;
225 ///===== Internal ========================================================
226 void SetDrawBroadcaster();
228 sal_Int32 GetCount() const;
229 uno::Reference< XAccessible > Get(const ScAccessibleShapeData* pData) const;
230 uno::Reference< XAccessible > Get(sal_Int32 nIndex) const;
231 uno::Reference< XAccessible > GetAt(const awt::Point& rPoint) const;
233 // gets the index of the shape starting on 0 (without the index of the table)
234 // returns the selected shape
235 bool IsSelected(sal_Int32 nIndex,
236 css::uno::Reference<css::drawing::XShape>& rShape) const;
238 bool SelectionChanged();
240 void Select(sal_Int32 nIndex);
241 void DeselectAll(); // deselect also the table
242 void SelectAll();
243 sal_Int32 GetSelectedCount() const;
244 uno::Reference< XAccessible > GetSelected(sal_Int32 nSelectedChildIndex, bool bTabSelected) const;
245 void Deselect(sal_Int32 nChildIndex);
247 SdrPage* GetDrawPage() const;
249 rtl::Reference<utl::AccessibleRelationSetHelper> GetRelationSet(const ScAddress* pAddress) const;
251 void VisAreaChanged() const;
252 private:
253 typedef std::vector<ScAccessibleShapeData*> SortedShapes;
254 typedef std::unordered_map<css::uno::Reference< css::drawing::XShape >, ScAccessibleShapeData*> ShapesMap;
256 mutable SortedShapes maZOrderedShapes; // a null pointer represents the sheet in the correct order
257 mutable ShapesMap maShapesMap;
258 mutable bool mbShapesNeedSorting; // set if maZOrderedShapes needs sorting
260 mutable ::accessibility::AccessibleShapeTreeInfo maShapeTreeInfo;
261 mutable css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier;
262 mutable sal_uInt32 mnShapesSelected;
263 ScTabViewShell* mpViewShell;
264 ScAccessibleDocument* mpAccessibleDocument;
265 ScSplitPos meSplitPos;
267 void FillShapes(std::vector < uno::Reference < drawing::XShape > >& rShapes) const;
268 bool FindSelectedShapesChanges(const css::uno::Reference<css::drawing::XShapes>& xShapes) const;
270 std::optional<ScAddress> GetAnchor(const uno::Reference<drawing::XShape>& xShape) const;
271 rtl::Reference<utl::AccessibleRelationSetHelper> GetRelationSet(const ScAccessibleShapeData* pData) const;
272 void SetAnchor(const uno::Reference<drawing::XShape>& xShape, ScAccessibleShapeData* pData) const;
273 void AddShape(const uno::Reference<drawing::XShape>& xShape, bool bCommitChange) const;
274 void RemoveShape(const uno::Reference<drawing::XShape>& xShape) const;
276 bool FindShape(const uno::Reference<drawing::XShape>& xShape, SortedShapes::iterator& rItr) const;
278 static sal_Int8 Compare(const ScAccessibleShapeData* pData1,
279 const ScAccessibleShapeData* pData2);
282 ScChildrenShapes::ScChildrenShapes(ScAccessibleDocument* pAccessibleDocument, ScTabViewShell* pViewShell, ScSplitPos eSplitPos)
284 mbShapesNeedSorting(false),
285 mnShapesSelected(0),
286 mpViewShell(pViewShell),
287 mpAccessibleDocument(pAccessibleDocument),
288 meSplitPos(eSplitPos)
290 if (mpViewShell)
292 SfxViewFrame& rViewFrame = mpViewShell->GetViewFrame();
293 xSelectionSupplier = uno::Reference<view::XSelectionSupplier>(rViewFrame.GetFrame().GetController(), uno::UNO_QUERY);
294 if (xSelectionSupplier.is())
296 xSelectionSupplier->addSelectionChangeListener(mpAccessibleDocument);
297 uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
298 if (xShapes.is())
299 mnShapesSelected = xShapes->getCount();
303 maZOrderedShapes.push_back(nullptr); // add an element which represents the table
305 GetCount(); // fill list with filtered shapes (no internal shapes)
307 if (mnShapesSelected)
309 //set flag on every selected shape
310 if (!xSelectionSupplier.is())
311 throw uno::RuntimeException("Could not get selected shapes. Null reference to xSelectionSupplier in ScChildrenShapes::ScChildrenShapes.");
313 uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
314 if (xShapes.is())
315 FindSelectedShapesChanges(xShapes);
317 if (!pViewShell)
318 return;
320 ScViewData& rViewData = pViewShell->GetViewData();
321 SfxBroadcaster* pDrawBC = rViewData.GetDocument().GetDrawBroadcaster();
322 if (pDrawBC)
324 StartListening(*pDrawBC);
326 maShapeTreeInfo.SetModelBroadcaster( new ScDrawModelBroadcaster(rViewData.GetDocument().GetDrawLayer()) );
327 maShapeTreeInfo.SetSdrView(rViewData.GetScDrawView());
328 maShapeTreeInfo.SetController(nullptr);
329 maShapeTreeInfo.SetWindow(pViewShell->GetWindowByPos(meSplitPos));
330 maShapeTreeInfo.SetViewForwarder(mpAccessibleDocument);
334 ScChildrenShapes::~ScChildrenShapes()
336 for (ScAccessibleShapeData* pShapeData : maZOrderedShapes)
337 delete pShapeData;
338 if (mpViewShell)
340 SfxBroadcaster* pDrawBC = mpViewShell->GetViewData().GetDocument().GetDrawBroadcaster();
341 if (pDrawBC)
342 EndListening(*pDrawBC);
344 if (mpAccessibleDocument && xSelectionSupplier.is())
345 xSelectionSupplier->removeSelectionChangeListener(mpAccessibleDocument);
348 void ScChildrenShapes::SetDrawBroadcaster()
350 if (!mpViewShell)
351 return;
353 ScViewData& rViewData = mpViewShell->GetViewData();
354 SfxBroadcaster* pDrawBC = rViewData.GetDocument().GetDrawBroadcaster();
355 if (pDrawBC)
357 StartListening(*pDrawBC, DuplicateHandling::Prevent);
359 maShapeTreeInfo.SetModelBroadcaster( new ScDrawModelBroadcaster(rViewData.GetDocument().GetDrawLayer()) );
360 maShapeTreeInfo.SetSdrView(rViewData.GetScDrawView());
361 maShapeTreeInfo.SetController(nullptr);
362 maShapeTreeInfo.SetWindow(mpViewShell->GetWindowByPos(meSplitPos));
363 maShapeTreeInfo.SetViewForwarder(mpAccessibleDocument);
367 void ScChildrenShapes::Notify(SfxBroadcaster&, const SfxHint& rHint)
369 if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint)
370 return;
371 const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
373 SdrObject* pObj = const_cast<SdrObject*>(pSdrHint->GetObject());
374 if (!(pObj && /*(pObj->GetLayer() != SC_LAYER_INTERN) && */(pObj->getSdrPageFromSdrObject() == GetDrawPage()) &&
375 (pObj->getSdrPageFromSdrObject() == pObj->getParentSdrObjListFromSdrObject())) ) //only do something if the object lies direct on the page
376 return;
378 switch (pSdrHint->GetKind())
380 case SdrHintKind::ObjectChange : // object changed
382 uno::Reference<drawing::XShape> xShape (pObj->getUnoShape(), uno::UNO_QUERY);
383 if (xShape.is())
385 mbShapesNeedSorting = true; // sort, because the z index or layer could be changed
386 auto it = maShapesMap.find(xShape);
387 if (it != maShapesMap.end())
388 SetAnchor(xShape, it->second);
391 break;
392 case SdrHintKind::ObjectInserted : // new drawing object inserted
394 uno::Reference<drawing::XShape> xShape (pObj->getUnoShape(), uno::UNO_QUERY);
395 if (xShape.is())
396 AddShape(xShape, true);
398 break;
399 case SdrHintKind::ObjectRemoved : // Removed drawing object from list
401 uno::Reference<drawing::XShape> xShape (pObj->getUnoShape(), uno::UNO_QUERY);
402 if (xShape.is())
403 RemoveShape(xShape);
405 break;
406 default :
408 // other events are not interesting
410 break;
414 bool ScChildrenShapes::ReplaceChild (::accessibility::AccessibleShape* pCurrentChild,
415 const css::uno::Reference< css::drawing::XShape >& _rxShape,
416 const tools::Long /*_nIndex*/, const ::accessibility::AccessibleShapeTreeInfo& _rShapeTreeInfo)
418 // create the new child
419 rtl::Reference< ::accessibility::AccessibleShape > pReplacement(::accessibility::ShapeTypeHandler::Instance().CreateAccessibleObject (
420 ::accessibility::AccessibleShapeInfo ( _rxShape, pCurrentChild->getAccessibleParent(), this ),
421 _rShapeTreeInfo
424 bool bResult(false);
425 if (pReplacement.is())
427 OSL_ENSURE(pCurrentChild->GetXShape().get() == pReplacement->GetXShape().get(), "XShape changes and should be inserted sorted");
428 auto it = maShapesMap.find(pCurrentChild->GetXShape());
429 if (it != maShapesMap.end() && it->second->pAccShape.is())
431 OSL_ENSURE(it->second->pAccShape == pCurrentChild, "wrong child found");
432 AccessibleEventObject aEvent;
433 aEvent.EventId = AccessibleEventId::CHILD;
434 aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument);
435 aEvent.OldValue <<= uno::Reference<XAccessible>(pCurrentChild);
436 aEvent.IndexHint = -1;
438 mpAccessibleDocument->CommitChange(aEvent); // child is gone - event
440 pCurrentChild->dispose();
443 // Init after above possible pCurrentChild->dispose so we don't trigger the assert
444 // ScDrawModelBroadcaster::addShapeEventListener of duplicate listeners
445 pReplacement->Init();
447 if (it != maShapesMap.end())
449 it->second->pAccShape = pReplacement;
450 AccessibleEventObject aEvent;
451 aEvent.EventId = AccessibleEventId::CHILD;
452 aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument);
453 aEvent.NewValue <<= uno::Reference<XAccessible>(pReplacement);
454 aEvent.IndexHint = -1;
456 mpAccessibleDocument->CommitChange(aEvent); // child is new - event
457 bResult = true;
460 return bResult;
463 ::accessibility::AccessibleControlShape * ScChildrenShapes::GetAccControlShapeFromModel(css::beans::XPropertySet* pSet)
465 GetCount(); // populate
466 for (ScAccessibleShapeData* pShape : maZOrderedShapes)
468 if (pShape)
470 rtl::Reference< ::accessibility::AccessibleShape > pAccShape(pShape->pAccShape);
471 if (pAccShape.is() && ::accessibility::ShapeTypeHandler::Instance().GetTypeId (pAccShape->GetXShape()) == ::accessibility::DRAWING_CONTROL)
473 ::accessibility::AccessibleControlShape *pCtlAccShape = static_cast < ::accessibility::AccessibleControlShape* >(pAccShape.get());
474 if (pCtlAccShape && pCtlAccShape->GetControlModel() == pSet)
475 return pCtlAccShape;
479 return nullptr;
482 css::uno::Reference < css::accessibility::XAccessible >
483 ScChildrenShapes::GetAccessibleCaption (const css::uno::Reference < css::drawing::XShape>& xShape)
485 GetCount(); // populate
486 auto it = maShapesMap.find(xShape);
487 if (it == maShapesMap.end())
488 return nullptr;
489 ScAccessibleShapeData* pShape = it->second;
490 css::uno::Reference< css::accessibility::XAccessible > xNewChild( pShape->pAccShape );
491 if(xNewChild)
492 return xNewChild;
493 return nullptr;
496 sal_Int32 ScChildrenShapes::GetCount() const
498 SdrPage* pDrawPage = GetDrawPage();
499 if (pDrawPage && (maZOrderedShapes.size() == 1)) // the table is always in
501 size_t nSdrObjCount = pDrawPage->GetObjCount();
502 maZOrderedShapes.reserve(nSdrObjCount + 1); // the table is always in
503 for (const rtl::Reference<SdrObject>& pObj : *pDrawPage)
505 uno::Reference< drawing::XShape > xShape (pObj->getUnoShape(), uno::UNO_QUERY);
506 AddShape(xShape, false); //inserts in the correct order
509 return maZOrderedShapes.size();
512 uno::Reference< XAccessible > ScChildrenShapes::Get(const ScAccessibleShapeData* pData) const
514 if (!pData)
515 return nullptr;
517 if (!pData->pAccShape.is())
519 ::accessibility::ShapeTypeHandler& rShapeHandler = ::accessibility::ShapeTypeHandler::Instance();
520 ::accessibility::AccessibleShapeInfo aShapeInfo(pData->xShape, mpAccessibleDocument, const_cast<ScChildrenShapes*>(this));
521 pData->pAccShape = rShapeHandler.CreateAccessibleObject(
522 aShapeInfo, maShapeTreeInfo);
523 if (pData->pAccShape.is())
525 pData->pAccShape->Init();
526 if (pData->bSelected)
527 pData->pAccShape->SetState(AccessibleStateType::SELECTED);
528 if (!pData->bSelectable)
529 pData->pAccShape->ResetState(AccessibleStateType::SELECTABLE);
530 pData->pAccShape->SetRelationSet(GetRelationSet(pData));
533 return pData->pAccShape;
536 uno::Reference< XAccessible > ScChildrenShapes::Get(sal_Int32 nIndex) const
538 if (maZOrderedShapes.size() <= 1)
539 GetCount(); // fill list with filtered shapes (no internal shapes)
541 if (mbShapesNeedSorting)
543 std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
544 mbShapesNeedSorting = false;
547 if (o3tl::make_unsigned(nIndex) >= maZOrderedShapes.size())
548 return nullptr;
550 return Get(maZOrderedShapes[nIndex]);
553 uno::Reference< XAccessible > ScChildrenShapes::GetAt(const awt::Point& rPoint) const
555 uno::Reference<XAccessible> xAccessible;
556 if(mpViewShell)
558 if (mbShapesNeedSorting)
560 std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
561 mbShapesNeedSorting = false;
564 sal_Int32 i(maZOrderedShapes.size() - 1);
565 bool bFound(false);
566 while (!bFound && i >= 0)
568 ScAccessibleShapeData* pShape = maZOrderedShapes[i];
569 if (pShape)
571 if (!pShape->pAccShape.is())
572 Get(pShape);
574 if (pShape->pAccShape.is())
576 Point aPoint(vcl::unohelper::ConvertToVCLPoint(rPoint));
577 aPoint
578 -= vcl::unohelper::ConvertToVCLRect(pShape->pAccShape->getBounds()).TopLeft();
579 if (pShape->pAccShape->containsPoint(vcl::unohelper::ConvertToAWTPoint(aPoint)))
581 xAccessible = pShape->pAccShape.get();
582 bFound = true;
585 else
587 OSL_FAIL("I should have an accessible shape now!");
590 else
591 bFound = true; // this is the sheet and it lies before the rest of the shapes which are background shapes
593 --i;
596 return xAccessible;
599 bool ScChildrenShapes::IsSelected(sal_Int32 nIndex,
600 uno::Reference<drawing::XShape>& rShape) const
602 bool bResult (false);
603 if (maZOrderedShapes.size() <= 1)
604 GetCount(); // fill list with filtered shapes (no internal shapes)
606 if (!xSelectionSupplier.is())
607 throw uno::RuntimeException("Could not get selected shapes. Null reference to xSelectionSupplier in ScChildrenShapes::IsSelected.");
609 if (mbShapesNeedSorting)
611 std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
612 mbShapesNeedSorting = false;
615 if (!maZOrderedShapes[nIndex])
616 return false;
618 bResult = maZOrderedShapes[nIndex]->bSelected;
619 rShape = maZOrderedShapes[nIndex]->xShape;
621 #if OSL_DEBUG_LEVEL > 0 // test whether it is truly selected by a slower method
622 uno::Reference< drawing::XShape > xReturnShape;
623 bool bDebugResult(false);
624 uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
626 if (xShapes.is())
628 sal_Int32 nCount(xShapes->getCount());
629 if (nCount)
631 uno::Reference< drawing::XShape > xShape;
632 uno::Reference< drawing::XShape > xIndexShape = maZOrderedShapes[nIndex]->xShape;
633 sal_Int32 i(0);
634 while (!bDebugResult && (i < nCount))
636 xShapes->getByIndex(i) >>= xShape;
637 if (xShape.is() && (xIndexShape.get() == xShape.get()))
639 bDebugResult = true;
640 xReturnShape = xShape;
642 else
643 ++i;
647 OSL_ENSURE((bResult == bDebugResult) && ((bResult && (rShape.get() == xReturnShape.get())) || !bResult), "found the wrong shape or result");
648 #endif
650 return bResult;
653 bool ScChildrenShapes::SelectionChanged()
655 bool bResult(false);
656 if (!xSelectionSupplier.is())
657 throw uno::RuntimeException("Could not get selected shapes. Null reference to xSelectionSupplier in ScChildrenShapes::SelectionChanged.");
659 uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
661 bResult = FindSelectedShapesChanges(xShapes);
663 return bResult;
666 void ScChildrenShapes::Select(sal_Int32 nIndex)
668 if (maZOrderedShapes.size() <= 1)
669 GetCount(); // fill list with filtered shapes (no internal shapes)
671 if (!xSelectionSupplier.is())
672 throw uno::RuntimeException("Could not get selected shapes. Null reference to xSelectionSupplier in ScChildrenShapes::Select.");
674 if (mbShapesNeedSorting)
676 std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
677 mbShapesNeedSorting = false;
680 if (!maZOrderedShapes[nIndex])
681 return;
683 uno::Reference<drawing::XShape> xShape;
684 if (IsSelected(nIndex, xShape) || !maZOrderedShapes[nIndex]->bSelectable)
685 return;
687 uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
689 if (!xShapes.is())
690 xShapes = drawing::ShapeCollection::create(
691 comphelper::getProcessComponentContext());
693 xShapes->add(maZOrderedShapes[nIndex]->xShape);
697 xSelectionSupplier->select(uno::Any(xShapes));
698 maZOrderedShapes[nIndex]->bSelected = true;
699 if (maZOrderedShapes[nIndex]->pAccShape.is())
700 maZOrderedShapes[nIndex]->pAccShape->SetState(AccessibleStateType::SELECTED);
702 catch (lang::IllegalArgumentException&)
707 void ScChildrenShapes::DeselectAll()
709 if (!xSelectionSupplier.is())
710 throw uno::RuntimeException("Could not get selected shapes. Null reference to xSelectionSupplier in ScChildrenShapes::DeselectAll.");
712 bool bSomethingSelected(true);
715 xSelectionSupplier->select(uno::Any()); //deselects all
717 catch (lang::IllegalArgumentException&)
719 OSL_FAIL("nothing selected before");
720 bSomethingSelected = false;
723 if (bSomethingSelected)
724 for (ScAccessibleShapeData* pAccShapeData : maZOrderedShapes)
725 if (pAccShapeData)
727 pAccShapeData->bSelected = false;
728 if (pAccShapeData->pAccShape.is())
729 pAccShapeData->pAccShape->ResetState(AccessibleStateType::SELECTED);
734 void ScChildrenShapes::SelectAll()
736 if (!xSelectionSupplier.is())
737 throw uno::RuntimeException("Could not get selected shapes. Null reference to xSelectionSupplier in ScChildrenShapes::SelectAll.");
739 if (maZOrderedShapes.size() <= 1)
740 GetCount(); // fill list with filtered shapes (no internal shapes)
742 if (maZOrderedShapes.size() <= 1)
743 return;
745 uno::Reference<drawing::XShapes> xShapes = drawing::ShapeCollection::create(
746 comphelper::getProcessComponentContext());
750 for (ScAccessibleShapeData* pAccShapeData : maZOrderedShapes)
752 if (pAccShapeData && pAccShapeData->bSelectable)
754 pAccShapeData->bSelected = true;
755 if (pAccShapeData->pAccShape.is())
756 pAccShapeData->pAccShape->SetState(AccessibleStateType::SELECTED);
757 if (xShapes.is())
758 xShapes->add(pAccShapeData->xShape);
761 xSelectionSupplier->select(uno::Any(xShapes));
763 catch (lang::IllegalArgumentException&)
765 SelectionChanged(); // find all selected shapes and set the flags
769 void ScChildrenShapes::FillShapes(std::vector < uno::Reference < drawing::XShape > >& rShapes) const
771 uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
772 if (xShapes.is())
774 sal_uInt32 nCount(xShapes->getCount());
775 for (sal_uInt32 i = 0; i < nCount; ++i)
777 uno::Reference<drawing::XShape> xShape;
778 xShapes->getByIndex(i) >>= xShape;
779 if (xShape.is())
780 rShapes.push_back(xShape);
785 sal_Int32 ScChildrenShapes::GetSelectedCount() const
787 if (!xSelectionSupplier.is())
788 throw uno::RuntimeException("Could not get selected shapes. Null reference to xSelectionSupplier in ScChildrenShapes::GetSelectedCount.");
790 std::vector < uno::Reference < drawing::XShape > > aShapes;
791 FillShapes(aShapes);
793 return aShapes.size();
796 uno::Reference< XAccessible > ScChildrenShapes::GetSelected(sal_Int32 nSelectedChildIndex, bool bTabSelected) const
798 uno::Reference< XAccessible > xAccessible;
800 if (maZOrderedShapes.size() <= 1)
801 GetCount(); // fill list with shapes
803 if (!bTabSelected)
805 std::vector < uno::Reference < drawing::XShape > > aShapes;
806 FillShapes(aShapes);
808 if (nSelectedChildIndex < 0 || o3tl::make_unsigned(nSelectedChildIndex) >= aShapes.size())
809 return xAccessible;
811 SortedShapes::iterator aItr;
812 if (FindShape(aShapes[nSelectedChildIndex], aItr))
813 xAccessible = Get(*aItr);
815 else
817 if (mbShapesNeedSorting)
819 std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
820 mbShapesNeedSorting = false;
822 for(const auto& rpShape : maZOrderedShapes)
824 if (!rpShape || rpShape->bSelected)
826 if (nSelectedChildIndex == 0)
828 if (rpShape)
829 xAccessible = rpShape->pAccShape.get();
830 break;
832 else
833 --nSelectedChildIndex;
838 return xAccessible;
841 void ScChildrenShapes::Deselect(sal_Int32 nChildIndex)
843 uno::Reference<drawing::XShape> xShape;
844 if (!IsSelected(nChildIndex, xShape)) // returns false if it is the sheet
845 return;
847 if (!xShape.is())
848 return;
850 uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
851 if (xShapes.is())
852 xShapes->remove(xShape);
856 xSelectionSupplier->select(uno::Any(xShapes));
858 catch (lang::IllegalArgumentException&)
860 OSL_FAIL("something not selectable");
863 maZOrderedShapes[nChildIndex]->bSelected = false;
864 if (maZOrderedShapes[nChildIndex]->pAccShape.is())
865 maZOrderedShapes[nChildIndex]->pAccShape->ResetState(AccessibleStateType::SELECTED);
868 SdrPage* ScChildrenShapes::GetDrawPage() const
870 SCTAB nTab(mpAccessibleDocument->getVisibleTable());
871 SdrPage* pDrawPage = nullptr;
872 if (mpViewShell)
874 ScDocument& rDoc = mpViewShell->GetViewData().GetDocument();
875 if (ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer())
877 if (pDrawLayer->HasObjects() && (pDrawLayer->GetPageCount() > nTab))
878 pDrawPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(static_cast<sal_Int16>(nTab)));
881 return pDrawPage;
884 rtl::Reference<utl::AccessibleRelationSetHelper> ScChildrenShapes::GetRelationSet(const ScAddress* pAddress) const
886 rtl::Reference<utl::AccessibleRelationSetHelper> pRelationSet;
887 for (const ScAccessibleShapeData* pAccShapeData : maZOrderedShapes)
889 if (pAccShapeData &&
890 ((!pAccShapeData->xRelationCell && !pAddress) ||
891 (pAccShapeData->xRelationCell && pAddress && (*(pAccShapeData->xRelationCell) == *pAddress))))
893 if (!pRelationSet)
894 pRelationSet = new utl::AccessibleRelationSetHelper();
896 AccessibleRelation aRelation;
897 aRelation.TargetSet = { Get(pAccShapeData) };
898 aRelation.RelationType = AccessibleRelationType_CONTROLLER_FOR;
900 pRelationSet->AddRelation(aRelation);
903 return pRelationSet;
906 bool ScChildrenShapes::FindSelectedShapesChanges(const uno::Reference<drawing::XShapes>& xShapes) const
908 bool bResult(false);
909 SortedShapes aShapesList;
910 if (xShapes.is())
912 mnShapesSelected = xShapes->getCount();
913 for (sal_uInt32 i = 0; i < mnShapesSelected; ++i)
915 uno::Reference< drawing::XShape > xShape;
916 xShapes->getByIndex(i) >>= xShape;
917 if (xShape.is())
919 ScAccessibleShapeData* pShapeData = new ScAccessibleShapeData(xShape);
920 aShapesList.push_back(pShapeData);
924 else
925 mnShapesSelected = 0;
926 SdrObject *pFocusedObj = nullptr;
927 if( mnShapesSelected == 1 && aShapesList.size() == 1)
929 pFocusedObj = SdrObject::getSdrObjectFromXShape(aShapesList[0]->xShape);
931 std::sort(aShapesList.begin(), aShapesList.end(), ScShapeDataLess());
932 SortedShapes vecSelectedShapeAdd;
933 SortedShapes vecSelectedShapeRemove;
934 bool bHasSelect=false;
935 SortedShapes::iterator aXShapesItr(aShapesList.begin());
936 SortedShapes::const_iterator aXShapesEndItr(aShapesList.end());
937 SortedShapes::iterator aDataItr(maZOrderedShapes.begin());
938 SortedShapes::const_iterator aDataEndItr(maZOrderedShapes.end());
939 SortedShapes::const_iterator aFocusedItr = aDataEndItr;
940 while(aDataItr != aDataEndItr)
942 if (*aDataItr) // is it really a shape or only the sheet
944 sal_Int8 nComp(0);
945 if (aXShapesItr == aXShapesEndItr)
946 nComp = -1; // simulate that the Shape is lower, so the selection state will be removed
947 else
948 nComp = Compare(*aDataItr, *aXShapesItr);
949 if (nComp == 0)
951 if (!(*aDataItr)->bSelected)
953 (*aDataItr)->bSelected = true;
954 if ((*aDataItr)->pAccShape.is())
956 (*aDataItr)->pAccShape->SetState(AccessibleStateType::SELECTED);
957 (*aDataItr)->pAccShape->SetState(AccessibleStateType::FOCUSED);
958 bResult = true;
959 vecSelectedShapeAdd.push_back(*aDataItr);
961 aFocusedItr = aDataItr;
963 else
965 bHasSelect = true;
967 ++aDataItr;
968 ++aXShapesItr;
970 else if (nComp < 0)
972 if ((*aDataItr)->bSelected)
974 (*aDataItr)->bSelected = false;
975 if ((*aDataItr)->pAccShape.is())
977 (*aDataItr)->pAccShape->ResetState(AccessibleStateType::SELECTED);
978 (*aDataItr)->pAccShape->ResetState(AccessibleStateType::FOCUSED);
979 bResult = true;
980 vecSelectedShapeRemove.push_back(*aDataItr);
983 ++aDataItr;
985 else
987 OSL_FAIL("here is a selected shape which is not in the childlist");
988 ++aXShapesItr;
989 --mnShapesSelected;
992 else
993 ++aDataItr;
995 bool bWinFocus=false;
996 if (mpViewShell)
998 ScGridWindow* pWin = static_cast<ScGridWindow*>(mpViewShell->GetWindowByPos(meSplitPos));
999 if (pWin)
1001 bWinFocus = pWin->HasFocus();
1004 const SdrMarkList* pMarkList = nullptr;
1005 SdrObject* pMarkedObj = nullptr;
1006 bool bIsFocuseMarked = true;
1007 if( mpViewShell && mnShapesSelected == 1 && bWinFocus)
1009 ScDrawView* pScDrawView = mpViewShell->GetViewData().GetScDrawView();
1010 if( pScDrawView )
1012 pMarkList = &(pScDrawView->GetMarkedObjectList());
1013 if( pMarkList->GetMarkCount() == 1 )
1015 pMarkedObj = pMarkList->GetMark(0)->GetMarkedSdrObj();
1016 uno::Reference< drawing::XShape > xMarkedXShape (pMarkedObj->getUnoShape(), uno::UNO_QUERY);
1017 if( aFocusedItr != aDataEndItr &&
1018 (*aFocusedItr)->xShape.is() &&
1019 xMarkedXShape.is() &&
1020 (*aFocusedItr)->xShape != xMarkedXShape )
1021 bIsFocuseMarked = false;
1025 //if ((aFocusedItr != aDataEndItr) && (*aFocusedItr)->pAccShape.is() && (mnShapesSelected == 1))
1026 if ( bIsFocuseMarked && (aFocusedItr != aDataEndItr) && (*aFocusedItr)->pAccShape.is() && (mnShapesSelected == 1) && bWinFocus)
1028 (*aFocusedItr)->pAccShape->SetState(AccessibleStateType::FOCUSED);
1030 else if( pFocusedObj && bWinFocus && pMarkList && pMarkList->GetMarkCount() == 1 && mnShapesSelected == 1 )
1032 if( pMarkedObj )
1034 uno::Reference< drawing::XShape > xMarkedXShape (pMarkedObj->getUnoShape(), uno::UNO_QUERY);
1035 SdrObject* pUpObj = pMarkedObj->getParentSdrObjectFromSdrObject();
1037 if( pMarkedObj == pFocusedObj && pUpObj )
1039 uno::Reference< drawing::XShape > xUpGroupXShape (pUpObj->getUnoShape(), uno::UNO_QUERY);
1040 uno::Reference < XAccessible > xAccGroupShape =
1041 const_cast<ScChildrenShapes*>(this)->GetAccessibleCaption( xUpGroupXShape );
1042 if( xAccGroupShape.is() )
1044 ::accessibility::AccessibleShape* pAccGroupShape =
1045 static_cast< ::accessibility::AccessibleShape* >(xAccGroupShape.get());
1046 if( pAccGroupShape )
1048 sal_Int64 nCount = pAccGroupShape->getAccessibleChildCount();
1049 for( sal_Int64 i = 0; i < nCount; i++ )
1051 uno::Reference<XAccessible> xAccShape = pAccGroupShape->getAccessibleChild(i);
1052 if (xAccShape.is())
1054 ::accessibility::AccessibleShape* pChildAccShape = static_cast< ::accessibility::AccessibleShape* >(xAccShape.get());
1055 uno::Reference< drawing::XShape > xChildShape = pChildAccShape->GetXShape();
1056 if (xChildShape == xMarkedXShape)
1058 pChildAccShape->SetState(AccessibleStateType::FOCUSED);
1060 else
1062 pChildAccShape->ResetState(AccessibleStateType::FOCUSED);
1071 if (vecSelectedShapeAdd.size() >= 10 )
1073 AccessibleEventObject aEvent;
1074 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_WITHIN;
1075 aEvent.Source = uno::Reference< XAccessible >(mpAccessibleDocument);
1076 mpAccessibleDocument->CommitChange(aEvent);
1078 else
1080 for (const auto& rpShape : vecSelectedShapeAdd)
1082 AccessibleEventObject aEvent;
1083 if (bHasSelect)
1085 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_ADD;
1087 else
1089 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED;
1091 aEvent.Source = uno::Reference< XAccessible >(mpAccessibleDocument);
1092 uno::Reference< XAccessible > xChild( rpShape->pAccShape );
1093 aEvent.NewValue <<= xChild;
1094 mpAccessibleDocument->CommitChange(aEvent);
1097 for (const auto& rpShape : vecSelectedShapeRemove)
1099 AccessibleEventObject aEvent;
1100 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_REMOVE;
1101 aEvent.Source = uno::Reference< XAccessible >(mpAccessibleDocument);
1102 uno::Reference< XAccessible > xChild( rpShape->pAccShape );
1103 aEvent.NewValue <<= xChild;
1104 mpAccessibleDocument->CommitChange(aEvent);
1106 for(ScAccessibleShapeData*& pShapeData : aShapesList)
1108 delete pShapeData;
1109 pShapeData = nullptr;
1111 return bResult;
1114 std::optional<ScAddress> ScChildrenShapes::GetAnchor(const uno::Reference<drawing::XShape>& xShape) const
1116 if (mpViewShell)
1118 SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape(xShape);
1119 uno::Reference<beans::XPropertySet> xShapeProp(xShape, uno::UNO_QUERY);
1120 if (pSdrObj && xShapeProp.is())
1122 if (ScDrawObjData *pAnchor = ScDrawLayer::GetObjData(pSdrObj))
1123 return std::optional<ScAddress>(pAnchor->maStart);
1127 return std::optional<ScAddress>();
1130 rtl::Reference<utl::AccessibleRelationSetHelper> ScChildrenShapes::GetRelationSet(const ScAccessibleShapeData* pData) const
1132 rtl::Reference<utl::AccessibleRelationSetHelper> pRelationSet = new utl::AccessibleRelationSetHelper();
1134 if (pData && mpAccessibleDocument)
1136 uno::Reference<XAccessible> xAccessible = mpAccessibleDocument->GetAccessibleSpreadsheet(); // should be the current table
1137 if (pData->xRelationCell && xAccessible.is())
1139 sal_Int32 nRow = pData->xRelationCell->Row();
1140 sal_Int32 nColumn = pData->xRelationCell->Col();
1141 bool bPositionUnset = nRow == -1 && nColumn == -1;
1142 if (!bPositionUnset)
1144 uno::Reference<XAccessibleTable> xAccTable(xAccessible->getAccessibleContext(), uno::UNO_QUERY);
1145 if (xAccTable.is())
1146 xAccessible = xAccTable->getAccessibleCellAt(nRow, nColumn);
1149 AccessibleRelation aRelation;
1150 aRelation.TargetSet = { xAccessible };
1151 aRelation.RelationType = AccessibleRelationType_CONTROLLED_BY;
1152 pRelationSet->AddRelation(aRelation);
1155 return pRelationSet;
1158 void ScChildrenShapes::SetAnchor(const uno::Reference<drawing::XShape>& xShape, ScAccessibleShapeData* pData) const
1160 if (pData)
1162 std::optional<ScAddress> xAddress = GetAnchor(xShape);
1163 if ((xAddress && pData->xRelationCell && (*xAddress != *(pData->xRelationCell))) ||
1164 (!xAddress && pData->xRelationCell) || (xAddress && !pData->xRelationCell))
1166 pData->xRelationCell = std::move(xAddress);
1167 if (pData->pAccShape.is())
1168 pData->pAccShape->SetRelationSet(GetRelationSet(pData));
1173 void ScChildrenShapes::AddShape(const uno::Reference<drawing::XShape>& xShape, bool bCommitChange) const
1175 assert( maShapesMap.find(xShape) == maShapesMap.end());
1177 ScAccessibleShapeData* pShape = new ScAccessibleShapeData(xShape);
1178 maZOrderedShapes.push_back(pShape);
1179 mbShapesNeedSorting = true;
1180 maShapesMap[xShape] = pShape;
1181 SetAnchor(xShape, pShape);
1183 uno::Reference< beans::XPropertySet > xShapeProp(xShape, uno::UNO_QUERY);
1184 if (xShapeProp.is())
1186 uno::Any aPropAny = xShapeProp->getPropertyValue(u"LayerID"_ustr);
1187 sal_Int16 nLayerID = 0;
1188 if( aPropAny >>= nLayerID )
1190 if( (SdrLayerID(nLayerID) == SC_LAYER_INTERN) || (SdrLayerID(nLayerID) == SC_LAYER_HIDDEN) )
1191 pShape->bSelectable = false;
1192 else
1193 pShape->bSelectable = true;
1197 if (!xSelectionSupplier.is())
1198 throw uno::RuntimeException("Could not get selected shapes. Null reference to xSelectionSupplier in ScChildrenShapes::AddShape.");
1200 uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
1201 uno::Reference<container::XEnumerationAccess> xEnumAcc(xShapes, uno::UNO_QUERY);
1202 if (xEnumAcc.is())
1204 uno::Reference<container::XEnumeration> xEnum = xEnumAcc->createEnumeration();
1205 if (xEnum.is())
1207 uno::Reference<drawing::XShape> xSelectedShape;
1208 bool bFound(false);
1209 while (!bFound && xEnum->hasMoreElements())
1211 xEnum->nextElement() >>= xSelectedShape;
1212 if (xShape.is() && (xShape.get() == xSelectedShape.get()))
1214 pShape->bSelected = true;
1215 bFound = true;
1220 if (mpAccessibleDocument && bCommitChange)
1222 AccessibleEventObject aEvent;
1223 aEvent.EventId = AccessibleEventId::CHILD;
1224 aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument);
1225 aEvent.NewValue <<= Get(pShape);
1226 aEvent.IndexHint = -1;
1228 mpAccessibleDocument->CommitChange(aEvent); // new child - event
1232 void ScChildrenShapes::RemoveShape(const uno::Reference<drawing::XShape>& xShape) const
1234 if (mbShapesNeedSorting)
1236 std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
1237 mbShapesNeedSorting = false;
1239 SortedShapes::iterator aItr;
1240 if (FindShape(xShape, aItr))
1242 if (mpAccessibleDocument)
1244 uno::Reference<XAccessible> xOldAccessible (Get(*aItr));
1246 delete *aItr;
1247 maShapesMap.erase((*aItr)->xShape);
1248 maZOrderedShapes.erase(aItr);
1250 AccessibleEventObject aEvent;
1251 aEvent.EventId = AccessibleEventId::CHILD;
1252 aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument);
1253 aEvent.OldValue <<= xOldAccessible;
1254 aEvent.IndexHint = -1;
1256 mpAccessibleDocument->CommitChange(aEvent); // child is gone - event
1258 else
1260 delete *aItr;
1261 maShapesMap.erase((*aItr)->xShape);
1262 maZOrderedShapes.erase(aItr);
1265 else
1267 OSL_FAIL("shape was not in internal list");
1271 bool ScChildrenShapes::FindShape(const uno::Reference<drawing::XShape>& xShape, ScChildrenShapes::SortedShapes::iterator& rItr) const
1273 if (mbShapesNeedSorting)
1275 std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
1276 mbShapesNeedSorting = false;
1278 bool bResult(false);
1279 ScAccessibleShapeData aShape(xShape);
1280 rItr = std::lower_bound(maZOrderedShapes.begin(), maZOrderedShapes.end(), &aShape, ScShapeDataLess());
1281 if ((rItr != maZOrderedShapes.end()) && (*rItr != nullptr) && ((*rItr)->xShape.get() == xShape.get()))
1282 bResult = true; // if the shape is found
1284 #if OSL_DEBUG_LEVEL > 0 // test whether it finds truly the correct shape (perhaps it is not really sorted)
1285 SortedShapes::iterator aDebugItr = std::find_if(maZOrderedShapes.begin(), maZOrderedShapes.end(),
1286 [&xShape](const ScAccessibleShapeData* pShape) { return pShape && (pShape->xShape.get() == xShape.get()); });
1287 bool bResult2 = (aDebugItr != maZOrderedShapes.end());
1288 OSL_ENSURE((bResult == bResult2) && ((bResult && (rItr == aDebugItr)) || !bResult), "wrong Shape found");
1289 #endif
1290 return bResult;
1293 sal_Int8 ScChildrenShapes::Compare(const ScAccessibleShapeData* pData1,
1294 const ScAccessibleShapeData* pData2)
1296 ScShapeDataLess aLess;
1298 bool bResult1(aLess(pData1, pData2));
1299 bool bResult2(aLess(pData2, pData1));
1301 sal_Int8 nResult(0);
1302 if (!bResult1 && bResult2)
1303 nResult = 1;
1304 else if (bResult1 && !bResult2)
1305 nResult = -1;
1307 return nResult;
1310 void ScChildrenShapes::VisAreaChanged() const
1312 for (const ScAccessibleShapeData* pAccShapeData: maZOrderedShapes)
1313 if (pAccShapeData && pAccShapeData->pAccShape.is())
1314 pAccShapeData->pAccShape->ViewForwarderChanged();
1317 ScAccessibleDocument::ScAccessibleDocument(
1318 const uno::Reference<XAccessible>& rxParent,
1319 ScTabViewShell* pViewShell,
1320 ScSplitPos eSplitPos)
1321 : ScAccessibleDocumentBase(rxParent),
1322 mpViewShell(pViewShell),
1323 meSplitPos(eSplitPos),
1324 mbCompleteSheetSelected(false)
1326 maVisArea = GetVisibleArea_Impl();
1329 void ScAccessibleDocument::PreInit()
1331 if (!mpViewShell)
1332 return;
1334 mpViewShell->AddAccessibilityObject(*this);
1335 vcl::Window *pWin = mpViewShell->GetWindowByPos(meSplitPos);
1336 if( pWin )
1338 pWin->AddChildEventListener( LINK( this, ScAccessibleDocument, WindowChildEventListener ));
1339 sal_uInt16 nCount = pWin->GetChildCount();
1340 for( sal_uInt16 i=0; i < nCount; ++i )
1342 vcl::Window *pChildWin = pWin->GetChild( i );
1343 if( pChildWin &&
1344 AccessibleRole::EMBEDDED_OBJECT == pChildWin->GetAccessibleRole() )
1345 AddChild( pChildWin->GetAccessible(), false );
1348 ScViewData& rViewData = mpViewShell->GetViewData();
1349 if (rViewData.HasEditView(meSplitPos))
1351 uno::Reference<XAccessible> xAcc = new ScAccessibleEditObject(this, rViewData.GetEditView(meSplitPos),
1352 mpViewShell->GetWindowByPos(meSplitPos), GetCurrentCellName(), GetCurrentCellDescription(),
1353 ScAccessibleEditObject::CellInEditMode);
1354 AddChild(xAcc, false);
1358 void ScAccessibleDocument::Init()
1360 if(!mpChildrenShapes)
1361 mpChildrenShapes.reset( new ScChildrenShapes(this, mpViewShell, meSplitPos) );
1364 ScAccessibleDocument::~ScAccessibleDocument()
1366 if (!ScAccessibleContextBase::IsDefunc() && !rBHelper.bInDispose)
1368 // increment refcount to prevent double call off dtor
1369 osl_atomic_increment( &m_refCount );
1370 dispose();
1374 void SAL_CALL ScAccessibleDocument::disposing()
1376 SolarMutexGuard aGuard;
1377 FreeAccessibleSpreadsheet();
1378 if (mpViewShell)
1380 vcl::Window *pWin = mpViewShell->GetWindowByPos(meSplitPos);
1381 if( pWin )
1382 pWin->RemoveChildEventListener( LINK( this, ScAccessibleDocument, WindowChildEventListener ));
1384 mpViewShell->RemoveAccessibilityObject(*this);
1385 mpViewShell = nullptr;
1387 mpChildrenShapes.reset();
1389 ScAccessibleDocumentBase::disposing();
1392 void SAL_CALL ScAccessibleDocument::disposing( const lang::EventObject& /* Source */ )
1394 disposing();
1397 //===== SfxListener =====================================================
1399 IMPL_LINK( ScAccessibleDocument, WindowChildEventListener, VclWindowEvent&, rEvent, void )
1401 OSL_ENSURE( rEvent.GetWindow(), "Window???" );
1402 switch ( rEvent.GetId() )
1404 case VclEventId::WindowShow: // send create on show for direct accessible children
1406 vcl::Window* pChildWin = static_cast < vcl::Window * >( rEvent.GetData() );
1407 if( pChildWin && AccessibleRole::EMBEDDED_OBJECT == pChildWin->GetAccessibleRole() )
1409 AddChild( pChildWin->GetAccessible(), true );
1412 break;
1413 case VclEventId::WindowHide: // send destroy on hide for direct accessible children
1415 vcl::Window* pChildWin = static_cast < vcl::Window * >( rEvent.GetData() );
1416 if( pChildWin && AccessibleRole::EMBEDDED_OBJECT == pChildWin->GetAccessibleRole() )
1418 RemoveChild( pChildWin->GetAccessible(), true );
1421 break;
1422 default: break;
1426 void ScAccessibleDocument::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
1428 if (rHint.GetId() == SfxHintId::ScAccGridWinFocusLost )
1430 auto pFocusLostHint = static_cast<const ScAccGridWinFocusLostHint*>(&rHint);
1431 if (pFocusLostHint->GetOldGridWin() == meSplitPos)
1433 if (mxTempAcc.is() && mpTempAccEdit)
1434 mpTempAccEdit->LostFocus();
1435 else if (mpAccessibleSpreadsheet.is())
1436 mpAccessibleSpreadsheet->LostFocus();
1437 else
1438 CommitFocusLost();
1441 else if (rHint.GetId() == SfxHintId::ScAccGridWinFocusGot)
1443 auto pFocusGotHint = static_cast<const ScAccGridWinFocusGotHint*>(&rHint);
1444 if (pFocusGotHint->GetNewGridWin() == meSplitPos)
1446 uno::Reference<XAccessible> xAccessible;
1447 if (mpChildrenShapes)
1449 bool bTabMarked(IsTableSelected());
1450 xAccessible = mpChildrenShapes->GetSelected(0, bTabMarked);
1452 if( xAccessible.is() )
1454 uno::Any aNewValue;
1455 aNewValue<<=AccessibleStateType::FOCUSED;
1456 static_cast< ::accessibility::AccessibleShape* >(xAccessible.get())->
1457 CommitChange(AccessibleEventId::STATE_CHANGED,
1458 aNewValue,
1459 uno::Any(), -1 );
1461 else
1463 if (mxTempAcc.is() && mpTempAccEdit)
1464 mpTempAccEdit->GotFocus();
1465 else if (mpAccessibleSpreadsheet.is())
1466 mpAccessibleSpreadsheet->GotFocus();
1467 else
1468 CommitFocusGained();
1472 else if (rHint.GetId() == SfxHintId::ScAccTableChanged)
1474 // only notify if child exist, otherwise it is not necessary
1475 if (mpAccessibleSpreadsheet.is())
1477 FreeAccessibleSpreadsheet();
1479 // Shapes / form controls after reload not accessible, rebuild the
1480 // mpChildrenShapes variable.
1481 mpChildrenShapes.reset( new ScChildrenShapes( this, mpViewShell, meSplitPos ) );
1483 AccessibleEventObject aEvent;
1484 aEvent.EventId = AccessibleEventId::INVALIDATE_ALL_CHILDREN;
1485 aEvent.Source = uno::Reference< XAccessibleContext >(this);
1486 CommitChange(aEvent); // all children changed
1488 if (mpAccessibleSpreadsheet.is())
1489 mpAccessibleSpreadsheet->GotFocus();
1492 else if (rHint.GetId() == SfxHintId::ScAccMakeDrawLayer)
1494 if (mpChildrenShapes)
1495 mpChildrenShapes->SetDrawBroadcaster();
1497 else if (rHint.GetId() == SfxHintId::ScAccEnterEditMode) // this event comes only on creating edit field of a cell
1499 if (mpViewShell->GetViewData().GetEditActivePart() == meSplitPos)
1501 ScViewData& rViewData = mpViewShell->GetViewData();
1502 EditEngine const& rEditEng = rViewData.GetEditView(meSplitPos)->getEditEngine();
1503 if (rEditEng.IsUpdateLayout())
1505 mpTempAccEdit = new ScAccessibleEditObject(this, rViewData.GetEditView(meSplitPos),
1506 mpViewShell->GetWindowByPos(meSplitPos), GetCurrentCellName(),
1507 ScResId(STR_ACC_EDITLINE_DESCR), ScAccessibleEditObject::CellInEditMode);
1508 uno::Reference<XAccessible> xAcc = mpTempAccEdit;
1510 AddChild(xAcc, true);
1512 if (mpAccessibleSpreadsheet.is())
1513 mpAccessibleSpreadsheet->LostFocus();
1514 else
1515 CommitFocusLost();
1517 mpTempAccEdit->GotFocus();
1521 else if (rHint.GetId() == SfxHintId::ScAccLeaveEditMode)
1523 if (mxTempAcc.is())
1525 if (mpTempAccEdit)
1527 mpTempAccEdit->LostFocus();
1529 RemoveChild(mxTempAcc, true);
1530 if (mpTempAccEdit)
1532 // tdf#125982 a11y use-after-free of editengine by
1533 // ScAccessibleEditObjectTextData living past the
1534 // the editengine of the editview passed in above
1535 // in ScAccEnterEditMode
1536 mpTempAccEdit->dispose();
1537 mpTempAccEdit = nullptr;
1539 if (mpAccessibleSpreadsheet.is() && mpViewShell && mpViewShell->IsActive())
1540 mpAccessibleSpreadsheet->GotFocus();
1541 else if( mpViewShell && mpViewShell->IsActive())
1542 CommitFocusGained();
1545 else if ((rHint.GetId() == SfxHintId::ScAccVisAreaChanged) || (rHint.GetId() == SfxHintId::ScAccWindowResized))
1547 tools::Rectangle aOldVisArea(maVisArea);
1548 maVisArea = GetVisibleArea_Impl();
1550 if (maVisArea != aOldVisArea)
1552 if (maVisArea.GetSize() != aOldVisArea.GetSize())
1554 AccessibleEventObject aEvent;
1555 aEvent.EventId = AccessibleEventId::BOUNDRECT_CHANGED;
1556 aEvent.Source = uno::Reference< XAccessibleContext >(this);
1558 CommitChange(aEvent);
1560 if (mpAccessibleSpreadsheet.is())
1561 mpAccessibleSpreadsheet->BoundingBoxChanged();
1562 if (mpAccessibleSpreadsheet.is() && mpViewShell && mpViewShell->IsActive())
1563 mpAccessibleSpreadsheet->FireFirstCellFocus();
1565 else if (mpAccessibleSpreadsheet.is())
1567 mpAccessibleSpreadsheet->VisAreaChanged();
1569 if (mpChildrenShapes)
1570 mpChildrenShapes->VisAreaChanged();
1574 ScAccessibleDocumentBase::Notify(rBC, rHint);
1577 void SAL_CALL ScAccessibleDocument::selectionChanged( const lang::EventObject& /* aEvent */ )
1579 bool bSelectionChanged(false);
1580 if (mpAccessibleSpreadsheet.is())
1582 bool bOldSelected(mbCompleteSheetSelected);
1583 mbCompleteSheetSelected = IsTableSelected();
1584 if (bOldSelected != mbCompleteSheetSelected)
1586 mpAccessibleSpreadsheet->CompleteSelectionChanged(mbCompleteSheetSelected);
1587 bSelectionChanged = true;
1591 if (mpChildrenShapes && mpChildrenShapes->SelectionChanged())
1592 bSelectionChanged = true;
1594 if (bSelectionChanged)
1596 AccessibleEventObject aEvent;
1597 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED;
1598 aEvent.Source = uno::Reference< XAccessibleContext >(this);
1600 CommitChange(aEvent);
1604 //===== XInterface =====================================================
1606 uno::Any SAL_CALL ScAccessibleDocument::queryInterface( uno::Type const & rType )
1608 uno::Any aAny (ScAccessibleDocumentImpl::queryInterface(rType));
1609 return aAny.hasValue() ? aAny : ScAccessibleContextBase::queryInterface(rType);
1612 void SAL_CALL ScAccessibleDocument::acquire()
1613 noexcept
1615 ScAccessibleContextBase::acquire();
1618 void SAL_CALL ScAccessibleDocument::release()
1619 noexcept
1621 ScAccessibleContextBase::release();
1624 //===== XAccessibleComponent ============================================
1626 uno::Reference< XAccessible > SAL_CALL ScAccessibleDocument::getAccessibleAtPoint(
1627 const awt::Point& rPoint )
1629 uno::Reference<XAccessible> xAccessible;
1630 if (containsPoint(rPoint))
1632 SolarMutexGuard aGuard;
1633 IsObjectValid();
1634 if (mpChildrenShapes)
1635 xAccessible = mpChildrenShapes->GetAt(rPoint);
1636 if(!xAccessible.is())
1638 if (mxTempAcc.is())
1640 uno::Reference< XAccessibleContext > xCont(mxTempAcc->getAccessibleContext());
1641 uno::Reference< XAccessibleComponent > xComp(xCont, uno::UNO_QUERY);
1642 if (xComp.is())
1644 tools::Rectangle aBound(vcl::unohelper::ConvertToVCLRect(xComp->getBounds()));
1645 if (aBound.Contains(vcl::unohelper::ConvertToVCLPoint(rPoint)))
1646 xAccessible = mxTempAcc;
1649 if (!xAccessible.is())
1650 xAccessible = GetAccessibleSpreadsheet();
1653 return xAccessible;
1656 void SAL_CALL ScAccessibleDocument::grabFocus( )
1658 SolarMutexGuard aGuard;
1659 IsObjectValid();
1660 if (!getAccessibleParent().is())
1661 return;
1663 uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY);
1664 if (xAccessibleComponent.is())
1666 xAccessibleComponent->grabFocus();
1667 // grab only focus if it does not have the focus and it is not hidden
1668 if (mpViewShell &&
1669 (mpViewShell->GetViewData().GetActivePart() != meSplitPos) &&
1670 mpViewShell->GetWindowByPos(meSplitPos)->IsVisible())
1672 mpViewShell->ActivatePart(meSplitPos);
1677 //===== XAccessibleContext ==============================================
1679 /// Return the number of currently visible children.
1680 sal_Int64 SAL_CALL
1681 ScAccessibleDocument::getAccessibleChildCount()
1683 SolarMutexGuard aGuard;
1684 IsObjectValid();
1685 sal_Int64 nCount(1);
1686 if (mpChildrenShapes)
1687 nCount = mpChildrenShapes->GetCount(); // returns the count of the shapes inclusive the table
1689 if (mxTempAcc.is())
1690 ++nCount;
1692 return nCount;
1695 /// Return the specified child or NULL if index is invalid.
1696 uno::Reference<XAccessible> SAL_CALL
1697 ScAccessibleDocument::getAccessibleChild(sal_Int64 nIndex)
1699 SolarMutexGuard aGuard;
1700 IsObjectValid();
1701 uno::Reference<XAccessible> xAccessible;
1702 if (nIndex >= 0)
1704 sal_Int64 nCount(1);
1705 if (mpChildrenShapes)
1707 xAccessible = mpChildrenShapes->Get(nIndex); // returns NULL if it is the table or out of range
1708 nCount = mpChildrenShapes->GetCount(); //there is always a table
1710 if (!xAccessible.is())
1712 if (nIndex < nCount)
1713 xAccessible = GetAccessibleSpreadsheet();
1714 else if (nIndex == nCount && mxTempAcc.is())
1715 xAccessible = mxTempAcc;
1719 if (!xAccessible.is())
1720 throw lang::IndexOutOfBoundsException();
1722 return xAccessible;
1725 /// Return the set of current states.
1726 sal_Int64 SAL_CALL
1727 ScAccessibleDocument::getAccessibleStateSet()
1729 SolarMutexGuard aGuard;
1730 sal_Int64 nParentStates = 0;
1731 if (getAccessibleParent().is())
1733 uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext();
1734 nParentStates = xParentContext->getAccessibleStateSet();
1736 sal_Int64 nStateSet = 0;
1737 if (IsDefunc(nParentStates))
1738 nStateSet |= AccessibleStateType::DEFUNC;
1739 else
1741 nStateSet |= AccessibleStateType::EDITABLE;
1742 nStateSet |= AccessibleStateType::ENABLED;
1743 nStateSet |= AccessibleStateType::OPAQUE;
1744 if (isShowing())
1745 nStateSet |= AccessibleStateType::SHOWING;
1746 if (isVisible())
1747 nStateSet |= AccessibleStateType::VISIBLE;
1749 return nStateSet;
1752 OUString SAL_CALL
1753 ScAccessibleDocument::getAccessibleName()
1755 SolarMutexGuard g;
1757 OUString aName = ScResId(STR_ACC_DOC_SPREADSHEET);
1758 ScDocument* pScDoc = GetDocument();
1759 if (!pScDoc)
1760 return aName;
1762 ScDocShell* pObjSh = pScDoc->GetDocumentShell();
1763 if (!pObjSh)
1764 return aName;
1766 OUString aFileName;
1767 SfxMedium* pMed = pObjSh->GetMedium();
1768 if (pMed)
1769 aFileName = pMed->GetName();
1771 if (aFileName.isEmpty())
1772 aFileName = pObjSh->GetTitle(SFX_TITLE_APINAME);
1774 if (!aFileName.isEmpty())
1776 OUString aReadOnly;
1777 if (pObjSh->IsReadOnly())
1778 aReadOnly = ScResId(STR_ACC_DOC_SPREADSHEET_READONLY);
1780 aName = aFileName + aReadOnly + " - " + aName;
1782 return aName;
1785 ///===== XAccessibleSelection ===========================================
1787 void SAL_CALL
1788 ScAccessibleDocument::selectAccessibleChild( sal_Int64 nChildIndex )
1790 SolarMutexGuard aGuard;
1791 IsObjectValid();
1793 if (!(mpChildrenShapes && mpViewShell))
1794 return;
1796 sal_Int32 nCount(mpChildrenShapes->GetCount()); // all shapes and the table
1797 if (mxTempAcc.is())
1798 ++nCount;
1799 if (nChildIndex < 0 || nChildIndex >= nCount)
1800 throw lang::IndexOutOfBoundsException();
1802 uno::Reference < XAccessible > xAccessible = mpChildrenShapes->Get(nChildIndex);
1803 if (xAccessible.is())
1805 bool bWasTableSelected(IsTableSelected());
1806 mpChildrenShapes->Select(nChildIndex); // throws no lang::IndexOutOfBoundsException if Index is too high
1807 if (bWasTableSelected)
1808 mpViewShell->SelectAll();
1810 else
1812 mpViewShell->SelectAll();
1816 sal_Bool SAL_CALL
1817 ScAccessibleDocument::isAccessibleChildSelected( sal_Int64 nChildIndex )
1819 SolarMutexGuard aGuard;
1820 IsObjectValid();
1821 bool bResult(false);
1823 if (mpChildrenShapes)
1825 sal_Int32 nCount(mpChildrenShapes->GetCount()); // all shapes and the table
1826 if (mxTempAcc.is())
1827 ++nCount;
1828 if (nChildIndex < 0 || nChildIndex >= nCount)
1829 throw lang::IndexOutOfBoundsException();
1831 uno::Reference < XAccessible > xAccessible = mpChildrenShapes->Get(nChildIndex);
1832 if (xAccessible.is())
1834 uno::Reference<drawing::XShape> xShape;
1835 bResult = mpChildrenShapes->IsSelected(nChildIndex, xShape); // throws no lang::IndexOutOfBoundsException if Index is too high
1837 else
1839 if (mxTempAcc.is() && nChildIndex == nCount)
1840 bResult = true;
1841 else
1842 bResult = IsTableSelected();
1845 return bResult;
1848 void SAL_CALL
1849 ScAccessibleDocument::clearAccessibleSelection( )
1851 SolarMutexGuard aGuard;
1852 IsObjectValid();
1854 if (mpChildrenShapes)
1855 mpChildrenShapes->DeselectAll(); //deselects all (also the table)
1858 void SAL_CALL
1859 ScAccessibleDocument::selectAllAccessibleChildren( )
1861 SolarMutexGuard aGuard;
1862 IsObjectValid();
1864 if (mpChildrenShapes)
1865 mpChildrenShapes->SelectAll();
1867 // select table after shapes, because while selecting shapes the table will be deselected
1868 if (mpViewShell)
1870 mpViewShell->SelectAll();
1874 sal_Int64 SAL_CALL
1875 ScAccessibleDocument::getSelectedAccessibleChildCount( )
1877 SolarMutexGuard aGuard;
1878 IsObjectValid();
1879 sal_Int64 nCount(0);
1881 if (mpChildrenShapes)
1882 nCount = mpChildrenShapes->GetSelectedCount();
1884 if (IsTableSelected())
1885 ++nCount;
1887 if (mxTempAcc.is())
1888 ++nCount;
1890 return nCount;
1893 uno::Reference<XAccessible > SAL_CALL
1894 ScAccessibleDocument::getSelectedAccessibleChild( sal_Int64 nSelectedChildIndex )
1896 SolarMutexGuard aGuard;
1897 IsObjectValid();
1898 uno::Reference<XAccessible> xAccessible;
1899 if (mpChildrenShapes)
1901 sal_Int64 nCount(getSelectedAccessibleChildCount()); //all shapes and the table
1902 if (nSelectedChildIndex < 0 || nSelectedChildIndex >= nCount)
1903 throw lang::IndexOutOfBoundsException();
1905 bool bTabMarked(IsTableSelected());
1907 if (mpChildrenShapes)
1908 xAccessible = mpChildrenShapes->GetSelected(nSelectedChildIndex, bTabMarked); // throws no lang::IndexOutOfBoundsException if Index is too high
1909 if (mxTempAcc.is() && nSelectedChildIndex == nCount - 1)
1910 xAccessible = mxTempAcc;
1911 else if (bTabMarked)
1912 xAccessible = GetAccessibleSpreadsheet();
1915 OSL_ENSURE(xAccessible.is(), "here should always be an accessible object or an exception thrown");
1917 return xAccessible;
1920 void SAL_CALL
1921 ScAccessibleDocument::deselectAccessibleChild( sal_Int64 nChildIndex )
1923 SolarMutexGuard aGuard;
1924 IsObjectValid();
1926 if (!(mpChildrenShapes && mpViewShell))
1927 return;
1929 sal_Int32 nCount(mpChildrenShapes->GetCount()); // all shapes and the table
1930 if (mxTempAcc.is())
1931 ++nCount;
1932 if (nChildIndex < 0 || nChildIndex >= nCount)
1933 throw lang::IndexOutOfBoundsException();
1935 bool bTabMarked(IsTableSelected());
1937 uno::Reference < XAccessible > xAccessible = mpChildrenShapes->Get(nChildIndex);
1938 if (xAccessible.is())
1940 mpChildrenShapes->Deselect(nChildIndex); // throws no lang::IndexOutOfBoundsException if Index is too high
1941 if (bTabMarked)
1942 mpViewShell->SelectAll(); // select the table again
1944 else if (bTabMarked)
1945 mpViewShell->Unmark();
1948 //===== XServiceInfo ====================================================
1950 OUString SAL_CALL
1951 ScAccessibleDocument::getImplementationName()
1953 return u"ScAccessibleDocument"_ustr;
1956 uno::Sequence< OUString> SAL_CALL
1957 ScAccessibleDocument::getSupportedServiceNames()
1959 const css::uno::Sequence<OUString> vals { u"com.sun.star.AccessibleSpreadsheetDocumentView"_ustr };
1960 return comphelper::concatSequences(ScAccessibleContextBase::getSupportedServiceNames(), vals);
1963 //===== XTypeProvider =======================================================
1965 uno::Sequence< uno::Type > SAL_CALL ScAccessibleDocument::getTypes()
1967 return comphelper::concatSequences(ScAccessibleDocumentImpl::getTypes(), ScAccessibleContextBase::getTypes());
1970 uno::Sequence<sal_Int8> SAL_CALL
1971 ScAccessibleDocument::getImplementationId()
1973 return css::uno::Sequence<sal_Int8>();
1976 ///===== IAccessibleViewForwarder ========================================
1978 tools::Rectangle ScAccessibleDocument::GetVisibleArea_Impl() const
1980 tools::Rectangle aVisRect(GetBoundingBox());
1982 if (mpViewShell)
1984 Point aPoint(mpViewShell->GetViewData().GetPixPos(meSplitPos)); // returns a negative Point
1985 aPoint.setX(-aPoint.getX());
1986 aPoint.setY(-aPoint.getY());
1987 aVisRect.SetPos(aPoint);
1989 ScGridWindow* pWin = static_cast<ScGridWindow*>(mpViewShell->GetWindowByPos(meSplitPos));
1990 if (pWin)
1991 aVisRect = pWin->PixelToLogic(aVisRect, pWin->GetDrawMapMode());
1994 return aVisRect;
1997 tools::Rectangle ScAccessibleDocument::GetVisibleArea() const
1999 SolarMutexGuard aGuard;
2000 IsObjectValid();
2001 return maVisArea;
2004 Point ScAccessibleDocument::LogicToPixel (const Point& rPoint) const
2006 SolarMutexGuard aGuard;
2007 IsObjectValid();
2008 Point aPoint;
2009 ScGridWindow* pWin = static_cast<ScGridWindow*>(mpViewShell->GetWindowByPos(meSplitPos));
2010 if (pWin)
2012 aPoint = pWin->LogicToPixel(rPoint, pWin->GetDrawMapMode());
2013 aPoint += Point(pWin->GetWindowExtentsAbsolute().TopLeft());
2015 return aPoint;
2018 Size ScAccessibleDocument::LogicToPixel (const Size& rSize) const
2020 SolarMutexGuard aGuard;
2021 IsObjectValid();
2022 Size aSize;
2023 ScGridWindow* pWin = static_cast<ScGridWindow*>(mpViewShell->GetWindowByPos(meSplitPos));
2024 if (pWin)
2025 aSize = pWin->LogicToPixel(rSize, pWin->GetDrawMapMode());
2026 return aSize;
2029 //===== internal ========================================================
2031 rtl::Reference<utl::AccessibleRelationSetHelper> ScAccessibleDocument::GetRelationSet(const ScAddress* pAddress) const
2033 rtl::Reference<utl::AccessibleRelationSetHelper> pRelationSet;
2034 if (mpChildrenShapes)
2035 pRelationSet = mpChildrenShapes->GetRelationSet(pAddress);
2036 return pRelationSet;
2039 OUString
2040 ScAccessibleDocument::createAccessibleDescription()
2042 return STR_ACC_DOC_DESCR;
2045 OUString
2046 ScAccessibleDocument::createAccessibleName()
2048 SolarMutexGuard aGuard;
2049 IsObjectValid();
2050 OUString sName = ScResId(STR_ACC_DOC_NAME);
2051 sal_Int32 nNumber(sal_Int32(meSplitPos) + 1);
2052 sName += OUString::number(nNumber);
2053 return sName;
2056 AbsoluteScreenPixelRectangle ScAccessibleDocument::GetBoundingBoxOnScreen() const
2058 AbsoluteScreenPixelRectangle aRect;
2059 if (mpViewShell)
2061 vcl::Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos);
2062 if (pWindow)
2063 aRect = pWindow->GetWindowExtentsAbsolute();
2065 return aRect;
2068 tools::Rectangle ScAccessibleDocument::GetBoundingBox() const
2070 tools::Rectangle aRect;
2071 if (mpViewShell)
2073 vcl::Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos);
2074 if (pWindow)
2075 aRect = pWindow->GetWindowExtentsRelative(*pWindow->GetAccessibleParentWindow());
2077 return aRect;
2080 SCTAB ScAccessibleDocument::getVisibleTable() const
2082 SCTAB nVisibleTable(0);
2083 if (mpViewShell)
2084 nVisibleTable = mpViewShell->GetViewData().GetTabNo();
2085 return nVisibleTable;
2088 uno::Reference < XAccessible >
2089 ScAccessibleDocument::GetAccessibleSpreadsheet()
2091 if (!mpAccessibleSpreadsheet.is() && mpViewShell)
2093 mpAccessibleSpreadsheet = new ScAccessibleSpreadsheet(this, mpViewShell, getVisibleTable(), meSplitPos);
2094 mpAccessibleSpreadsheet->Init();
2095 mbCompleteSheetSelected = IsTableSelected();
2097 return mpAccessibleSpreadsheet;
2100 void ScAccessibleDocument::FreeAccessibleSpreadsheet()
2102 if (mpAccessibleSpreadsheet.is())
2104 mpAccessibleSpreadsheet->dispose();
2105 mpAccessibleSpreadsheet.clear();
2109 bool ScAccessibleDocument::IsTableSelected() const
2111 bool bResult (false);
2112 if(mpViewShell)
2114 SCTAB nTab(getVisibleTable());
2115 //#103800#; use a copy of MarkData
2116 ScMarkData aMarkData(mpViewShell->GetViewData().GetMarkData());
2117 ScDocument* pDoc = GetDocument();
2118 if (aMarkData.IsAllMarked( ScRange( 0, 0, nTab, pDoc->MaxCol(), pDoc->MaxRow(), nTab)))
2119 bResult = true;
2121 return bResult;
2124 bool ScAccessibleDocument::IsDefunc(sal_Int64 nParentStates)
2126 return ScAccessibleContextBase::IsDefunc() || (mpViewShell == nullptr) || !getAccessibleParent().is() ||
2127 (nParentStates & AccessibleStateType::DEFUNC);
2130 void ScAccessibleDocument::AddChild(const uno::Reference<XAccessible>& xAcc, bool bFireEvent)
2132 OSL_ENSURE(!mxTempAcc.is(), "this object should be removed before");
2133 if (xAcc.is())
2135 mxTempAcc = xAcc;
2136 if( bFireEvent )
2138 AccessibleEventObject aEvent;
2139 aEvent.Source = uno::Reference<XAccessibleContext>(this);
2140 aEvent.EventId = AccessibleEventId::CHILD;
2141 aEvent.NewValue <<= mxTempAcc;
2142 aEvent.IndexHint = getAccessibleChildCount() - 1;
2143 CommitChange( aEvent );
2148 void ScAccessibleDocument::RemoveChild(const uno::Reference<XAccessible>& xAcc, bool bFireEvent)
2150 OSL_ENSURE(mxTempAcc.is(), "this object should be added before");
2151 if (!xAcc.is())
2152 return;
2154 OSL_ENSURE(xAcc.get() == mxTempAcc.get(), "only the same object should be removed");
2155 if( bFireEvent )
2157 AccessibleEventObject aEvent;
2158 aEvent.Source = uno::Reference<XAccessibleContext>(this);
2159 aEvent.EventId = AccessibleEventId::CHILD;
2160 aEvent.OldValue <<= mxTempAcc;
2161 aEvent.IndexHint = -1;
2162 CommitChange( aEvent );
2164 mxTempAcc = nullptr;
2167 OUString ScAccessibleDocument::GetCurrentCellName() const
2169 OUString sName(ScResId(STR_ACC_CELL_NAME));
2170 if (mpViewShell)
2172 // Document not needed, because only the cell address, but not the tablename is needed
2173 OUString sAddress(mpViewShell->GetViewData().GetCurPos().Format(ScRefFlags::VALID));
2174 sName = sName.replaceFirst("%1", sAddress);
2176 return sName;
2179 const OUString & ScAccessibleDocument::GetCurrentCellDescription()
2181 return EMPTY_OUSTRING;
2184 ScDocument *ScAccessibleDocument::GetDocument() const
2186 return mpViewShell ? &mpViewShell->GetViewData().GetDocument() : nullptr;
2189 ScAddress ScAccessibleDocument::GetCurCellAddress() const
2191 return mpViewShell ? mpViewShell->GetViewData().GetCurPos() : ScAddress();
2194 uno::Any SAL_CALL ScAccessibleDocument::getExtendedAttributes()
2196 SolarMutexGuard g;
2198 uno::Any anyAttribute;
2200 sal_uInt16 sheetIndex;
2201 OUString sSheetName;
2202 sheetIndex = getVisibleTable();
2203 if(GetDocument()==nullptr)
2204 return anyAttribute;
2205 GetDocument()->GetName(sheetIndex,sSheetName);
2206 OUString sValue = "page-name:" + sSheetName +
2207 ";page-number:" + OUString::number(sheetIndex+1) +
2208 ";total-pages:" + OUString::number(GetDocument()->GetTableCount()) + ";";
2209 anyAttribute <<= sValue;
2210 return anyAttribute;
2213 sal_Int32 SAL_CALL ScAccessibleDocument::getForeground( )
2215 return sal_Int32(COL_BLACK);
2218 sal_Int32 SAL_CALL ScAccessibleDocument::getBackground( )
2220 SolarMutexGuard aGuard;
2221 IsObjectValid();
2222 return sal_Int32(ScModule::get()->GetColorConfig().GetColorValue(::svtools::DOCCOLOR).nColor);
2225 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */