1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
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>
35 
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 
46 #include <unotools/accessiblestatesethelper.hxx>
47 #include <tools/gen.hxx>
48 #include <svx/svdpage.hxx>
49 #include <svx/svdobj.hxx>
50 #include <svx/ShapeTypeHandler.hxx>
51 #include <svx/AccessibleShape.hxx>
52 #include <svx/AccessibleShapeTreeInfo.hxx>
53 #include <svx/AccessibleShapeInfo.hxx>
54 #include <svx/IAccessibleParent.hxx>
55 #include <comphelper/sequence.hxx>
56 #include <sfx2/viewfrm.hxx>
57 #include <sfx2/docfile.hxx>
58 #include <svx/unoshape.hxx>
59 #include <unotools/accessiblerelationsethelper.hxx>
60 #include <toolkit/helper/convert.hxx>
61 #include <vcl/svapp.hxx>
62 
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>
69 
70 #include <algorithm>
71 
72 #include <svx/unoapi.hxx>
73 #include <scmod.hxx>
74 
75 #ifdef indices
76 #undef indices
77 #endif
78 
79 #ifdef extents
80 #undef extents
81 #endif
82 
83 using namespace ::com::sun::star;
84 using namespace ::com::sun::star::accessibility;
85 
86     //=====  internal  ========================================================
87 
88 struct ScAccessibleShapeData
89 {
90     ScAccessibleShapeData() : bSelected(false), bSelectable(true) {}
91     ~ScAccessibleShapeData();
92     mutable rtl::Reference< ::accessibility::AccessibleShape > pAccShape;
93     mutable boost::optional<ScAddress> xRelationCell; // if it is NULL this shape is anchored on the table
94     css::uno::Reference< css::drawing::XShape > xShape;
95     mutable bool            bSelected;
96     bool                    bSelectable;
97 };
98 
99 ScAccessibleShapeData::~ScAccessibleShapeData()
100 {
101     if (pAccShape.is())
102     {
103         pAccShape->dispose();
104     }
105 }
106 
107 struct ScShapeDataLess
108 {
109     static constexpr OUStringLiteral gsLayerId = "LayerID";
110     static constexpr OUStringLiteral gsZOrder = "ZOrder";
111 
112     static void ConvertLayerId(sal_Int16& rLayerID) // changes the number of the LayerId so it the accessibility order
113     {
114         // note: MSVC 2017 ICE's if this is written as "switch" so use "if"
115         if (sal_uInt8(SC_LAYER_FRONT) == rLayerID)
116         {
117             rLayerID = 1;
118         }
119         else if (sal_uInt8(SC_LAYER_BACK) == rLayerID)
120         {
121             rLayerID = 0;
122         }
123         else if (sal_uInt8(SC_LAYER_INTERN) == rLayerID)
124         {
125             rLayerID = 2;
126         }
127         else if (sal_uInt8(SC_LAYER_CONTROLS) == rLayerID)
128         {
129             rLayerID = 3;
130         }
131     }
132     static bool LessThanSheet(const ScAccessibleShapeData* pData)
133     {
134         bool bResult(false);
135         uno::Reference< beans::XPropertySet> xProps(pData->xShape, uno::UNO_QUERY);
136         if (xProps.is())
137         {
138             uno::Any aPropAny = xProps->getPropertyValue(gsLayerId);
139             sal_Int16 nLayerID = 0;
140             if( aPropAny >>= nLayerID )
141             {
142                 if (SdrLayerID(nLayerID) == SC_LAYER_BACK)
143                     bResult = true;
144             }
145         }
146         return bResult;
147     }
148     bool operator()(const ScAccessibleShapeData* pData1, const ScAccessibleShapeData* pData2) const
149     {
150         bool bResult(false);
151         if (pData1 && pData2)
152         {
153             uno::Reference< beans::XPropertySet> xProps1(pData1->xShape, uno::UNO_QUERY);
154             uno::Reference< beans::XPropertySet> xProps2(pData2->xShape, uno::UNO_QUERY);
155             if (xProps1.is() && xProps2.is())
156             {
157                 uno::Any aPropAny1 = xProps1->getPropertyValue(gsLayerId);
158                 uno::Any aPropAny2 = xProps2->getPropertyValue(gsLayerId);
159                 sal_Int16 nLayerID1(0);
160                 sal_Int16 nLayerID2(0);
161                 if( (aPropAny1 >>= nLayerID1) && (aPropAny2 >>= nLayerID2) )
162                 {
163                     if (nLayerID1 == nLayerID2)
164                     {
165                         uno::Any aAny1 = xProps1->getPropertyValue(gsZOrder);
166                         sal_Int32 nZOrder1 = 0;
167                         uno::Any aAny2 = xProps2->getPropertyValue(gsZOrder);
168                         sal_Int32 nZOrder2 = 0;
169                         if ( (aAny1 >>= nZOrder1) && (aAny2 >>= nZOrder2) )
170                             bResult = (nZOrder1 < nZOrder2);
171                     }
172                     else
173                     {
174                         ConvertLayerId(nLayerID1);
175                         ConvertLayerId(nLayerID2);
176                         bResult = (nLayerID1 < nLayerID2);
177                     }
178                 }
179             }
180         }
181         else if (pData1 && !pData2)
182             bResult = LessThanSheet(pData1);
183         else if (!pData1 && pData2)
184             bResult = !LessThanSheet(pData2);
185         else
186             bResult = false;
187         return bResult;
188     }
189 };
190 
191 class ScChildrenShapes : public SfxListener,
192     public ::accessibility::IAccessibleParent
193 {
194 public:
195     ScChildrenShapes(ScAccessibleDocument* pAccessibleDocument, ScTabViewShell* pViewShell, ScSplitPos eSplitPos);
196     virtual ~ScChildrenShapes() override;
197 
198     ///=====  SfxListener  =====================================================
199 
200     virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
201 
202     ///=====  IAccessibleParent  ===============================================
203 
204     virtual bool ReplaceChild (
205         ::accessibility::AccessibleShape* pCurrentChild,
206         const css::uno::Reference< css::drawing::XShape >& _rxShape,
207         const long _nIndex,
208         const ::accessibility::AccessibleShapeTreeInfo& _rShapeTreeInfo
209     ) override;
210 
211     virtual ::accessibility::AccessibleControlShape* GetAccControlShapeFromModel
212         (css::beans::XPropertySet* pSet) override;
213     virtual css::uno::Reference< css::accessibility::XAccessible>
214         GetAccessibleCaption (const css::uno::Reference<css::drawing::XShape>& xShape) override;
215     ///=====  Internal  ========================================================
216     void SetDrawBroadcaster();
217 
218     sal_Int32 GetCount() const;
219     uno::Reference< XAccessible > Get(const ScAccessibleShapeData* pData) const;
220     uno::Reference< XAccessible > Get(sal_Int32 nIndex) const;
221     uno::Reference< XAccessible > GetAt(const awt::Point& rPoint) const;
222 
223     // gets the index of the shape starting on 0 (without the index of the table)
224     // returns the selected shape
225     bool IsSelected(sal_Int32 nIndex,
226         css::uno::Reference<css::drawing::XShape>& rShape) const;
227 
228     bool SelectionChanged();
229 
230     void Select(sal_Int32 nIndex);
231     void DeselectAll(); // deselect also the table
232     void SelectAll();
233     sal_Int32 GetSelectedCount() const;
234     uno::Reference< XAccessible > GetSelected(sal_Int32 nSelectedChildIndex, bool bTabSelected) const;
235     void Deselect(sal_Int32 nChildIndex);
236 
237     SdrPage* GetDrawPage() const;
238 
239     utl::AccessibleRelationSetHelper* GetRelationSet(const ScAddress* pAddress) const;
240 
241     void VisAreaChanged() const;
242 private:
243     typedef std::vector<ScAccessibleShapeData*> SortedShapes;
244     typedef std::unordered_map<css::uno::Reference< css::drawing::XShape >, ScAccessibleShapeData*> ShapesMap;
245 
246     mutable SortedShapes maZOrderedShapes; // a null pointer represents the sheet in the correct order
247     mutable ShapesMap maShapesMap;
248     mutable bool mbShapesNeedSorting; // set if maZOrderedShapes needs sorting
249 
250     mutable ::accessibility::AccessibleShapeTreeInfo maShapeTreeInfo;
251     mutable css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier;
252     mutable size_t mnSdrObjCount;
253     mutable sal_uInt32 mnShapesSelected;
254     ScTabViewShell* mpViewShell;
255     ScAccessibleDocument* mpAccessibleDocument;
256     ScSplitPos const meSplitPos;
257 
258     void FillShapes(std::vector < uno::Reference < drawing::XShape > >& rShapes) const;
259     bool FindSelectedShapesChanges(const css::uno::Reference<css::drawing::XShapes>& xShapes) const;
260 
261     boost::optional<ScAddress> GetAnchor(const uno::Reference<drawing::XShape>& xShape) const;
262     uno::Reference<XAccessibleRelationSet> GetRelationSet(const ScAccessibleShapeData* pData) const;
263     void SetAnchor(const uno::Reference<drawing::XShape>& xShape, ScAccessibleShapeData* pData) const;
264     void AddShape(const uno::Reference<drawing::XShape>& xShape, bool bCommitChange) const;
265     void RemoveShape(const uno::Reference<drawing::XShape>& xShape) const;
266 
267     bool FindShape(const uno::Reference<drawing::XShape>& xShape, SortedShapes::iterator& rItr) const;
268 
269     static sal_Int8 Compare(const ScAccessibleShapeData* pData1,
270         const ScAccessibleShapeData* pData2);
271 };
272 
273 ScChildrenShapes::ScChildrenShapes(ScAccessibleDocument* pAccessibleDocument, ScTabViewShell* pViewShell, ScSplitPos eSplitPos)
274     :
275     mbShapesNeedSorting(false),
276     mnShapesSelected(0),
277     mpViewShell(pViewShell),
278     mpAccessibleDocument(pAccessibleDocument),
279     meSplitPos(eSplitPos)
280 {
281     if (mpViewShell)
282     {
283         SfxViewFrame* pViewFrame = mpViewShell->GetViewFrame();
284         if (pViewFrame)
285         {
286             xSelectionSupplier = uno::Reference<view::XSelectionSupplier>(pViewFrame->GetFrame().GetController(), uno::UNO_QUERY);
287             if (xSelectionSupplier.is())
288             {
289                 xSelectionSupplier->addSelectionChangeListener(mpAccessibleDocument);
290                 uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
291                 if (xShapes.is())
292                     mnShapesSelected = xShapes->getCount();
293             }
294         }
295     }
296 
297     maZOrderedShapes.push_back(nullptr); // add an element which represents the table
298 
299     GetCount(); // fill list with filtered shapes (no internal shapes)
300 
301     if (mnShapesSelected)
302     {
303         //set flag on every selected shape
304         if (!xSelectionSupplier.is())
305             throw uno::RuntimeException();
306 
307         uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
308         if (xShapes.is())
309             FindSelectedShapesChanges(xShapes);
310     }
311     if (pViewShell)
312     {
313         ScViewData& rViewData = pViewShell->GetViewData();
314         SfxBroadcaster* pDrawBC = rViewData.GetDocument()->GetDrawBroadcaster();
315         if (pDrawBC)
316         {
317             StartListening(*pDrawBC);
318 
319             maShapeTreeInfo.SetModelBroadcaster( new ScDrawModelBroadcaster(rViewData.GetDocument()->GetDrawLayer()) );
320             maShapeTreeInfo.SetSdrView(rViewData.GetScDrawView());
321             maShapeTreeInfo.SetController(nullptr);
322             maShapeTreeInfo.SetDevice(pViewShell->GetWindowByPos(meSplitPos));
323             maShapeTreeInfo.SetViewForwarder(mpAccessibleDocument);
324         }
325     }
326 }
327 
328 ScChildrenShapes::~ScChildrenShapes()
329 {
330     for (ScAccessibleShapeData* pShapeData : maZOrderedShapes)
331         delete pShapeData;
332     if (mpViewShell)
333     {
334         SfxBroadcaster* pDrawBC = mpViewShell->GetViewData().GetDocument()->GetDrawBroadcaster();
335         if (pDrawBC)
336             EndListening(*pDrawBC);
337     }
338     if (mpAccessibleDocument && xSelectionSupplier.is())
339         xSelectionSupplier->removeSelectionChangeListener(mpAccessibleDocument);
340 }
341 
342 void ScChildrenShapes::SetDrawBroadcaster()
343 {
344     if (mpViewShell)
345     {
346         ScViewData& rViewData = mpViewShell->GetViewData();
347         SfxBroadcaster* pDrawBC = rViewData.GetDocument()->GetDrawBroadcaster();
348         if (pDrawBC)
349         {
350             StartListening(*pDrawBC, DuplicateHandling::Prevent);
351 
352             maShapeTreeInfo.SetModelBroadcaster( new ScDrawModelBroadcaster(rViewData.GetDocument()->GetDrawLayer()) );
353             maShapeTreeInfo.SetSdrView(rViewData.GetScDrawView());
354             maShapeTreeInfo.SetController(nullptr);
355             maShapeTreeInfo.SetDevice(mpViewShell->GetWindowByPos(meSplitPos));
356             maShapeTreeInfo.SetViewForwarder(mpAccessibleDocument);
357         }
358     }
359 }
360 
361 void ScChildrenShapes::Notify(SfxBroadcaster&, const SfxHint& rHint)
362 {
363     if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint)
364         return;
365     const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
366 
367     SdrObject* pObj = const_cast<SdrObject*>(pSdrHint->GetObject());
368     if (pObj && /*(pObj->GetLayer() != SC_LAYER_INTERN) && */(pObj->getSdrPageFromSdrObject() == GetDrawPage()) &&
369         (pObj->getSdrPageFromSdrObject() == pObj->getParentSdrObjListFromSdrObject()) ) //only do something if the object lies direct on the page
370     {
371         switch (pSdrHint->GetKind())
372         {
373             case SdrHintKind::ObjectChange :         // object changed
374             {
375                 uno::Reference<drawing::XShape> xShape (pObj->getUnoShape(), uno::UNO_QUERY);
376                 if (xShape.is())
377                 {
378                     mbShapesNeedSorting = true; // sort, because the z index or layer could be changed
379                     auto it = maShapesMap.find(xShape);
380                     if (it != maShapesMap.end())
381                         SetAnchor(xShape, it->second);
382                 }
383             }
384             break;
385             case SdrHintKind::ObjectInserted :    // new drawing object inserted
386             {
387                 uno::Reference<drawing::XShape> xShape (pObj->getUnoShape(), uno::UNO_QUERY);
388                 if (xShape.is())
389                     AddShape(xShape, true);
390             }
391             break;
392             case SdrHintKind::ObjectRemoved :     // Removed drawing object from list
393             {
394                 uno::Reference<drawing::XShape> xShape (pObj->getUnoShape(), uno::UNO_QUERY);
395                 if (xShape.is())
396                     RemoveShape(xShape);
397             }
398             break;
399             default :
400             {
401                 // other events are not interesting
402             }
403             break;
404         }
405     }
406 }
407 
408 bool ScChildrenShapes::ReplaceChild (::accessibility::AccessibleShape* pCurrentChild,
409         const css::uno::Reference< css::drawing::XShape >& _rxShape,
410         const long /*_nIndex*/, const ::accessibility::AccessibleShapeTreeInfo& _rShapeTreeInfo)
411 {
412     // create the new child
413     rtl::Reference< ::accessibility::AccessibleShape > pReplacement(::accessibility::ShapeTypeHandler::Instance().CreateAccessibleObject (
414         ::accessibility::AccessibleShapeInfo ( _rxShape, pCurrentChild->getAccessibleParent(), this ),
415         _rShapeTreeInfo
416     ));
417     if ( pReplacement.is() )
418         pReplacement->Init();
419 
420     bool bResult(false);
421     if (pReplacement.is())
422     {
423         OSL_ENSURE(pCurrentChild->GetXShape().get() == pReplacement->GetXShape().get(), "XShape changes and should be inserted sorted");
424         auto it = maShapesMap.find(pCurrentChild->GetXShape());
425         if (it != maShapesMap.end())
426         {
427             if (it->second->pAccShape.is())
428             {
429                 OSL_ENSURE(it->second->pAccShape == pCurrentChild, "wrong child found");
430                 AccessibleEventObject aEvent;
431                 aEvent.EventId = AccessibleEventId::CHILD;
432                 aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument);
433                 aEvent.OldValue <<= uno::Reference<XAccessible>(pCurrentChild);
434 
435                 mpAccessibleDocument->CommitChange(aEvent); // child is gone - event
436 
437                 pCurrentChild->dispose();
438             }
439             it->second->pAccShape = pReplacement;
440             AccessibleEventObject aEvent;
441             aEvent.EventId = AccessibleEventId::CHILD;
442             aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument);
443             aEvent.NewValue <<= uno::Reference<XAccessible>(pReplacement.get());
444 
445             mpAccessibleDocument->CommitChange(aEvent); // child is new - event
446             bResult = true;
447         }
448     }
449     return bResult;
450 }
451 
452 ::accessibility::AccessibleControlShape * ScChildrenShapes::GetAccControlShapeFromModel(css::beans::XPropertySet* pSet)
453 {
454     GetCount(); // populate
455     for (ScAccessibleShapeData* pShape : maZOrderedShapes)
456     {
457         if (pShape)
458         {
459             rtl::Reference< ::accessibility::AccessibleShape > pAccShape(pShape->pAccShape);
460             if (pAccShape.is() && ::accessibility::ShapeTypeHandler::Instance().GetTypeId (pAccShape->GetXShape()) == ::accessibility::DRAWING_CONTROL)
461             {
462                 ::accessibility::AccessibleControlShape *pCtlAccShape = static_cast < ::accessibility::AccessibleControlShape* >(pAccShape.get());
463                 if (pCtlAccShape && pCtlAccShape->GetControlModel() == pSet)
464                     return pCtlAccShape;
465             }
466         }
467     }
468     return nullptr;
469 }
470 
471 css::uno::Reference < css::accessibility::XAccessible >
472 ScChildrenShapes::GetAccessibleCaption (const css::uno::Reference < css::drawing::XShape>& xShape)
473 {
474     GetCount(); // populate
475     auto it = maShapesMap.find(xShape);
476     if (it == maShapesMap.end())
477         return nullptr;
478     ScAccessibleShapeData* pShape = it->second;
479     css::uno::Reference< css::accessibility::XAccessible > xNewChild( pShape->pAccShape.get() );
480     if(xNewChild.get())
481         return xNewChild;
482     return nullptr;
483 }
484 
485 sal_Int32 ScChildrenShapes::GetCount() const
486 {
487     SdrPage* pDrawPage = GetDrawPage();
488     if (pDrawPage && (maZOrderedShapes.size() == 1)) // the table is always in
489     {
490         mnSdrObjCount = pDrawPage->GetObjCount();
491         maZOrderedShapes.reserve(mnSdrObjCount + 1); // the table is always in
492         for (size_t i = 0; i < mnSdrObjCount; ++i)
493         {
494             SdrObject* pObj = pDrawPage->GetObj(i);
495             if (pObj/* && (pObj->GetLayer() != SC_LAYER_INTERN)*/)
496             {
497                 uno::Reference< drawing::XShape > xShape (pObj->getUnoShape(), uno::UNO_QUERY);
498                 AddShape(xShape, false); //inserts in the correct order
499             }
500         }
501     }
502     return maZOrderedShapes.size();
503 }
504 
505 uno::Reference< XAccessible > ScChildrenShapes::Get(const ScAccessibleShapeData* pData) const
506 {
507     if (!pData)
508         return nullptr;
509 
510     if (!pData->pAccShape.is())
511     {
512         ::accessibility::ShapeTypeHandler& rShapeHandler = ::accessibility::ShapeTypeHandler::Instance();
513         ::accessibility::AccessibleShapeInfo aShapeInfo(pData->xShape, mpAccessibleDocument, const_cast<ScChildrenShapes*>(this));
514         pData->pAccShape = rShapeHandler.CreateAccessibleObject(
515             aShapeInfo, maShapeTreeInfo);
516         if (pData->pAccShape.is())
517         {
518             pData->pAccShape->Init();
519             if (pData->bSelected)
520                 pData->pAccShape->SetState(AccessibleStateType::SELECTED);
521             if (!pData->bSelectable)
522                 pData->pAccShape->ResetState(AccessibleStateType::SELECTABLE);
523             pData->pAccShape->SetRelationSet(GetRelationSet(pData));
524         }
525     }
526     return pData->pAccShape.get();
527  }
528 
529 uno::Reference< XAccessible > ScChildrenShapes::Get(sal_Int32 nIndex) const
530 {
531     if (maZOrderedShapes.size() <= 1)
532         GetCount(); // fill list with filtered shapes (no internal shapes)
533 
534     if (mbShapesNeedSorting)
535     {
536         std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
537         mbShapesNeedSorting = false;
538     }
539 
540     if (static_cast<sal_uInt32>(nIndex) >= maZOrderedShapes.size())
541         return nullptr;
542 
543     return Get(maZOrderedShapes[nIndex]);
544 }
545 
546 uno::Reference< XAccessible > ScChildrenShapes::GetAt(const awt::Point& rPoint) const
547 {
548     uno::Reference<XAccessible> xAccessible;
549     if(mpViewShell)
550     {
551         if (mbShapesNeedSorting)
552         {
553             std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
554             mbShapesNeedSorting = false;
555         }
556 
557         sal_Int32 i(maZOrderedShapes.size() - 1);
558         bool bFound(false);
559         while (!bFound && i >= 0)
560         {
561             ScAccessibleShapeData* pShape = maZOrderedShapes[i];
562             if (pShape)
563             {
564                 if (!pShape->pAccShape.is())
565                     Get(pShape);
566 
567                 if (pShape->pAccShape.is())
568                 {
569                     Point aPoint(VCLPoint(rPoint));
570                     aPoint -= VCLRectangle(pShape->pAccShape->getBounds()).TopLeft();
571                     if (pShape->pAccShape->containsPoint(AWTPoint(aPoint)))
572                     {
573                         xAccessible = pShape->pAccShape.get();
574                         bFound = true;
575                     }
576                 }
577                 else
578                 {
579                     OSL_FAIL("I should have an accessible shape now!");
580                 }
581             }
582             else
583                 bFound = true; // this is the sheet and it lies before the rest of the shapes which are background shapes
584 
585             --i;
586         }
587     }
588     return xAccessible;
589 }
590 
591 bool ScChildrenShapes::IsSelected(sal_Int32 nIndex,
592                         uno::Reference<drawing::XShape>& rShape) const
593 {
594     bool bResult (false);
595     if (maZOrderedShapes.size() <= 1)
596         GetCount(); // fill list with filtered shapes (no internal shapes)
597 
598     if (!xSelectionSupplier.is())
599         throw uno::RuntimeException();
600 
601     if (mbShapesNeedSorting)
602     {
603         std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
604         mbShapesNeedSorting = false;
605     }
606 
607     if (!maZOrderedShapes[nIndex])
608         return false;
609 
610     bResult = maZOrderedShapes[nIndex]->bSelected;
611     rShape = maZOrderedShapes[nIndex]->xShape;
612 
613 #if OSL_DEBUG_LEVEL > 0 // test whether it is truly selected by a slower method
614     uno::Reference< drawing::XShape > xReturnShape;
615     bool bDebugResult(false);
616     uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
617 
618     if (xShapes.is())
619     {
620         sal_Int32 nCount(xShapes->getCount());
621         if (nCount)
622         {
623             uno::Reference< drawing::XShape > xShape;
624             uno::Reference< drawing::XShape > xIndexShape = maZOrderedShapes[nIndex]->xShape;
625             sal_Int32 i(0);
626             while (!bDebugResult && (i < nCount))
627             {
628                 xShapes->getByIndex(i) >>= xShape;
629                 if (xShape.is() && (xIndexShape.get() == xShape.get()))
630                 {
631                     bDebugResult = true;
632                     xReturnShape = xShape;
633                 }
634                 else
635                     ++i;
636             }
637         }
638     }
639     OSL_ENSURE((bResult == bDebugResult) && ((bResult && (rShape.get() == xReturnShape.get())) || !bResult), "found the wrong shape or result");
640 #endif
641 
642     return bResult;
643 }
644 
645 bool ScChildrenShapes::SelectionChanged()
646 {
647     bool bResult(false);
648     if (!xSelectionSupplier.is())
649         throw uno::RuntimeException();
650 
651     uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
652 
653     bResult = FindSelectedShapesChanges(xShapes);
654 
655     return bResult;
656 }
657 
658 void ScChildrenShapes::Select(sal_Int32 nIndex)
659 {
660     if (maZOrderedShapes.size() <= 1)
661         GetCount(); // fill list with filtered shapes (no internal shapes)
662 
663     if (!xSelectionSupplier.is())
664         throw uno::RuntimeException();
665 
666     if (mbShapesNeedSorting)
667     {
668         std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
669         mbShapesNeedSorting = false;
670     }
671 
672     if (!maZOrderedShapes[nIndex])
673         return;
674 
675     uno::Reference<drawing::XShape> xShape;
676     if (!IsSelected(nIndex, xShape) && maZOrderedShapes[nIndex]->bSelectable)
677     {
678         uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
679 
680         if (!xShapes.is())
681             xShapes = drawing::ShapeCollection::create(
682                     comphelper::getProcessComponentContext());
683 
684         xShapes->add(maZOrderedShapes[nIndex]->xShape);
685 
686         try
687         {
688             xSelectionSupplier->select(uno::makeAny(xShapes));
689             maZOrderedShapes[nIndex]->bSelected = true;
690             if (maZOrderedShapes[nIndex]->pAccShape.is())
691                 maZOrderedShapes[nIndex]->pAccShape->SetState(AccessibleStateType::SELECTED);
692         }
693         catch (lang::IllegalArgumentException&)
694         {
695         }
696     }
697 }
698 
699 void ScChildrenShapes::DeselectAll()
700 {
701     if (!xSelectionSupplier.is())
702         throw uno::RuntimeException();
703 
704     bool bSomethingSelected(true);
705     try
706     {
707         xSelectionSupplier->select(uno::Any()); //deselects all
708     }
709     catch (lang::IllegalArgumentException&)
710     {
711         OSL_FAIL("nothing selected before");
712         bSomethingSelected = false;
713     }
714 
715     if (bSomethingSelected)
716         for (const ScAccessibleShapeData* pAccShapeData : maZOrderedShapes)
717             if (pAccShapeData)
718             {
719                 pAccShapeData->bSelected = false;
720                 if (pAccShapeData->pAccShape.is())
721                     pAccShapeData->pAccShape->ResetState(AccessibleStateType::SELECTED);
722             }
723 };
724 
725 
726 void ScChildrenShapes::SelectAll()
727 {
728     if (!xSelectionSupplier.is())
729         throw uno::RuntimeException();
730 
731     if (maZOrderedShapes.size() <= 1)
732         GetCount(); // fill list with filtered shapes (no internal shapes)
733 
734     if (maZOrderedShapes.size() > 1)
735     {
736         uno::Reference<drawing::XShapes> xShapes = drawing::ShapeCollection::create(
737                 comphelper::getProcessComponentContext());
738 
739         try
740         {
741             for (const ScAccessibleShapeData* pAccShapeData : maZOrderedShapes)
742             {
743                 if (pAccShapeData && pAccShapeData->bSelectable)
744                 {
745                     pAccShapeData->bSelected = true;
746                     if (pAccShapeData->pAccShape.is())
747                         pAccShapeData->pAccShape->SetState(AccessibleStateType::SELECTED);
748                     if (xShapes.is())
749                         xShapes->add(pAccShapeData->xShape);
750                 }
751             }
752             xSelectionSupplier->select(uno::makeAny(xShapes));
753         }
754         catch (lang::IllegalArgumentException&)
755         {
756             SelectionChanged(); // find all selected shapes and set the flags
757         }
758     }
759 }
760 
761 void ScChildrenShapes::FillShapes(std::vector < uno::Reference < drawing::XShape > >& rShapes) const
762 {
763     uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
764     if (xShapes.is())
765     {
766         sal_uInt32 nCount(xShapes->getCount());
767         for (sal_uInt32 i = 0; i < nCount; ++i)
768         {
769             uno::Reference<drawing::XShape> xShape;
770             xShapes->getByIndex(i) >>= xShape;
771             if (xShape.is())
772                 rShapes.push_back(xShape);
773         }
774     }
775 }
776 
777 sal_Int32 ScChildrenShapes::GetSelectedCount() const
778 {
779     if (!xSelectionSupplier.is())
780         throw uno::RuntimeException();
781 
782     std::vector < uno::Reference < drawing::XShape > > aShapes;
783     FillShapes(aShapes);
784 
785     return aShapes.size();
786 }
787 
788 uno::Reference< XAccessible > ScChildrenShapes::GetSelected(sal_Int32 nSelectedChildIndex, bool bTabSelected) const
789 {
790     uno::Reference< XAccessible > xAccessible;
791 
792     if (maZOrderedShapes.size() <= 1)
793         GetCount(); // fill list with shapes
794 
795     if (!bTabSelected)
796     {
797         std::vector < uno::Reference < drawing::XShape > > aShapes;
798         FillShapes(aShapes);
799 
800         if (nSelectedChildIndex < 0 || static_cast<size_t>(nSelectedChildIndex) >= aShapes.size())
801             return xAccessible;
802 
803         SortedShapes::iterator aItr;
804         if (FindShape(aShapes[nSelectedChildIndex], aItr))
805             xAccessible = Get(*aItr);
806     }
807     else
808     {
809         if (mbShapesNeedSorting)
810         {
811             std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
812             mbShapesNeedSorting = false;
813         }
814         for(const auto& rpShape : maZOrderedShapes)
815         {
816             if (!rpShape || rpShape->bSelected)
817             {
818                 if (nSelectedChildIndex == 0)
819                 {
820                     if (rpShape)
821                         xAccessible = rpShape->pAccShape.get();
822                     break;
823                 }
824                 else
825                     --nSelectedChildIndex;
826             }
827         }
828     }
829 
830     return xAccessible;
831 }
832 
833 void ScChildrenShapes::Deselect(sal_Int32 nChildIndex)
834 {
835     uno::Reference<drawing::XShape> xShape;
836     if (IsSelected(nChildIndex, xShape)) // returns false if it is the sheet
837     {
838         if (xShape.is())
839         {
840             uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
841             if (xShapes.is())
842                 xShapes->remove(xShape);
843 
844             try
845             {
846                 xSelectionSupplier->select(uno::makeAny(xShapes));
847             }
848             catch (lang::IllegalArgumentException&)
849             {
850                 OSL_FAIL("something not selectable");
851             }
852 
853             maZOrderedShapes[nChildIndex]->bSelected = false;
854             if (maZOrderedShapes[nChildIndex]->pAccShape.is())
855                 maZOrderedShapes[nChildIndex]->pAccShape->ResetState(AccessibleStateType::SELECTED);
856         }
857     }
858 }
859 
860 SdrPage* ScChildrenShapes::GetDrawPage() const
861 {
862     SCTAB nTab(mpAccessibleDocument->getVisibleTable());
863     SdrPage* pDrawPage = nullptr;
864     if (mpViewShell)
865     {
866         ScViewData& rViewData = mpViewShell->GetViewData();
867         ScDocument* pDoc = rViewData.GetDocument();
868         if (pDoc && pDoc->GetDrawLayer())
869         {
870             ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
871             if (pDrawLayer->HasObjects() && (pDrawLayer->GetPageCount() > nTab))
872                 pDrawPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(static_cast<sal_Int16>(nTab)));
873         }
874     }
875     return pDrawPage;
876 }
877 
878 utl::AccessibleRelationSetHelper* ScChildrenShapes::GetRelationSet(const ScAddress* pAddress) const
879 {
880     utl::AccessibleRelationSetHelper* pRelationSet = nullptr;
881     for (const ScAccessibleShapeData* pAccShapeData : maZOrderedShapes)
882     {
883         if (pAccShapeData &&
884             ((!pAccShapeData->xRelationCell && !pAddress) ||
885             (pAccShapeData->xRelationCell && pAddress && (*(pAccShapeData->xRelationCell) == *pAddress))))
886         {
887             if (!pRelationSet)
888                 pRelationSet = new utl::AccessibleRelationSetHelper();
889 
890             AccessibleRelation aRelation;
891             aRelation.TargetSet.realloc(1);
892             aRelation.TargetSet[0] = Get(pAccShapeData);
893             aRelation.RelationType = AccessibleRelationType::CONTROLLER_FOR;
894 
895             pRelationSet->AddRelation(aRelation);
896         }
897     }
898     return pRelationSet;
899 }
900 
901 bool ScChildrenShapes::FindSelectedShapesChanges(const uno::Reference<drawing::XShapes>& xShapes) const
902 {
903     bool bResult(false);
904     SortedShapes aShapesList;
905     if (xShapes.is())
906     {
907         mnShapesSelected = xShapes->getCount();
908         for (sal_uInt32 i = 0; i < mnShapesSelected; ++i)
909         {
910             uno::Reference< drawing::XShape > xShape;
911             xShapes->getByIndex(i) >>= xShape;
912             if (xShape.is())
913             {
914                 ScAccessibleShapeData* pShapeData = new ScAccessibleShapeData();
915                 pShapeData->xShape = xShape;
916                 aShapesList.push_back(pShapeData);
917             }
918         }
919     }
920     else
921         mnShapesSelected = 0;
922     SdrObject *pFocusedObj = nullptr;
923     if( mnShapesSelected == 1 && aShapesList.size() == 1)
924     {
925         pFocusedObj = GetSdrObjectFromXShape(aShapesList[0]->xShape);
926     }
927     std::sort(aShapesList.begin(), aShapesList.end(), ScShapeDataLess());
928     SortedShapes vecSelectedShapeAdd;
929     SortedShapes vecSelectedShapeRemove;
930     bool bHasSelect=false;
931     SortedShapes::iterator aXShapesItr(aShapesList.begin());
932     SortedShapes::const_iterator aXShapesEndItr(aShapesList.end());
933     SortedShapes::iterator aDataItr(maZOrderedShapes.begin());
934     SortedShapes::const_iterator aDataEndItr(maZOrderedShapes.end());
935     SortedShapes::const_iterator aFocusedItr = aDataEndItr;
936     while(aDataItr != aDataEndItr)
937     {
938         if (*aDataItr) // is it really a shape or only the sheet
939         {
940             sal_Int8 nComp(0);
941             if (aXShapesItr == aXShapesEndItr)
942                 nComp = -1; // simulate that the Shape is lower, so the selection state will be removed
943             else
944                 nComp = Compare(*aDataItr, *aXShapesItr);
945             if (nComp == 0)
946             {
947                 if (!(*aDataItr)->bSelected)
948                 {
949                     (*aDataItr)->bSelected = true;
950                     if ((*aDataItr)->pAccShape.is())
951                     {
952                         (*aDataItr)->pAccShape->SetState(AccessibleStateType::SELECTED);
953                         (*aDataItr)->pAccShape->SetState(AccessibleStateType::FOCUSED);
954                         bResult = true;
955                         vecSelectedShapeAdd.push_back(*aDataItr);
956                     }
957                     aFocusedItr = aDataItr;
958                 }
959                 else
960                 {
961                      bHasSelect = true;
962                 }
963                 ++aDataItr;
964                 ++aXShapesItr;
965             }
966             else if (nComp < 0)
967             {
968                 if ((*aDataItr)->bSelected)
969                 {
970                     (*aDataItr)->bSelected = false;
971                     if ((*aDataItr)->pAccShape.is())
972                     {
973                         (*aDataItr)->pAccShape->ResetState(AccessibleStateType::SELECTED);
974                         (*aDataItr)->pAccShape->ResetState(AccessibleStateType::FOCUSED);
975                         bResult = true;
976                         vecSelectedShapeRemove.push_back(*aDataItr);
977                     }
978                 }
979                 ++aDataItr;
980             }
981             else
982             {
983                 OSL_FAIL("here is a selected shape which is not in the childlist");
984                 ++aXShapesItr;
985                 --mnShapesSelected;
986             }
987         }
988         else
989             ++aDataItr;
990     }
991     bool bWinFocus=false;
992     if (mpViewShell)
993     {
994         ScGridWindow* pWin = static_cast<ScGridWindow*>(mpViewShell->GetWindowByPos(meSplitPos));
995         if (pWin)
996         {
997             bWinFocus = pWin->HasFocus();
998         }
999     }
1000     const SdrMarkList* pMarkList = nullptr;
1001     SdrObject* pMarkedObj = nullptr;
1002     SdrObject* pUpObj = nullptr;
1003     bool bIsFocuseMarked = true;
1004     if( mpViewShell && mnShapesSelected == 1 && bWinFocus)
1005     {
1006         ScDrawView* pScDrawView = mpViewShell->GetViewData().GetScDrawView();
1007         if( pScDrawView )
1008         {
1009             if( pScDrawView->GetMarkedObjectList().GetMarkCount() == 1 )
1010             {
1011                 pMarkList = &(pScDrawView->GetMarkedObjectList());
1012                 pMarkedObj = pMarkList->GetMark(0)->GetMarkedSdrObj();
1013                 uno::Reference< drawing::XShape > xMarkedXShape (pMarkedObj->getUnoShape(), uno::UNO_QUERY);
1014                 if( aFocusedItr != aDataEndItr &&
1015                     (*aFocusedItr)->xShape.is() &&
1016                     xMarkedXShape.is() &&
1017                     (*aFocusedItr)->xShape != xMarkedXShape )
1018                     bIsFocuseMarked = false;
1019             }
1020         }
1021     }
1022     //if ((aFocusedItr != aDataEndItr) && (*aFocusedItr)->pAccShape.is() && (mnShapesSelected == 1))
1023     if ( bIsFocuseMarked && (aFocusedItr != aDataEndItr) && (*aFocusedItr)->pAccShape.is() && (mnShapesSelected == 1) && bWinFocus)
1024     {
1025         (*aFocusedItr)->pAccShape->SetState(AccessibleStateType::FOCUSED);
1026     }
1027     else if( pFocusedObj && bWinFocus && pMarkList && pMarkList->GetMarkCount() == 1 && mnShapesSelected == 1 )
1028     {
1029         if( pMarkedObj )
1030         {
1031             uno::Reference< drawing::XShape > xMarkedXShape (pMarkedObj->getUnoShape(), uno::UNO_QUERY);
1032             pUpObj = pMarkedObj->getParentSdrObjectFromSdrObject();
1033 
1034             if( pMarkedObj == pFocusedObj && pUpObj )
1035             {
1036                 uno::Reference< drawing::XShape > xUpGroupXShape (pUpObj->getUnoShape(), uno::UNO_QUERY);
1037                 uno::Reference < XAccessible > xAccGroupShape =
1038                     const_cast<ScChildrenShapes*>(this)->GetAccessibleCaption( xUpGroupXShape );
1039                 if( xAccGroupShape.is() )
1040                 {
1041                     ::accessibility::AccessibleShape* pAccGroupShape =
1042                         static_cast< ::accessibility::AccessibleShape* >(xAccGroupShape.get());
1043                     if( pAccGroupShape )
1044                     {
1045                         sal_Int32 nCount =  pAccGroupShape->getAccessibleChildCount();
1046                         for( sal_Int32 i = 0; i < nCount; i++ )
1047                         {
1048                             uno::Reference<XAccessible> xAccShape = pAccGroupShape->getAccessibleChild(i);
1049                             if (xAccShape.is())
1050                             {
1051                                 ::accessibility::AccessibleShape* pChildAccShape =  static_cast< ::accessibility::AccessibleShape* >(xAccShape.get());
1052                                 uno::Reference< drawing::XShape > xChildShape = pChildAccShape->GetXShape();
1053                                 if (xChildShape == xMarkedXShape)
1054                                 {
1055                                     pChildAccShape->SetState(AccessibleStateType::FOCUSED);
1056                                 }
1057                                 else
1058                                 {
1059                                     pChildAccShape->ResetState(AccessibleStateType::FOCUSED);
1060                                 }
1061                             }
1062                         }
1063                     }
1064                 }
1065             }
1066         }
1067     }
1068     if (vecSelectedShapeAdd.size() >= 10 )
1069     {
1070         AccessibleEventObject aEvent;
1071         aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_WITHIN;
1072         aEvent.Source = uno::Reference< XAccessible >(mpAccessibleDocument);
1073         mpAccessibleDocument->CommitChange(aEvent);
1074     }
1075     else
1076     {
1077         for (const auto& rpShape : vecSelectedShapeAdd)
1078         {
1079             AccessibleEventObject aEvent;
1080             if (bHasSelect)
1081             {
1082                 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_ADD;
1083             }
1084             else
1085             {
1086                 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED;
1087             }
1088             aEvent.Source = uno::Reference< XAccessible >(mpAccessibleDocument);
1089             uno::Reference< XAccessible > xChild( rpShape->pAccShape.get());
1090             aEvent.NewValue <<= xChild;
1091             mpAccessibleDocument->CommitChange(aEvent);
1092         }
1093     }
1094     for (const auto& rpShape : vecSelectedShapeRemove)
1095     {
1096         AccessibleEventObject aEvent;
1097         aEvent.EventId =  AccessibleEventId::SELECTION_CHANGED_REMOVE;
1098         aEvent.Source = uno::Reference< XAccessible >(mpAccessibleDocument);
1099         uno::Reference< XAccessible > xChild( rpShape->pAccShape.get());
1100         aEvent.NewValue <<= xChild;
1101         mpAccessibleDocument->CommitChange(aEvent);
1102     }
1103     for(ScAccessibleShapeData*& pShapeData : aShapesList)
1104     {
1105         delete pShapeData;
1106         pShapeData = nullptr;
1107     }
1108     return bResult;
1109 }
1110 
1111 boost::optional<ScAddress> ScChildrenShapes::GetAnchor(const uno::Reference<drawing::XShape>& xShape) const
1112 {
1113     if (mpViewShell)
1114     {
1115         SvxShape* pShapeImp = comphelper::getUnoTunnelImplementation<SvxShape>(xShape);
1116         uno::Reference<beans::XPropertySet> xShapeProp(xShape, uno::UNO_QUERY);
1117         if (pShapeImp && xShapeProp.is())
1118         {
1119             if (SdrObject *pSdrObj = pShapeImp->GetSdrObject())
1120             {
1121                 if (ScDrawObjData *pAnchor = ScDrawLayer::GetObjData(pSdrObj))
1122                     return boost::optional<ScAddress>(pAnchor->maStart);
1123             }
1124         }
1125     }
1126 
1127     return boost::optional<ScAddress>();
1128 }
1129 
1130 uno::Reference<XAccessibleRelationSet> ScChildrenShapes::GetRelationSet(const ScAccessibleShapeData* pData) const
1131 {
1132     utl::AccessibleRelationSetHelper* pRelationSet = new utl::AccessibleRelationSetHelper();
1133 
1134     if (pData && mpAccessibleDocument)
1135     {
1136         uno::Reference<XAccessible> xAccessible = mpAccessibleDocument->GetAccessibleSpreadsheet(); // should be the current table
1137         if (pData->xRelationCell && xAccessible.is())
1138         {
1139             uno::Reference<XAccessibleTable> xAccTable (xAccessible->getAccessibleContext(), uno::UNO_QUERY);
1140             if (xAccTable.is())
1141                 xAccessible = xAccTable->getAccessibleCellAt(pData->xRelationCell->Row(), pData->xRelationCell->Col());
1142         }
1143         AccessibleRelation aRelation;
1144         aRelation.TargetSet.realloc(1);
1145         aRelation.TargetSet[0] = xAccessible;
1146         aRelation.RelationType = AccessibleRelationType::CONTROLLED_BY;
1147         pRelationSet->AddRelation(aRelation);
1148     }
1149 
1150     return pRelationSet;
1151 }
1152 
1153 void ScChildrenShapes::SetAnchor(const uno::Reference<drawing::XShape>& xShape, ScAccessibleShapeData* pData) const
1154 {
1155     if (pData)
1156     {
1157         boost::optional<ScAddress> xAddress = GetAnchor(xShape);
1158         if ((xAddress && pData->xRelationCell && (*xAddress != *(pData->xRelationCell))) ||
1159             (!xAddress && pData->xRelationCell) || (xAddress && !pData->xRelationCell))
1160         {
1161             pData->xRelationCell = xAddress;
1162             if (pData->pAccShape.is())
1163                 pData->pAccShape->SetRelationSet(GetRelationSet(pData));
1164         }
1165     }
1166 }
1167 
1168 void ScChildrenShapes::AddShape(const uno::Reference<drawing::XShape>& xShape, bool bCommitChange) const
1169 {
1170     if (mbShapesNeedSorting)
1171     {
1172         std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
1173         mbShapesNeedSorting = false;
1174     }
1175     SortedShapes::iterator aFindItr;
1176     if (!FindShape(xShape, aFindItr))
1177     {
1178         ScAccessibleShapeData* pShape = new ScAccessibleShapeData();
1179         pShape->xShape = xShape;
1180         SortedShapes::iterator aNewItr = maZOrderedShapes.insert(aFindItr, pShape);
1181         maShapesMap[xShape] = pShape;
1182         SetAnchor(xShape, pShape);
1183 
1184         uno::Reference< beans::XPropertySet > xShapeProp(xShape, uno::UNO_QUERY);
1185         if (xShapeProp.is())
1186         {
1187             uno::Any aPropAny = xShapeProp->getPropertyValue("LayerID");
1188             sal_Int16 nLayerID = 0;
1189             if( aPropAny >>= nLayerID )
1190             {
1191                 if( (SdrLayerID(nLayerID) == SC_LAYER_INTERN) || (SdrLayerID(nLayerID) == SC_LAYER_HIDDEN) )
1192                     pShape->bSelectable = false;
1193                 else
1194                     pShape->bSelectable = true;
1195             }
1196         }
1197 
1198         if (!xSelectionSupplier.is())
1199             throw uno::RuntimeException();
1200 
1201         uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
1202         uno::Reference<container::XEnumerationAccess> xEnumAcc(xShapes, uno::UNO_QUERY);
1203         if (xEnumAcc.is())
1204         {
1205             uno::Reference<container::XEnumeration> xEnum = xEnumAcc->createEnumeration();
1206             if (xEnum.is())
1207             {
1208                 uno::Reference<drawing::XShape> xSelectedShape;
1209                 bool bFound(false);
1210                 while (!bFound && xEnum->hasMoreElements())
1211                 {
1212                     xEnum->nextElement() >>= xSelectedShape;
1213                     if (xShape.is() && (xShape.get() == xSelectedShape.get()))
1214                     {
1215                         pShape->bSelected = true;
1216                         bFound = true;
1217                     }
1218                 }
1219             }
1220         }
1221         if (mpAccessibleDocument && bCommitChange)
1222         {
1223             AccessibleEventObject aEvent;
1224             aEvent.EventId = AccessibleEventId::CHILD;
1225             aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument);
1226             aEvent.NewValue <<= Get(*aNewItr);
1227 
1228             mpAccessibleDocument->CommitChange(aEvent); // new child - event
1229         }
1230     }
1231     else
1232     {
1233         OSL_FAIL("shape is always in the list");
1234     }
1235 }
1236 
1237 void ScChildrenShapes::RemoveShape(const uno::Reference<drawing::XShape>& xShape) const
1238 {
1239     if (mbShapesNeedSorting)
1240     {
1241         std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
1242         mbShapesNeedSorting = false;
1243     }
1244     SortedShapes::iterator aItr;
1245     if (FindShape(xShape, aItr))
1246     {
1247         if (mpAccessibleDocument)
1248         {
1249             uno::Reference<XAccessible> xOldAccessible (Get(*aItr));
1250 
1251             delete *aItr;
1252             maShapesMap.erase((*aItr)->xShape);
1253             maZOrderedShapes.erase(aItr);
1254 
1255             AccessibleEventObject aEvent;
1256             aEvent.EventId = AccessibleEventId::CHILD;
1257             aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument);
1258             aEvent.OldValue <<= xOldAccessible;
1259 
1260             mpAccessibleDocument->CommitChange(aEvent); // child is gone - event
1261         }
1262         else
1263         {
1264             delete *aItr;
1265             maShapesMap.erase((*aItr)->xShape);
1266             maZOrderedShapes.erase(aItr);
1267         }
1268     }
1269     else
1270     {
1271         OSL_FAIL("shape was not in internal list");
1272     }
1273 }
1274 
1275 bool ScChildrenShapes::FindShape(const uno::Reference<drawing::XShape>& xShape, ScChildrenShapes::SortedShapes::iterator& rItr) const
1276 {
1277     if (mbShapesNeedSorting)
1278     {
1279         std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
1280         mbShapesNeedSorting = false;
1281     }
1282     bool bResult(false);
1283     ScAccessibleShapeData aShape;
1284     aShape.xShape = xShape;
1285     rItr = std::lower_bound(maZOrderedShapes.begin(), maZOrderedShapes.end(), &aShape, ScShapeDataLess());
1286     if ((rItr != maZOrderedShapes.end()) && (*rItr != nullptr) && ((*rItr)->xShape.get() == xShape.get()))
1287         bResult = true; // if the shape is found
1288 
1289 #if OSL_DEBUG_LEVEL > 0 // test whether it finds truly the correct shape (perhaps it is not really sorted)
1290     SortedShapes::iterator aDebugItr = std::find_if(maZOrderedShapes.begin(), maZOrderedShapes.end(),
1291         [&xShape](const ScAccessibleShapeData* pShape) { return pShape && (pShape->xShape.get() == xShape.get()); });
1292     bool bResult2 = (aDebugItr != maZOrderedShapes.end());
1293     OSL_ENSURE((bResult == bResult2) && ((bResult && (rItr == aDebugItr)) || !bResult), "wrong Shape found");
1294 #endif
1295     return bResult;
1296 }
1297 
1298 sal_Int8 ScChildrenShapes::Compare(const ScAccessibleShapeData* pData1,
1299         const ScAccessibleShapeData* pData2)
1300 {
1301     ScShapeDataLess aLess;
1302 
1303     bool bResult1(aLess(pData1, pData2));
1304     bool bResult2(aLess(pData2, pData1));
1305 
1306     sal_Int8 nResult(0);
1307     if (!bResult1 && bResult2)
1308         nResult = 1;
1309     else if (bResult1 && !bResult2)
1310         nResult = -1;
1311 
1312     return nResult;
1313 }
1314 
1315 void ScChildrenShapes::VisAreaChanged() const
1316 {
1317     for (const ScAccessibleShapeData* pAccShapeData: maZOrderedShapes)
1318         if (pAccShapeData && pAccShapeData->pAccShape.is())
1319             pAccShapeData->pAccShape->ViewForwarderChanged();
1320 }
1321 
1322 ScAccessibleDocument::ScAccessibleDocument(
1323         const uno::Reference<XAccessible>& rxParent,
1324         ScTabViewShell* pViewShell,
1325         ScSplitPos eSplitPos)
1326     : ScAccessibleDocumentBase(rxParent),
1327     mpViewShell(pViewShell),
1328     meSplitPos(eSplitPos),
1329     mpTempAccEdit(nullptr),
1330     mbCompleteSheetSelected(false)
1331 {
1332     maVisArea = GetVisibleArea_Impl();
1333 }
1334 
1335 void ScAccessibleDocument::PreInit()
1336 {
1337     if (mpViewShell)
1338     {
1339         mpViewShell->AddAccessibilityObject(*this);
1340         vcl::Window *pWin = mpViewShell->GetWindowByPos(meSplitPos);
1341         if( pWin )
1342         {
1343             pWin->AddChildEventListener( LINK( this, ScAccessibleDocument, WindowChildEventListener ));
1344             sal_uInt16 nCount =   pWin->GetChildCount();
1345             for( sal_uInt16 i=0; i < nCount; ++i )
1346             {
1347                 vcl::Window *pChildWin = pWin->GetChild( i );
1348                 if( pChildWin &&
1349                     AccessibleRole::EMBEDDED_OBJECT == pChildWin->GetAccessibleRole() )
1350                     AddChild( pChildWin->GetAccessible(), false );
1351             }
1352         }
1353         ScViewData& rViewData = mpViewShell->GetViewData();
1354         if (rViewData.HasEditView(meSplitPos))
1355         {
1356             uno::Reference<XAccessible> xAcc = new ScAccessibleEditObject(this, rViewData.GetEditView(meSplitPos),
1357                 mpViewShell->GetWindowByPos(meSplitPos), GetCurrentCellName(), GetCurrentCellDescription(),
1358                 ScAccessibleEditObject::CellInEditMode);
1359             AddChild(xAcc, false);
1360         }
1361     }
1362 }
1363 
1364 void ScAccessibleDocument::Init()
1365 {
1366     if(!mpChildrenShapes)
1367         mpChildrenShapes.reset( new ScChildrenShapes(this, mpViewShell, meSplitPos) );
1368 }
1369 
1370 ScAccessibleDocument::~ScAccessibleDocument()
1371 {
1372     if (!ScAccessibleContextBase::IsDefunc() && !rBHelper.bInDispose)
1373     {
1374         // increment refcount to prevent double call off dtor
1375         osl_atomic_increment( &m_refCount );
1376         dispose();
1377     }
1378 }
1379 
1380 void SAL_CALL ScAccessibleDocument::disposing()
1381 {
1382     SolarMutexGuard aGuard;
1383     FreeAccessibleSpreadsheet();
1384     if (mpViewShell)
1385     {
1386         vcl::Window *pWin = mpViewShell->GetWindowByPos(meSplitPos);
1387         if( pWin )
1388             pWin->RemoveChildEventListener( LINK( this, ScAccessibleDocument, WindowChildEventListener ));
1389 
1390         mpViewShell->RemoveAccessibilityObject(*this);
1391         mpViewShell = nullptr;
1392     }
1393     mpChildrenShapes.reset();
1394 
1395     ScAccessibleDocumentBase::disposing();
1396 }
1397 
1398 void SAL_CALL ScAccessibleDocument::disposing( const lang::EventObject& /* Source */ )
1399 {
1400     disposing();
1401 }
1402 
1403     //=====  SfxListener  =====================================================
1404 
1405 IMPL_LINK( ScAccessibleDocument, WindowChildEventListener, VclWindowEvent&, rEvent, void )
1406 {
1407     OSL_ENSURE( rEvent.GetWindow(), "Window???" );
1408     switch ( rEvent.GetId() )
1409     {
1410     case VclEventId::WindowShow:  // send create on show for direct accessible children
1411         {
1412             vcl::Window* pChildWin = static_cast < vcl::Window * >( rEvent.GetData() );
1413             if( pChildWin && AccessibleRole::EMBEDDED_OBJECT == pChildWin->GetAccessibleRole() )
1414             {
1415                 AddChild( pChildWin->GetAccessible(), true );
1416             }
1417         }
1418         break;
1419     case VclEventId::WindowHide:  // send destroy on hide for direct accessible children
1420         {
1421             vcl::Window* pChildWin = static_cast < vcl::Window * >( rEvent.GetData() );
1422             if( pChildWin && AccessibleRole::EMBEDDED_OBJECT == pChildWin->GetAccessibleRole() )
1423             {
1424                 RemoveChild( pChildWin->GetAccessible(), true );
1425             }
1426         }
1427         break;
1428     default: break;
1429     }
1430 }
1431 
1432 void ScAccessibleDocument::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
1433 {
1434     if (dynamic_cast<const ScAccGridWinFocusLostHint*>(&rHint) )
1435     {
1436         const ScAccGridWinFocusLostHint* pFocusLostHint = static_cast<const ScAccGridWinFocusLostHint *>(&rHint);
1437         if (pFocusLostHint->GetOldGridWin() == meSplitPos)
1438         {
1439             if (mxTempAcc.is() && mpTempAccEdit)
1440                 mpTempAccEdit->LostFocus();
1441             else if (mpAccessibleSpreadsheet.is())
1442                 mpAccessibleSpreadsheet->LostFocus();
1443             else
1444                 CommitFocusLost();
1445         }
1446     }
1447     else if (dynamic_cast<const ScAccGridWinFocusGotHint*>(&rHint) )
1448     {
1449         const ScAccGridWinFocusGotHint* pFocusGotHint = static_cast<const ScAccGridWinFocusGotHint*>(&rHint);
1450         if (pFocusGotHint->GetNewGridWin() == meSplitPos)
1451         {
1452             uno::Reference<XAccessible> xAccessible;
1453             if (mpChildrenShapes)
1454             {
1455                 bool bTabMarked(IsTableSelected());
1456                 xAccessible = mpChildrenShapes->GetSelected(0, bTabMarked);
1457             }
1458             if( xAccessible.is() )
1459             {
1460                 uno::Any aNewValue;
1461                 aNewValue<<=AccessibleStateType::FOCUSED;
1462                 static_cast< ::accessibility::AccessibleShape* >(xAccessible.get())->
1463                     CommitChange(AccessibleEventId::STATE_CHANGED,
1464                                 aNewValue,
1465                                 uno::Any() );
1466             }
1467             else
1468             {
1469             if (mxTempAcc.is() && mpTempAccEdit)
1470                 mpTempAccEdit->GotFocus();
1471             else if (mpAccessibleSpreadsheet.is())
1472                 mpAccessibleSpreadsheet->GotFocus();
1473             else
1474                 CommitFocusGained();
1475             }
1476         }
1477     }
1478     else
1479     {
1480         // only notify if child exist, otherwise it is not necessary
1481         if ((rHint.GetId() == SfxHintId::ScAccTableChanged) &&
1482             mpAccessibleSpreadsheet.is())
1483         {
1484             FreeAccessibleSpreadsheet();
1485 
1486             // Shapes / form controls after reload not accessible, rebuild the
1487             // mpChildrenShapes variable.
1488             mpChildrenShapes.reset( new ScChildrenShapes( this, mpViewShell, meSplitPos ) );
1489 
1490             AccessibleEventObject aEvent;
1491             aEvent.EventId = AccessibleEventId::INVALIDATE_ALL_CHILDREN;
1492             aEvent.Source = uno::Reference< XAccessibleContext >(this);
1493             CommitChange(aEvent); // all children changed
1494 
1495             if (mpAccessibleSpreadsheet.is())
1496                 mpAccessibleSpreadsheet->FireFirstCellFocus();
1497         }
1498         else if (rHint.GetId() == SfxHintId::ScAccMakeDrawLayer)
1499         {
1500             if (mpChildrenShapes)
1501                 mpChildrenShapes->SetDrawBroadcaster();
1502         }
1503         else if (rHint.GetId() == SfxHintId::ScAccEnterEditMode) // this event comes only on creating edit field of a cell
1504         {
1505             if (mpViewShell->GetViewData().GetEditActivePart() == meSplitPos)
1506             {
1507                 ScViewData& rViewData = mpViewShell->GetViewData();
1508                 const EditEngine* pEditEng = rViewData.GetEditView(meSplitPos)->GetEditEngine();
1509                 if (pEditEng && pEditEng->GetUpdateMode())
1510                 {
1511                     mpTempAccEdit = new ScAccessibleEditObject(this, rViewData.GetEditView(meSplitPos),
1512                         mpViewShell->GetWindowByPos(meSplitPos), GetCurrentCellName(),
1513                         ScResId(STR_ACC_EDITLINE_DESCR), ScAccessibleEditObject::CellInEditMode);
1514                     uno::Reference<XAccessible> xAcc = mpTempAccEdit;
1515 
1516                     AddChild(xAcc, true);
1517 
1518                     if (mpAccessibleSpreadsheet.is())
1519                         mpAccessibleSpreadsheet->LostFocus();
1520                     else
1521                         CommitFocusLost();
1522 
1523                     mpTempAccEdit->GotFocus();
1524                 }
1525             }
1526         }
1527         else if (rHint.GetId() == SfxHintId::ScAccLeaveEditMode)
1528         {
1529             if (mxTempAcc.is())
1530             {
1531                 if (mpTempAccEdit)
1532                 {
1533                     mpTempAccEdit->LostFocus();
1534                 }
1535                 RemoveChild(mxTempAcc, true);
1536                 if (mpTempAccEdit)
1537                 {
1538                     // tdf#125982 a11y use-after-free of editengine by
1539                     // ScAccessibleEditObjectTextData living past the
1540                     // the editengine of the editview passed in above
1541                     // in ScAccEnterEditMode
1542                     mpTempAccEdit->dispose();
1543                     mpTempAccEdit = nullptr;
1544                 }
1545                 if (mpAccessibleSpreadsheet.is() && mpViewShell && mpViewShell->IsActive())
1546                     mpAccessibleSpreadsheet->GotFocus();
1547                 else if( mpViewShell && mpViewShell->IsActive())
1548                     CommitFocusGained();
1549             }
1550         }
1551         else if ((rHint.GetId() == SfxHintId::ScAccVisAreaChanged) || (rHint.GetId() == SfxHintId::ScAccWindowResized))
1552         {
1553             tools::Rectangle aOldVisArea(maVisArea);
1554             maVisArea = GetVisibleArea_Impl();
1555 
1556             if (maVisArea != aOldVisArea)
1557             {
1558                 if (maVisArea.GetSize() != aOldVisArea.GetSize())
1559                 {
1560                     AccessibleEventObject aEvent;
1561                     aEvent.EventId = AccessibleEventId::BOUNDRECT_CHANGED;
1562                     aEvent.Source = uno::Reference< XAccessibleContext >(this);
1563 
1564                     CommitChange(aEvent);
1565 
1566                     if (mpAccessibleSpreadsheet.is())
1567                         mpAccessibleSpreadsheet->BoundingBoxChanged();
1568                     if (mpAccessibleSpreadsheet.is() && mpViewShell && mpViewShell->IsActive())
1569                         mpAccessibleSpreadsheet->FireFirstCellFocus();
1570                 }
1571                 else if (mpAccessibleSpreadsheet.is())
1572                 {
1573                     mpAccessibleSpreadsheet->VisAreaChanged();
1574                 }
1575                 if (mpChildrenShapes)
1576                     mpChildrenShapes->VisAreaChanged();
1577             }
1578         }
1579     }
1580 
1581     ScAccessibleDocumentBase::Notify(rBC, rHint);
1582 }
1583 
1584 void SAL_CALL ScAccessibleDocument::selectionChanged( const lang::EventObject& /* aEvent */ )
1585 {
1586     bool bSelectionChanged(false);
1587     if (mpAccessibleSpreadsheet.is())
1588     {
1589         bool bOldSelected(mbCompleteSheetSelected);
1590         mbCompleteSheetSelected = IsTableSelected();
1591         if (bOldSelected != mbCompleteSheetSelected)
1592         {
1593             mpAccessibleSpreadsheet->CompleteSelectionChanged(mbCompleteSheetSelected);
1594             bSelectionChanged = true;
1595         }
1596     }
1597 
1598     if (mpChildrenShapes && mpChildrenShapes->SelectionChanged())
1599         bSelectionChanged = true;
1600 
1601     if (bSelectionChanged)
1602     {
1603         AccessibleEventObject aEvent;
1604         aEvent.EventId = AccessibleEventId::SELECTION_CHANGED;
1605         aEvent.Source = uno::Reference< XAccessibleContext >(this);
1606 
1607         CommitChange(aEvent);
1608     }
1609 }
1610 
1611     //=====  XInterface  =====================================================
1612 
1613 uno::Any SAL_CALL ScAccessibleDocument::queryInterface( uno::Type const & rType )
1614 {
1615     uno::Any aAnyTmp;
1616     if(rType == cppu::UnoType<XAccessibleGetAccFlowTo>::get())
1617     {
1618          css::uno::Reference<XAccessibleGetAccFlowTo> AccFromXShape = this;
1619          aAnyTmp <<= AccFromXShape;
1620          return aAnyTmp;
1621     }
1622     uno::Any aAny (ScAccessibleDocumentImpl::queryInterface(rType));
1623     return aAny.hasValue() ? aAny : ScAccessibleContextBase::queryInterface(rType);
1624 }
1625 
1626 void SAL_CALL ScAccessibleDocument::acquire()
1627     throw ()
1628 {
1629     ScAccessibleContextBase::acquire();
1630 }
1631 
1632 void SAL_CALL ScAccessibleDocument::release()
1633     throw ()
1634 {
1635     ScAccessibleContextBase::release();
1636 }
1637 
1638     //=====  XAccessibleComponent  ============================================
1639 
1640 uno::Reference< XAccessible > SAL_CALL ScAccessibleDocument::getAccessibleAtPoint(
1641         const awt::Point& rPoint )
1642 {
1643     uno::Reference<XAccessible> xAccessible;
1644     if (containsPoint(rPoint))
1645     {
1646         SolarMutexGuard aGuard;
1647         IsObjectValid();
1648         if (mpChildrenShapes)
1649             xAccessible = mpChildrenShapes->GetAt(rPoint);
1650         if(!xAccessible.is())
1651         {
1652             if (mxTempAcc.is())
1653             {
1654                 uno::Reference< XAccessibleContext > xCont(mxTempAcc->getAccessibleContext());
1655                 uno::Reference< XAccessibleComponent > xComp(xCont, uno::UNO_QUERY);
1656                 if (xComp.is())
1657                 {
1658                     tools::Rectangle aBound(VCLRectangle(xComp->getBounds()));
1659                     if (aBound.IsInside(VCLPoint(rPoint)))
1660                         xAccessible = mxTempAcc;
1661                 }
1662             }
1663             if (!xAccessible.is())
1664                 xAccessible = GetAccessibleSpreadsheet();
1665         }
1666     }
1667     return xAccessible;
1668 }
1669 
1670 void SAL_CALL ScAccessibleDocument::grabFocus(  )
1671 {
1672     SolarMutexGuard aGuard;
1673     IsObjectValid();
1674     if (getAccessibleParent().is())
1675     {
1676         uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY);
1677         if (xAccessibleComponent.is())
1678         {
1679             xAccessibleComponent->grabFocus();
1680             // grab only focus if it does not have the focus and it is not hidden
1681             if (mpViewShell &&
1682                 (mpViewShell->GetViewData().GetActivePart() != meSplitPos) &&
1683                 mpViewShell->GetWindowByPos(meSplitPos)->IsVisible())
1684             {
1685                 mpViewShell->ActivatePart(meSplitPos);
1686             }
1687         }
1688     }
1689 }
1690 
1691     //=====  XAccessibleContext  ==============================================
1692 
1693     /// Return the number of currently visible children.
1694 sal_Int32 SAL_CALL
1695     ScAccessibleDocument::getAccessibleChildCount()
1696 {
1697     SolarMutexGuard aGuard;
1698     IsObjectValid();
1699     sal_Int32 nCount(1);
1700     if (mpChildrenShapes)
1701         nCount = mpChildrenShapes->GetCount(); // returns the count of the shapes inclusive the table
1702 
1703     if (mxTempAcc.is())
1704         ++nCount;
1705 
1706     return nCount;
1707 }
1708 
1709     /// Return the specified child or NULL if index is invalid.
1710 uno::Reference<XAccessible> SAL_CALL
1711     ScAccessibleDocument::getAccessibleChild(sal_Int32 nIndex)
1712 {
1713     SolarMutexGuard aGuard;
1714     IsObjectValid();
1715     uno::Reference<XAccessible> xAccessible;
1716     if (nIndex >= 0)
1717     {
1718         sal_Int32 nCount(1);
1719         if (mpChildrenShapes)
1720         {
1721             xAccessible = mpChildrenShapes->Get(nIndex); // returns NULL if it is the table or out of range
1722             nCount = mpChildrenShapes->GetCount(); //there is always a table
1723         }
1724         if (!xAccessible.is())
1725         {
1726             if (nIndex < nCount)
1727                 xAccessible = GetAccessibleSpreadsheet();
1728             else if (nIndex == nCount && mxTempAcc.is())
1729                 xAccessible = mxTempAcc;
1730         }
1731     }
1732 
1733     if (!xAccessible.is())
1734         throw lang::IndexOutOfBoundsException();
1735 
1736     return xAccessible;
1737 }
1738 
1739     /// Return the set of current states.
1740 uno::Reference<XAccessibleStateSet> SAL_CALL
1741     ScAccessibleDocument::getAccessibleStateSet()
1742 {
1743     SolarMutexGuard aGuard;
1744     uno::Reference<XAccessibleStateSet> xParentStates;
1745     if (getAccessibleParent().is())
1746     {
1747         uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext();
1748         xParentStates = xParentContext->getAccessibleStateSet();
1749     }
1750     utl::AccessibleStateSetHelper* pStateSet = new utl::AccessibleStateSetHelper();
1751     if (IsDefunc(xParentStates))
1752         pStateSet->AddState(AccessibleStateType::DEFUNC);
1753     else
1754     {
1755         pStateSet->AddState(AccessibleStateType::EDITABLE);
1756         pStateSet->AddState(AccessibleStateType::ENABLED);
1757         pStateSet->AddState(AccessibleStateType::OPAQUE);
1758         if (isShowing())
1759             pStateSet->AddState(AccessibleStateType::SHOWING);
1760         if (isVisible())
1761             pStateSet->AddState(AccessibleStateType::VISIBLE);
1762     }
1763     return pStateSet;
1764 }
1765 
1766 OUString SAL_CALL
1767     ScAccessibleDocument::getAccessibleName()
1768 {
1769     SolarMutexGuard g;
1770 
1771     OUString aName = ScResId(STR_ACC_DOC_SPREADSHEET);
1772     ScDocument* pScDoc = GetDocument();
1773     if (!pScDoc)
1774         return aName;
1775 
1776     SfxObjectShell* pObjSh = pScDoc->GetDocumentShell();
1777     if (!pObjSh)
1778         return aName;
1779 
1780     OUString aFileName;
1781     SfxMedium* pMed = pObjSh->GetMedium();
1782     if (pMed)
1783         aFileName = pMed->GetName();
1784 
1785     if (aFileName.isEmpty())
1786         aFileName = pObjSh->GetTitle(SFX_TITLE_APINAME);
1787 
1788     if (!aFileName.isEmpty())
1789     {
1790         OUString aReadOnly;
1791         if (pObjSh->IsReadOnly())
1792             aReadOnly = ScResId(STR_ACC_DOC_SPREADSHEET_READONLY);
1793 
1794         aName = aFileName + aReadOnly + " - " + aName;
1795     }
1796     return aName;
1797 }
1798 
1799 ///=====  XAccessibleSelection  ===========================================
1800 
1801 void SAL_CALL
1802     ScAccessibleDocument::selectAccessibleChild( sal_Int32 nChildIndex )
1803 {
1804     SolarMutexGuard aGuard;
1805     IsObjectValid();
1806 
1807     if (mpChildrenShapes && mpViewShell)
1808     {
1809         sal_Int32 nCount(mpChildrenShapes->GetCount()); // all shapes and the table
1810         if (mxTempAcc.is())
1811             ++nCount;
1812         if (nChildIndex < 0 || nChildIndex >= nCount)
1813             throw lang::IndexOutOfBoundsException();
1814 
1815         uno::Reference < XAccessible > xAccessible = mpChildrenShapes->Get(nChildIndex);
1816         if (xAccessible.is())
1817         {
1818             bool bWasTableSelected(IsTableSelected());
1819             mpChildrenShapes->Select(nChildIndex); // throws no lang::IndexOutOfBoundsException if Index is too high
1820             if (bWasTableSelected)
1821                 mpViewShell->SelectAll();
1822         }
1823         else
1824         {
1825             mpViewShell->SelectAll();
1826         }
1827     }
1828 }
1829 
1830 sal_Bool SAL_CALL
1831     ScAccessibleDocument::isAccessibleChildSelected( sal_Int32 nChildIndex )
1832 {
1833     SolarMutexGuard aGuard;
1834     IsObjectValid();
1835     bool bResult(false);
1836 
1837     if (mpChildrenShapes)
1838     {
1839         sal_Int32 nCount(mpChildrenShapes->GetCount()); // all shapes and the table
1840         if (mxTempAcc.is())
1841             ++nCount;
1842         if (nChildIndex < 0 || nChildIndex >= nCount)
1843             throw lang::IndexOutOfBoundsException();
1844 
1845         uno::Reference < XAccessible > xAccessible = mpChildrenShapes->Get(nChildIndex);
1846         if (xAccessible.is())
1847         {
1848             uno::Reference<drawing::XShape> xShape;
1849             bResult = mpChildrenShapes->IsSelected(nChildIndex, xShape); // throws no lang::IndexOutOfBoundsException if Index is too high
1850         }
1851         else
1852         {
1853             if (mxTempAcc.is() && nChildIndex == nCount)
1854                 bResult = true;
1855             else
1856                 bResult = IsTableSelected();
1857         }
1858     }
1859     return bResult;
1860 }
1861 
1862 void SAL_CALL
1863     ScAccessibleDocument::clearAccessibleSelection(  )
1864 {
1865     SolarMutexGuard aGuard;
1866     IsObjectValid();
1867 
1868     if (mpChildrenShapes)
1869         mpChildrenShapes->DeselectAll(); //deselects all (also the table)
1870 }
1871 
1872 void SAL_CALL
1873     ScAccessibleDocument::selectAllAccessibleChildren(  )
1874 {
1875     SolarMutexGuard aGuard;
1876     IsObjectValid();
1877 
1878     if (mpChildrenShapes)
1879         mpChildrenShapes->SelectAll();
1880 
1881     // select table after shapes, because while selecting shapes the table will be deselected
1882     if (mpViewShell)
1883     {
1884         mpViewShell->SelectAll();
1885     }
1886 }
1887 
1888 sal_Int32 SAL_CALL
1889     ScAccessibleDocument::getSelectedAccessibleChildCount(  )
1890 {
1891     SolarMutexGuard aGuard;
1892     IsObjectValid();
1893     sal_Int32 nCount(0);
1894 
1895     if (mpChildrenShapes)
1896         nCount = mpChildrenShapes->GetSelectedCount();
1897 
1898     if (IsTableSelected())
1899         ++nCount;
1900 
1901     if (mxTempAcc.is())
1902         ++nCount;
1903 
1904     return nCount;
1905 }
1906 
1907 uno::Reference<XAccessible > SAL_CALL
1908     ScAccessibleDocument::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex )
1909 {
1910     SolarMutexGuard aGuard;
1911     IsObjectValid();
1912     uno::Reference<XAccessible> xAccessible;
1913     if (mpChildrenShapes)
1914     {
1915         sal_Int32 nCount(getSelectedAccessibleChildCount()); //all shapes and the table
1916         if (nSelectedChildIndex < 0 || nSelectedChildIndex >= nCount)
1917             throw lang::IndexOutOfBoundsException();
1918 
1919         bool bTabMarked(IsTableSelected());
1920 
1921         if (mpChildrenShapes)
1922             xAccessible = mpChildrenShapes->GetSelected(nSelectedChildIndex, bTabMarked); // throws no lang::IndexOutOfBoundsException if Index is too high
1923         if (mxTempAcc.is() && nSelectedChildIndex == nCount - 1)
1924             xAccessible = mxTempAcc;
1925         else if (bTabMarked)
1926             xAccessible = GetAccessibleSpreadsheet();
1927     }
1928 
1929     OSL_ENSURE(xAccessible.is(), "here should always be an accessible object or an exception thrown");
1930 
1931     return xAccessible;
1932 }
1933 
1934 void SAL_CALL
1935     ScAccessibleDocument::deselectAccessibleChild( sal_Int32 nChildIndex )
1936 {
1937     SolarMutexGuard aGuard;
1938     IsObjectValid();
1939 
1940     if (mpChildrenShapes && mpViewShell)
1941     {
1942         sal_Int32 nCount(mpChildrenShapes->GetCount()); // all shapes and the table
1943         if (mxTempAcc.is())
1944             ++nCount;
1945         if (nChildIndex < 0 || nChildIndex >= nCount)
1946             throw lang::IndexOutOfBoundsException();
1947 
1948         bool bTabMarked(IsTableSelected());
1949 
1950         uno::Reference < XAccessible > xAccessible = mpChildrenShapes->Get(nChildIndex);
1951         if (xAccessible.is())
1952         {
1953             mpChildrenShapes->Deselect(nChildIndex); // throws no lang::IndexOutOfBoundsException if Index is too high
1954             if (bTabMarked)
1955                 mpViewShell->SelectAll(); // select the table again
1956         }
1957         else if (bTabMarked)
1958             mpViewShell->Unmark();
1959     }
1960 }
1961 
1962     //=====  XServiceInfo  ====================================================
1963 
1964 OUString SAL_CALL
1965     ScAccessibleDocument::getImplementationName()
1966 {
1967     return "ScAccessibleDocument";
1968 }
1969 
1970 uno::Sequence< OUString> SAL_CALL
1971     ScAccessibleDocument::getSupportedServiceNames()
1972 {
1973     uno::Sequence< OUString > aSequence = ScAccessibleContextBase::getSupportedServiceNames();
1974     sal_Int32 nOldSize(aSequence.getLength());
1975     aSequence.realloc(nOldSize + 1);
1976 
1977     aSequence[nOldSize] = "com.sun.star.AccessibleSpreadsheetDocumentView";
1978 
1979     return aSequence;
1980 }
1981 
1982 //=====  XTypeProvider  =======================================================
1983 
1984 uno::Sequence< uno::Type > SAL_CALL ScAccessibleDocument::getTypes()
1985 {
1986     return comphelper::concatSequences(ScAccessibleDocumentImpl::getTypes(), ScAccessibleContextBase::getTypes());
1987 }
1988 
1989 uno::Sequence<sal_Int8> SAL_CALL
1990     ScAccessibleDocument::getImplementationId()
1991 {
1992     return css::uno::Sequence<sal_Int8>();
1993 }
1994 
1995 ///=====  IAccessibleViewForwarder  ========================================
1996 
1997 tools::Rectangle ScAccessibleDocument::GetVisibleArea_Impl() const
1998 {
1999     tools::Rectangle aVisRect(GetBoundingBox());
2000 
2001     if (mpViewShell)
2002     {
2003         Point aPoint(mpViewShell->GetViewData().GetPixPos(meSplitPos)); // returns a negative Point
2004         aPoint.setX(-aPoint.getX());
2005         aPoint.setY(-aPoint.getY());
2006         aVisRect.SetPos(aPoint);
2007 
2008         ScGridWindow* pWin = static_cast<ScGridWindow*>(mpViewShell->GetWindowByPos(meSplitPos));
2009         if (pWin)
2010             aVisRect = pWin->PixelToLogic(aVisRect, pWin->GetDrawMapMode());
2011     }
2012 
2013     return aVisRect;
2014 }
2015 
2016 tools::Rectangle ScAccessibleDocument::GetVisibleArea() const
2017 {
2018     SolarMutexGuard aGuard;
2019     IsObjectValid();
2020     return maVisArea;
2021 }
2022 
2023 Point ScAccessibleDocument::LogicToPixel (const Point& rPoint) const
2024 {
2025     SolarMutexGuard aGuard;
2026     IsObjectValid();
2027     Point aPoint;
2028     ScGridWindow* pWin = static_cast<ScGridWindow*>(mpViewShell->GetWindowByPos(meSplitPos));
2029     if (pWin)
2030     {
2031         aPoint = pWin->LogicToPixel(rPoint, pWin->GetDrawMapMode());
2032         aPoint += pWin->GetWindowExtentsRelative(nullptr).TopLeft();
2033     }
2034     return aPoint;
2035 }
2036 
2037 Size ScAccessibleDocument::LogicToPixel (const Size& rSize) const
2038 {
2039     SolarMutexGuard aGuard;
2040     IsObjectValid();
2041     Size aSize;
2042     ScGridWindow* pWin = static_cast<ScGridWindow*>(mpViewShell->GetWindowByPos(meSplitPos));
2043     if (pWin)
2044         aSize = pWin->LogicToPixel(rSize, pWin->GetDrawMapMode());
2045     return aSize;
2046 }
2047 
2048     //=====  internal  ========================================================
2049 
2050 utl::AccessibleRelationSetHelper* ScAccessibleDocument::GetRelationSet(const ScAddress* pAddress) const
2051 {
2052     utl::AccessibleRelationSetHelper* pRelationSet = nullptr;
2053     if (mpChildrenShapes)
2054         pRelationSet = mpChildrenShapes->GetRelationSet(pAddress);
2055     return pRelationSet;
2056 }
2057 
2058 OUString
2059     ScAccessibleDocument::createAccessibleDescription()
2060 {
2061     OUString sDescription = STR_ACC_DOC_DESCR;
2062     return sDescription;
2063 }
2064 
2065 OUString
2066     ScAccessibleDocument::createAccessibleName()
2067 {
2068     SolarMutexGuard aGuard;
2069     IsObjectValid();
2070     OUString sName = ScResId(STR_ACC_DOC_NAME);
2071     sal_Int32 nNumber(sal_Int32(meSplitPos) + 1);
2072     sName += OUString::number(nNumber);
2073     return sName;
2074 }
2075 
2076 tools::Rectangle ScAccessibleDocument::GetBoundingBoxOnScreen() const
2077 {
2078     tools::Rectangle aRect;
2079     if (mpViewShell)
2080     {
2081         vcl::Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos);
2082         if (pWindow)
2083             aRect = pWindow->GetWindowExtentsRelative(nullptr);
2084     }
2085     return aRect;
2086 }
2087 
2088 tools::Rectangle ScAccessibleDocument::GetBoundingBox() const
2089 {
2090     tools::Rectangle aRect;
2091     if (mpViewShell)
2092     {
2093         vcl::Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos);
2094         if (pWindow)
2095             aRect = pWindow->GetWindowExtentsRelative(pWindow->GetAccessibleParentWindow());
2096     }
2097     return aRect;
2098 }
2099 
2100 SCTAB ScAccessibleDocument::getVisibleTable() const
2101 {
2102     SCTAB nVisibleTable(0);
2103     if (mpViewShell)
2104         nVisibleTable = mpViewShell->GetViewData().GetTabNo();
2105     return nVisibleTable;
2106 }
2107 
2108 uno::Reference < XAccessible >
2109     ScAccessibleDocument::GetAccessibleSpreadsheet()
2110 {
2111     if (!mpAccessibleSpreadsheet.is() && mpViewShell)
2112     {
2113         mpAccessibleSpreadsheet = new ScAccessibleSpreadsheet(this, mpViewShell, getVisibleTable(), meSplitPos);
2114         mpAccessibleSpreadsheet->Init();
2115         mbCompleteSheetSelected = IsTableSelected();
2116     }
2117     return mpAccessibleSpreadsheet.get();
2118 }
2119 
2120 void ScAccessibleDocument::FreeAccessibleSpreadsheet()
2121 {
2122     if (mpAccessibleSpreadsheet.is())
2123     {
2124         mpAccessibleSpreadsheet->dispose();
2125         mpAccessibleSpreadsheet.clear();
2126     }
2127 }
2128 
2129 bool ScAccessibleDocument::IsTableSelected() const
2130 {
2131     bool bResult (false);
2132     if(mpViewShell)
2133     {
2134         SCTAB nTab(getVisibleTable());
2135         //#103800#; use a copy of MarkData
2136         ScMarkData aMarkData(mpViewShell->GetViewData().GetMarkData());
2137         aMarkData.MarkToMulti();
2138         if (aMarkData.IsAllMarked( ScRange( 0, 0, nTab, MAXCOL, MAXROW, nTab)))
2139             bResult = true;
2140     }
2141     return bResult;
2142 }
2143 
2144 bool ScAccessibleDocument::IsDefunc(
2145     const uno::Reference<XAccessibleStateSet>& rxParentStates)
2146 {
2147     return ScAccessibleContextBase::IsDefunc() || (mpViewShell == nullptr) || !getAccessibleParent().is() ||
2148         (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC));
2149 }
2150 
2151 void ScAccessibleDocument::AddChild(const uno::Reference<XAccessible>& xAcc, bool bFireEvent)
2152 {
2153     OSL_ENSURE(!mxTempAcc.is(), "this object should be removed before");
2154     if (xAcc.is())
2155     {
2156         mxTempAcc = xAcc;
2157         if( bFireEvent )
2158         {
2159             AccessibleEventObject aEvent;
2160             aEvent.Source = uno::Reference<XAccessibleContext>(this);
2161             aEvent.EventId = AccessibleEventId::CHILD;
2162             aEvent.NewValue <<= mxTempAcc;
2163             CommitChange( aEvent );
2164         }
2165     }
2166 }
2167 
2168 void ScAccessibleDocument::RemoveChild(const uno::Reference<XAccessible>& xAcc, bool bFireEvent)
2169 {
2170     OSL_ENSURE(mxTempAcc.is(), "this object should be added before");
2171     if (xAcc.is())
2172     {
2173         OSL_ENSURE(xAcc.get() == mxTempAcc.get(), "only the same object should be removed");
2174         if( bFireEvent )
2175         {
2176             AccessibleEventObject aEvent;
2177             aEvent.Source = uno::Reference<XAccessibleContext>(this);
2178             aEvent.EventId = AccessibleEventId::CHILD;
2179             aEvent.OldValue <<= mxTempAcc;
2180             CommitChange( aEvent );
2181         }
2182         mxTempAcc = nullptr;
2183     }
2184 }
2185 
2186 OUString ScAccessibleDocument::GetCurrentCellName() const
2187 {
2188     OUString sName(ScResId(STR_ACC_CELL_NAME));
2189     if (mpViewShell)
2190     {
2191         // Document not needed, because only the cell address, but not the tablename is needed
2192         OUString sAddress(mpViewShell->GetViewData().GetCurPos().Format(ScRefFlags::VALID));
2193         sName = sName.replaceFirst("%1", sAddress);
2194     }
2195     return sName;
2196 }
2197 
2198 OUString ScAccessibleDocument::GetCurrentCellDescription()
2199 {
2200     return OUString();
2201 }
2202 
2203 ScDocument *ScAccessibleDocument::GetDocument() const
2204 {
2205     return mpViewShell ? mpViewShell->GetViewData().GetDocument() : nullptr;
2206 }
2207 
2208 ScAddress   ScAccessibleDocument::GetCurCellAddress() const
2209 {
2210     return mpViewShell ? mpViewShell->GetViewData().GetCurPos() : ScAddress();
2211 }
2212 
2213 uno::Any SAL_CALL ScAccessibleDocument::getExtendedAttributes()
2214 {
2215     SolarMutexGuard g;
2216 
2217     uno::Any anyAtrribute;
2218 
2219     OUString sName;
2220     OUString sValue;
2221     sal_uInt16 sheetIndex;
2222     OUString sSheetName;
2223     sheetIndex = getVisibleTable();
2224     if(GetDocument()==nullptr)
2225         return anyAtrribute;
2226     GetDocument()->GetName(sheetIndex,sSheetName);
2227     sName = "page-name:";
2228     sValue = sName + sSheetName ;
2229     sName = ";page-number:";
2230     sValue += sName;
2231     sValue += OUString::number(sheetIndex+1) ;
2232     sName = ";total-pages:";
2233     sValue += sName;
2234     sValue += OUString::number(GetDocument()->GetTableCount());
2235     sValue += ";";
2236     anyAtrribute <<= sValue;
2237     return anyAtrribute;
2238 }
2239 
2240 css::uno::Sequence< css::uno::Any > ScAccessibleDocument::GetScAccFlowToSequence()
2241 {
2242     if ( getAccessibleChildCount() )
2243     {
2244         uno::Reference < XAccessible > xSCTableAcc = getAccessibleChild( 0 ); // table
2245         if ( xSCTableAcc.is() )
2246         {
2247             uno::Reference < XAccessibleSelection > xAccSelection( xSCTableAcc, uno::UNO_QUERY );
2248             sal_Int32 nSelCount = xAccSelection->getSelectedAccessibleChildCount();
2249             if( nSelCount )
2250             {
2251                 uno::Reference < XAccessible > xSel = xAccSelection->getSelectedAccessibleChild( 0 ); // selected cell
2252                 if ( xSel.is() )
2253                 {
2254                     uno::Reference < XAccessibleContext > xSelContext( xSel->getAccessibleContext() );
2255                     if ( xSelContext.is() )
2256                     {
2257                         if ( xSelContext->getAccessibleRole() == AccessibleRole::TABLE_CELL )
2258                         {
2259                             sal_Int32 nParaCount = 0;
2260                             uno::Sequence <uno::Any> aSequence(nSelCount);
2261                             for ( sal_Int32 i = 0; i < nSelCount; i++ )
2262                             {
2263                                 xSel = xAccSelection->getSelectedAccessibleChild( i )   ;
2264                                 if ( xSel.is() )
2265                                 {
2266                                     xSelContext = xSel->getAccessibleContext();
2267                                     if ( xSelContext.is() )
2268                                     {
2269                                         if ( xSelContext->getAccessibleRole() == AccessibleRole::TABLE_CELL )
2270                                         {
2271                                             aSequence[nParaCount] <<= xSel;
2272                                             nParaCount++;
2273                                         }
2274                                     }
2275                                 }
2276                             }
2277                             return aSequence;
2278                         }
2279                     }
2280                 }
2281             }
2282         }
2283     }
2284     uno::Sequence <uno::Any> aEmpty;
2285     return aEmpty;
2286 }
2287 
2288 css::uno::Sequence< css::uno::Any >
2289         SAL_CALL ScAccessibleDocument::getAccFlowTo(const css::uno::Any& rAny, sal_Int32 nType)
2290 {
2291     SolarMutexGuard g;
2292 
2293     const sal_Int32 SPELLCHECKFLOWTO = 1;
2294     const sal_Int32 FINDREPLACEFLOWTO = 2;
2295     if ( nType == SPELLCHECKFLOWTO )
2296     {
2297         uno::Reference< css::drawing::XShape > xShape;
2298         rAny >>= xShape;
2299         if ( xShape.is() )
2300         {
2301             uno::Reference < XAccessible > xAcc = mpChildrenShapes->GetAccessibleCaption(xShape);
2302             uno::Reference < XAccessibleSelection > xAccSelection( xAcc, uno::UNO_QUERY );
2303             if ( xAccSelection.is() )
2304             {
2305                 if ( xAccSelection->getSelectedAccessibleChildCount() )
2306                 {
2307                     uno::Reference < XAccessible > xSel = xAccSelection->getSelectedAccessibleChild( 0 );
2308                     if ( xSel.is() )
2309                     {
2310                         uno::Reference < XAccessibleContext > xSelContext( xSel->getAccessibleContext() );
2311                         if ( xSelContext.is() )
2312                         {
2313                             //if in sw we find the selected paragraph here
2314                             if ( xSelContext->getAccessibleRole() == AccessibleRole::PARAGRAPH )
2315                             {
2316                                 uno::Sequence<uno::Any> aRet( 1 );
2317                                 aRet[0] <<= xSel;
2318                                 return aRet;
2319                             }
2320                         }
2321                     }
2322                 }
2323             }
2324         }
2325         else
2326         {
2327             if ( getSelectedAccessibleChildCount() )
2328             {
2329                 uno::Reference < XAccessible > xSel = getSelectedAccessibleChild( 0 );
2330                 if ( xSel.is() )
2331                 {
2332                     uno::Reference < XAccessibleContext > xSelContext( xSel->getAccessibleContext() );
2333                     if ( xSelContext.is() )
2334                     {
2335                         uno::Reference < XAccessibleSelection > xAccChildSelection( xSel, uno::UNO_QUERY );
2336                         if ( xAccChildSelection.is() )
2337                         {
2338                             if ( xAccChildSelection->getSelectedAccessibleChildCount() )
2339                             {
2340                                 uno::Reference < XAccessible > xChildSel = xAccChildSelection->getSelectedAccessibleChild( 0 );
2341                                 if ( xChildSel.is() )
2342                                 {
2343                                     uno::Reference < css::accessibility::XAccessibleContext > xChildSelContext( xChildSel->getAccessibleContext() );
2344                                     if ( xChildSelContext.is() &&
2345                                         xChildSelContext->getAccessibleRole() == css::accessibility::AccessibleRole::PARAGRAPH )
2346                                     {
2347                                         uno::Sequence<uno::Any> aRet( 1 );
2348                                         aRet[0] <<= xChildSel;
2349                                         return aRet;
2350                                     }
2351                                 }
2352                             }
2353                         }
2354                     }
2355                 }
2356             }
2357         }
2358     }
2359     else if ( nType == FINDREPLACEFLOWTO )
2360     {
2361         bool bSuccess(false);
2362         rAny >>= bSuccess;
2363         if ( bSuccess )
2364         {
2365             uno::Sequence< uno::Any> aSeq = GetScAccFlowToSequence();
2366             if ( aSeq.hasElements() )
2367             {
2368                 return aSeq;
2369             }
2370             else if( mpAccessibleSpreadsheet.is() )
2371             {
2372                 uno::Reference < XAccessible > xFindCellAcc = mpAccessibleSpreadsheet->GetActiveCell();
2373                 // add xFindCellAcc to the return the Sequence
2374                 uno::Sequence< uno::Any> aSeq2(1);
2375                 aSeq2[0] <<= xFindCellAcc;
2376                 return aSeq2;
2377             }
2378         }
2379     }
2380     uno::Sequence< uno::Any> aEmpty;
2381     return aEmpty;
2382 }
2383 
2384 sal_Int32 SAL_CALL ScAccessibleDocument::getForeground(  )
2385 {
2386     return sal_Int32(COL_BLACK);
2387 }
2388 
2389 sal_Int32 SAL_CALL ScAccessibleDocument::getBackground(  )
2390 {
2391     SolarMutexGuard aGuard;
2392     IsObjectValid();
2393     return sal_Int32(SC_MOD()->GetColorConfig().GetColorValue( ::svtools::DOCCOLOR ).nColor);
2394 }
2395 
2396 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2397