nss: upgrade to release 3.73
[LibreOffice.git] / sc / source / ui / Accessibility / AccessibleDocument.cxx
blob1015063d1ce29b097afda70d9efeb61c15128c43
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <AccessibleDocument.hxx>
21 #include <AccessibleSpreadsheet.hxx>
22 #include <tabvwsh.hxx>
23 #include <AccessibilityHints.hxx>
24 #include <document.hxx>
25 #include <drwlayer.hxx>
26 #include <DrawModelBroadcaster.hxx>
27 #include <drawview.hxx>
28 #include <gridwin.hxx>
29 #include <AccessibleEditObject.hxx>
30 #include <userdat.hxx>
31 #include <scresid.hxx>
32 #include <strings.hrc>
33 #include <strings.hxx>
34 #include <markdata.hxx>
36 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
37 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
38 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
39 #include <com/sun/star/accessibility/AccessibleRole.hpp>
40 #include <com/sun/star/view/XSelectionSupplier.hpp>
41 #include <com/sun/star/drawing/ShapeCollection.hpp>
42 #include <com/sun/star/drawing/XShape.hpp>
43 #include <com/sun/star/drawing/XShapes.hpp>
44 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
45 #include <o3tl/safeint.hxx>
46 #include <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>
63 #include <svx/AccessibleControlShape.hxx>
64 #include <svx/SvxShapeTypes.hxx>
65 #include <sfx2/objsh.hxx>
66 #include <editeng/editview.hxx>
67 #include <editeng/editeng.hxx>
68 #include <comphelper/processfactory.hxx>
70 #include <algorithm>
72 #include <svx/unoapi.hxx>
73 #include <scmod.hxx>
75 #ifdef indices
76 #undef indices
77 #endif
79 #ifdef extents
80 #undef extents
81 #endif
83 using namespace ::com::sun::star;
84 using namespace ::com::sun::star::accessibility;
86 //===== internal ========================================================
88 namespace {
90 struct ScAccessibleShapeData
92 ScAccessibleShapeData(css::uno::Reference< css::drawing::XShape > xShape_);
93 ~ScAccessibleShapeData();
94 mutable rtl::Reference< ::accessibility::AccessibleShape > pAccShape;
95 mutable std::optional<ScAddress> xRelationCell; // if it is NULL this shape is anchored on the table
96 css::uno::Reference< css::drawing::XShape > xShape;
97 mutable bool bSelected;
98 bool bSelectable;
99 // cache these to make the sorting cheaper
100 std::optional<sal_Int16> mxLayerID;
101 std::optional<sal_Int32> mxZOrder;
106 ScAccessibleShapeData::ScAccessibleShapeData(css::uno::Reference< css::drawing::XShape > xShape_)
107 : xShape(xShape_),
108 bSelected(false), bSelectable(true)
110 static constexpr OUStringLiteral gsLayerId = u"LayerID";
111 static constexpr OUStringLiteral gsZOrder = u"ZOrder";
112 uno::Reference< beans::XPropertySet> xProps(xShape, uno::UNO_QUERY);
113 if (xProps.is())
115 uno::Any aAny = xProps->getPropertyValue(gsLayerId);
116 sal_Int16 nLayerID;
117 if (aAny >>= nLayerID)
118 mxLayerID = nLayerID;
119 sal_Int32 nZOrder;
120 aAny = xProps->getPropertyValue(gsZOrder);
121 if (aAny >>= nZOrder)
122 mxZOrder = nZOrder;
126 ScAccessibleShapeData::~ScAccessibleShapeData()
128 if (pAccShape.is())
130 pAccShape->dispose();
134 namespace {
136 struct ScShapeDataLess
138 static void ConvertLayerId(sal_Int16& rLayerID) // changes the number of the LayerId so it the accessibility order
140 // note: MSVC 2017 ICE's if this is written as "switch" so use "if"
141 if (sal_uInt8(SC_LAYER_FRONT) == rLayerID)
143 rLayerID = 1;
145 else if (sal_uInt8(SC_LAYER_BACK) == rLayerID)
147 rLayerID = 0;
149 else if (sal_uInt8(SC_LAYER_INTERN) == rLayerID)
151 rLayerID = 2;
153 else if (sal_uInt8(SC_LAYER_CONTROLS) == rLayerID)
155 rLayerID = 3;
158 static bool LessThanSheet(const ScAccessibleShapeData* pData)
160 bool bResult(false);
161 if (pData->mxLayerID)
163 if (SdrLayerID(*pData->mxLayerID) == SC_LAYER_BACK)
164 bResult = true;
166 return bResult;
168 bool operator()(const ScAccessibleShapeData* pData1, const ScAccessibleShapeData* pData2) const
170 bool bResult(false);
171 if (pData1 && pData2)
173 if( pData1->mxLayerID && pData2->mxLayerID )
175 sal_Int16 nLayerID1 = *pData1->mxLayerID;
176 sal_Int16 nLayerID2 = *pData2->mxLayerID;
177 if (nLayerID1 == nLayerID2)
179 if ( pData1->mxZOrder && pData2->mxZOrder )
180 bResult = (*pData1->mxZOrder < *pData2->mxZOrder);
182 else
184 ConvertLayerId(nLayerID1);
185 ConvertLayerId(nLayerID2);
186 bResult = (nLayerID1 < nLayerID2);
190 else if (pData1 && !pData2)
191 bResult = LessThanSheet(pData1);
192 else if (!pData1 && pData2)
193 bResult = !LessThanSheet(pData2);
194 else
195 bResult = false;
196 return bResult;
202 class ScChildrenShapes : public SfxListener,
203 public ::accessibility::IAccessibleParent
205 public:
206 ScChildrenShapes(ScAccessibleDocument* pAccessibleDocument, ScTabViewShell* pViewShell, ScSplitPos eSplitPos);
207 virtual ~ScChildrenShapes() override;
209 ///===== SfxListener =====================================================
211 virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
213 ///===== IAccessibleParent ===============================================
215 virtual bool ReplaceChild (
216 ::accessibility::AccessibleShape* pCurrentChild,
217 const css::uno::Reference< css::drawing::XShape >& _rxShape,
218 const tools::Long _nIndex,
219 const ::accessibility::AccessibleShapeTreeInfo& _rShapeTreeInfo
220 ) override;
222 virtual ::accessibility::AccessibleControlShape* GetAccControlShapeFromModel
223 (css::beans::XPropertySet* pSet) override;
224 virtual css::uno::Reference< css::accessibility::XAccessible>
225 GetAccessibleCaption (const css::uno::Reference<css::drawing::XShape>& xShape) override;
226 ///===== Internal ========================================================
227 void SetDrawBroadcaster();
229 sal_Int32 GetCount() const;
230 uno::Reference< XAccessible > Get(const ScAccessibleShapeData* pData) const;
231 uno::Reference< XAccessible > Get(sal_Int32 nIndex) const;
232 uno::Reference< XAccessible > GetAt(const awt::Point& rPoint) const;
234 // gets the index of the shape starting on 0 (without the index of the table)
235 // returns the selected shape
236 bool IsSelected(sal_Int32 nIndex,
237 css::uno::Reference<css::drawing::XShape>& rShape) const;
239 bool SelectionChanged();
241 void Select(sal_Int32 nIndex);
242 void DeselectAll(); // deselect also the table
243 void SelectAll();
244 sal_Int32 GetSelectedCount() const;
245 uno::Reference< XAccessible > GetSelected(sal_Int32 nSelectedChildIndex, bool bTabSelected) const;
246 void Deselect(sal_Int32 nChildIndex);
248 SdrPage* GetDrawPage() const;
250 utl::AccessibleRelationSetHelper* GetRelationSet(const ScAddress* pAddress) const;
252 void VisAreaChanged() const;
253 private:
254 typedef std::vector<ScAccessibleShapeData*> SortedShapes;
255 typedef std::unordered_map<css::uno::Reference< css::drawing::XShape >, ScAccessibleShapeData*> ShapesMap;
257 mutable SortedShapes maZOrderedShapes; // a null pointer represents the sheet in the correct order
258 mutable ShapesMap maShapesMap;
259 mutable bool mbShapesNeedSorting; // set if maZOrderedShapes needs sorting
261 mutable ::accessibility::AccessibleShapeTreeInfo maShapeTreeInfo;
262 mutable css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier;
263 mutable size_t mnSdrObjCount;
264 mutable sal_uInt32 mnShapesSelected;
265 ScTabViewShell* mpViewShell;
266 ScAccessibleDocument* mpAccessibleDocument;
267 ScSplitPos meSplitPos;
269 void FillShapes(std::vector < uno::Reference < drawing::XShape > >& rShapes) const;
270 bool FindSelectedShapesChanges(const css::uno::Reference<css::drawing::XShapes>& xShapes) const;
272 std::optional<ScAddress> GetAnchor(const uno::Reference<drawing::XShape>& xShape) const;
273 uno::Reference<XAccessibleRelationSet> GetRelationSet(const ScAccessibleShapeData* pData) const;
274 void SetAnchor(const uno::Reference<drawing::XShape>& xShape, ScAccessibleShapeData* pData) const;
275 void AddShape(const uno::Reference<drawing::XShape>& xShape, bool bCommitChange) const;
276 void RemoveShape(const uno::Reference<drawing::XShape>& xShape) const;
278 bool FindShape(const uno::Reference<drawing::XShape>& xShape, SortedShapes::iterator& rItr) const;
280 static sal_Int8 Compare(const ScAccessibleShapeData* pData1,
281 const ScAccessibleShapeData* pData2);
284 ScChildrenShapes::ScChildrenShapes(ScAccessibleDocument* pAccessibleDocument, ScTabViewShell* pViewShell, ScSplitPos eSplitPos)
286 mbShapesNeedSorting(false),
287 mnShapesSelected(0),
288 mpViewShell(pViewShell),
289 mpAccessibleDocument(pAccessibleDocument),
290 meSplitPos(eSplitPos)
292 if (mpViewShell)
294 SfxViewFrame* pViewFrame = mpViewShell->GetViewFrame();
295 if (pViewFrame)
297 xSelectionSupplier = uno::Reference<view::XSelectionSupplier>(pViewFrame->GetFrame().GetController(), uno::UNO_QUERY);
298 if (xSelectionSupplier.is())
300 xSelectionSupplier->addSelectionChangeListener(mpAccessibleDocument);
301 uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
302 if (xShapes.is())
303 mnShapesSelected = xShapes->getCount();
308 maZOrderedShapes.push_back(nullptr); // add an element which represents the table
310 GetCount(); // fill list with filtered shapes (no internal shapes)
312 if (mnShapesSelected)
314 //set flag on every selected shape
315 if (!xSelectionSupplier.is())
316 throw uno::RuntimeException();
318 uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
319 if (xShapes.is())
320 FindSelectedShapesChanges(xShapes);
322 if (!pViewShell)
323 return;
325 ScViewData& rViewData = pViewShell->GetViewData();
326 SfxBroadcaster* pDrawBC = rViewData.GetDocument().GetDrawBroadcaster();
327 if (pDrawBC)
329 StartListening(*pDrawBC);
331 maShapeTreeInfo.SetModelBroadcaster( new ScDrawModelBroadcaster(rViewData.GetDocument().GetDrawLayer()) );
332 maShapeTreeInfo.SetSdrView(rViewData.GetScDrawView());
333 maShapeTreeInfo.SetController(nullptr);
334 maShapeTreeInfo.SetDevice(pViewShell->GetWindowByPos(meSplitPos));
335 maShapeTreeInfo.SetViewForwarder(mpAccessibleDocument);
339 ScChildrenShapes::~ScChildrenShapes()
341 for (ScAccessibleShapeData* pShapeData : maZOrderedShapes)
342 delete pShapeData;
343 if (mpViewShell)
345 SfxBroadcaster* pDrawBC = mpViewShell->GetViewData().GetDocument().GetDrawBroadcaster();
346 if (pDrawBC)
347 EndListening(*pDrawBC);
349 if (mpAccessibleDocument && xSelectionSupplier.is())
350 xSelectionSupplier->removeSelectionChangeListener(mpAccessibleDocument);
353 void ScChildrenShapes::SetDrawBroadcaster()
355 if (!mpViewShell)
356 return;
358 ScViewData& rViewData = mpViewShell->GetViewData();
359 SfxBroadcaster* pDrawBC = rViewData.GetDocument().GetDrawBroadcaster();
360 if (pDrawBC)
362 StartListening(*pDrawBC, DuplicateHandling::Prevent);
364 maShapeTreeInfo.SetModelBroadcaster( new ScDrawModelBroadcaster(rViewData.GetDocument().GetDrawLayer()) );
365 maShapeTreeInfo.SetSdrView(rViewData.GetScDrawView());
366 maShapeTreeInfo.SetController(nullptr);
367 maShapeTreeInfo.SetDevice(mpViewShell->GetWindowByPos(meSplitPos));
368 maShapeTreeInfo.SetViewForwarder(mpAccessibleDocument);
372 void ScChildrenShapes::Notify(SfxBroadcaster&, const SfxHint& rHint)
374 if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint)
375 return;
376 const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
378 SdrObject* pObj = const_cast<SdrObject*>(pSdrHint->GetObject());
379 if (!(pObj && /*(pObj->GetLayer() != SC_LAYER_INTERN) && */(pObj->getSdrPageFromSdrObject() == GetDrawPage()) &&
380 (pObj->getSdrPageFromSdrObject() == pObj->getParentSdrObjListFromSdrObject())) ) //only do something if the object lies direct on the page
381 return;
383 switch (pSdrHint->GetKind())
385 case SdrHintKind::ObjectChange : // object changed
387 uno::Reference<drawing::XShape> xShape (pObj->getUnoShape(), uno::UNO_QUERY);
388 if (xShape.is())
390 mbShapesNeedSorting = true; // sort, because the z index or layer could be changed
391 auto it = maShapesMap.find(xShape);
392 if (it != maShapesMap.end())
393 SetAnchor(xShape, it->second);
396 break;
397 case SdrHintKind::ObjectInserted : // new drawing object inserted
399 uno::Reference<drawing::XShape> xShape (pObj->getUnoShape(), uno::UNO_QUERY);
400 if (xShape.is())
401 AddShape(xShape, true);
403 break;
404 case SdrHintKind::ObjectRemoved : // Removed drawing object from list
406 uno::Reference<drawing::XShape> xShape (pObj->getUnoShape(), uno::UNO_QUERY);
407 if (xShape.is())
408 RemoveShape(xShape);
410 break;
411 default :
413 // other events are not interesting
415 break;
419 bool ScChildrenShapes::ReplaceChild (::accessibility::AccessibleShape* pCurrentChild,
420 const css::uno::Reference< css::drawing::XShape >& _rxShape,
421 const tools::Long /*_nIndex*/, const ::accessibility::AccessibleShapeTreeInfo& _rShapeTreeInfo)
423 // create the new child
424 rtl::Reference< ::accessibility::AccessibleShape > pReplacement(::accessibility::ShapeTypeHandler::Instance().CreateAccessibleObject (
425 ::accessibility::AccessibleShapeInfo ( _rxShape, pCurrentChild->getAccessibleParent(), this ),
426 _rShapeTreeInfo
429 bool bResult(false);
430 if (pReplacement.is())
432 OSL_ENSURE(pCurrentChild->GetXShape().get() == pReplacement->GetXShape().get(), "XShape changes and should be inserted sorted");
433 auto it = maShapesMap.find(pCurrentChild->GetXShape());
434 if (it != maShapesMap.end() && it->second->pAccShape.is())
436 OSL_ENSURE(it->second->pAccShape == pCurrentChild, "wrong child found");
437 AccessibleEventObject aEvent;
438 aEvent.EventId = AccessibleEventId::CHILD;
439 aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument);
440 aEvent.OldValue <<= uno::Reference<XAccessible>(pCurrentChild);
442 mpAccessibleDocument->CommitChange(aEvent); // child is gone - event
444 pCurrentChild->dispose();
447 // Init after above possible pCurrentChild->dispose so we don't trigger the assert
448 // ScDrawModelBroadcaster::addShapeEventListener of duplicate listeners
449 pReplacement->Init();
451 if (it != maShapesMap.end())
453 it->second->pAccShape = pReplacement;
454 AccessibleEventObject aEvent;
455 aEvent.EventId = AccessibleEventId::CHILD;
456 aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument);
457 aEvent.NewValue <<= uno::Reference<XAccessible>(pReplacement.get());
459 mpAccessibleDocument->CommitChange(aEvent); // child is new - event
460 bResult = true;
463 return bResult;
466 ::accessibility::AccessibleControlShape * ScChildrenShapes::GetAccControlShapeFromModel(css::beans::XPropertySet* pSet)
468 GetCount(); // populate
469 for (ScAccessibleShapeData* pShape : maZOrderedShapes)
471 if (pShape)
473 rtl::Reference< ::accessibility::AccessibleShape > pAccShape(pShape->pAccShape);
474 if (pAccShape.is() && ::accessibility::ShapeTypeHandler::Instance().GetTypeId (pAccShape->GetXShape()) == ::accessibility::DRAWING_CONTROL)
476 ::accessibility::AccessibleControlShape *pCtlAccShape = static_cast < ::accessibility::AccessibleControlShape* >(pAccShape.get());
477 if (pCtlAccShape && pCtlAccShape->GetControlModel() == pSet)
478 return pCtlAccShape;
482 return nullptr;
485 css::uno::Reference < css::accessibility::XAccessible >
486 ScChildrenShapes::GetAccessibleCaption (const css::uno::Reference < css::drawing::XShape>& xShape)
488 GetCount(); // populate
489 auto it = maShapesMap.find(xShape);
490 if (it == maShapesMap.end())
491 return nullptr;
492 ScAccessibleShapeData* pShape = it->second;
493 css::uno::Reference< css::accessibility::XAccessible > xNewChild( pShape->pAccShape.get() );
494 if(xNewChild)
495 return xNewChild;
496 return nullptr;
499 sal_Int32 ScChildrenShapes::GetCount() const
501 SdrPage* pDrawPage = GetDrawPage();
502 if (pDrawPage && (maZOrderedShapes.size() == 1)) // the table is always in
504 mnSdrObjCount = pDrawPage->GetObjCount();
505 maZOrderedShapes.reserve(mnSdrObjCount + 1); // the table is always in
506 for (size_t i = 0; i < mnSdrObjCount; ++i)
508 SdrObject* pObj = pDrawPage->GetObj(i);
509 if (pObj/* && (pObj->GetLayer() != SC_LAYER_INTERN)*/)
511 uno::Reference< drawing::XShape > xShape (pObj->getUnoShape(), uno::UNO_QUERY);
512 AddShape(xShape, false); //inserts in the correct order
516 return maZOrderedShapes.size();
519 uno::Reference< XAccessible > ScChildrenShapes::Get(const ScAccessibleShapeData* pData) const
521 if (!pData)
522 return nullptr;
524 if (!pData->pAccShape.is())
526 ::accessibility::ShapeTypeHandler& rShapeHandler = ::accessibility::ShapeTypeHandler::Instance();
527 ::accessibility::AccessibleShapeInfo aShapeInfo(pData->xShape, mpAccessibleDocument, const_cast<ScChildrenShapes*>(this));
528 pData->pAccShape = rShapeHandler.CreateAccessibleObject(
529 aShapeInfo, maShapeTreeInfo);
530 if (pData->pAccShape.is())
532 pData->pAccShape->Init();
533 if (pData->bSelected)
534 pData->pAccShape->SetState(AccessibleStateType::SELECTED);
535 if (!pData->bSelectable)
536 pData->pAccShape->ResetState(AccessibleStateType::SELECTABLE);
537 pData->pAccShape->SetRelationSet(GetRelationSet(pData));
540 return pData->pAccShape.get();
543 uno::Reference< XAccessible > ScChildrenShapes::Get(sal_Int32 nIndex) const
545 if (maZOrderedShapes.size() <= 1)
546 GetCount(); // fill list with filtered shapes (no internal shapes)
548 if (mbShapesNeedSorting)
550 std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
551 mbShapesNeedSorting = false;
554 if (o3tl::make_unsigned(nIndex) >= maZOrderedShapes.size())
555 return nullptr;
557 return Get(maZOrderedShapes[nIndex]);
560 uno::Reference< XAccessible > ScChildrenShapes::GetAt(const awt::Point& rPoint) const
562 uno::Reference<XAccessible> xAccessible;
563 if(mpViewShell)
565 if (mbShapesNeedSorting)
567 std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
568 mbShapesNeedSorting = false;
571 sal_Int32 i(maZOrderedShapes.size() - 1);
572 bool bFound(false);
573 while (!bFound && i >= 0)
575 ScAccessibleShapeData* pShape = maZOrderedShapes[i];
576 if (pShape)
578 if (!pShape->pAccShape.is())
579 Get(pShape);
581 if (pShape->pAccShape.is())
583 Point aPoint(VCLPoint(rPoint));
584 aPoint -= VCLRectangle(pShape->pAccShape->getBounds()).TopLeft();
585 if (pShape->pAccShape->containsPoint(AWTPoint(aPoint)))
587 xAccessible = pShape->pAccShape.get();
588 bFound = true;
591 else
593 OSL_FAIL("I should have an accessible shape now!");
596 else
597 bFound = true; // this is the sheet and it lies before the rest of the shapes which are background shapes
599 --i;
602 return xAccessible;
605 bool ScChildrenShapes::IsSelected(sal_Int32 nIndex,
606 uno::Reference<drawing::XShape>& rShape) const
608 bool bResult (false);
609 if (maZOrderedShapes.size() <= 1)
610 GetCount(); // fill list with filtered shapes (no internal shapes)
612 if (!xSelectionSupplier.is())
613 throw uno::RuntimeException();
615 if (mbShapesNeedSorting)
617 std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
618 mbShapesNeedSorting = false;
621 if (!maZOrderedShapes[nIndex])
622 return false;
624 bResult = maZOrderedShapes[nIndex]->bSelected;
625 rShape = maZOrderedShapes[nIndex]->xShape;
627 #if OSL_DEBUG_LEVEL > 0 // test whether it is truly selected by a slower method
628 uno::Reference< drawing::XShape > xReturnShape;
629 bool bDebugResult(false);
630 uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
632 if (xShapes.is())
634 sal_Int32 nCount(xShapes->getCount());
635 if (nCount)
637 uno::Reference< drawing::XShape > xShape;
638 uno::Reference< drawing::XShape > xIndexShape = maZOrderedShapes[nIndex]->xShape;
639 sal_Int32 i(0);
640 while (!bDebugResult && (i < nCount))
642 xShapes->getByIndex(i) >>= xShape;
643 if (xShape.is() && (xIndexShape.get() == xShape.get()))
645 bDebugResult = true;
646 xReturnShape = xShape;
648 else
649 ++i;
653 OSL_ENSURE((bResult == bDebugResult) && ((bResult && (rShape.get() == xReturnShape.get())) || !bResult), "found the wrong shape or result");
654 #endif
656 return bResult;
659 bool ScChildrenShapes::SelectionChanged()
661 bool bResult(false);
662 if (!xSelectionSupplier.is())
663 throw uno::RuntimeException();
665 uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
667 bResult = FindSelectedShapesChanges(xShapes);
669 return bResult;
672 void ScChildrenShapes::Select(sal_Int32 nIndex)
674 if (maZOrderedShapes.size() <= 1)
675 GetCount(); // fill list with filtered shapes (no internal shapes)
677 if (!xSelectionSupplier.is())
678 throw uno::RuntimeException();
680 if (mbShapesNeedSorting)
682 std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
683 mbShapesNeedSorting = false;
686 if (!maZOrderedShapes[nIndex])
687 return;
689 uno::Reference<drawing::XShape> xShape;
690 if (IsSelected(nIndex, xShape) || !maZOrderedShapes[nIndex]->bSelectable)
691 return;
693 uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
695 if (!xShapes.is())
696 xShapes = drawing::ShapeCollection::create(
697 comphelper::getProcessComponentContext());
699 xShapes->add(maZOrderedShapes[nIndex]->xShape);
703 xSelectionSupplier->select(uno::makeAny(xShapes));
704 maZOrderedShapes[nIndex]->bSelected = true;
705 if (maZOrderedShapes[nIndex]->pAccShape.is())
706 maZOrderedShapes[nIndex]->pAccShape->SetState(AccessibleStateType::SELECTED);
708 catch (lang::IllegalArgumentException&)
713 void ScChildrenShapes::DeselectAll()
715 if (!xSelectionSupplier.is())
716 throw uno::RuntimeException();
718 bool bSomethingSelected(true);
721 xSelectionSupplier->select(uno::Any()); //deselects all
723 catch (lang::IllegalArgumentException&)
725 OSL_FAIL("nothing selected before");
726 bSomethingSelected = false;
729 if (bSomethingSelected)
730 for (const ScAccessibleShapeData* pAccShapeData : maZOrderedShapes)
731 if (pAccShapeData)
733 pAccShapeData->bSelected = false;
734 if (pAccShapeData->pAccShape.is())
735 pAccShapeData->pAccShape->ResetState(AccessibleStateType::SELECTED);
740 void ScChildrenShapes::SelectAll()
742 if (!xSelectionSupplier.is())
743 throw uno::RuntimeException();
745 if (maZOrderedShapes.size() <= 1)
746 GetCount(); // fill list with filtered shapes (no internal shapes)
748 if (maZOrderedShapes.size() <= 1)
749 return;
751 uno::Reference<drawing::XShapes> xShapes = drawing::ShapeCollection::create(
752 comphelper::getProcessComponentContext());
756 for (const ScAccessibleShapeData* pAccShapeData : maZOrderedShapes)
758 if (pAccShapeData && pAccShapeData->bSelectable)
760 pAccShapeData->bSelected = true;
761 if (pAccShapeData->pAccShape.is())
762 pAccShapeData->pAccShape->SetState(AccessibleStateType::SELECTED);
763 if (xShapes.is())
764 xShapes->add(pAccShapeData->xShape);
767 xSelectionSupplier->select(uno::makeAny(xShapes));
769 catch (lang::IllegalArgumentException&)
771 SelectionChanged(); // find all selected shapes and set the flags
775 void ScChildrenShapes::FillShapes(std::vector < uno::Reference < drawing::XShape > >& rShapes) const
777 uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
778 if (xShapes.is())
780 sal_uInt32 nCount(xShapes->getCount());
781 for (sal_uInt32 i = 0; i < nCount; ++i)
783 uno::Reference<drawing::XShape> xShape;
784 xShapes->getByIndex(i) >>= xShape;
785 if (xShape.is())
786 rShapes.push_back(xShape);
791 sal_Int32 ScChildrenShapes::GetSelectedCount() const
793 if (!xSelectionSupplier.is())
794 throw uno::RuntimeException();
796 std::vector < uno::Reference < drawing::XShape > > aShapes;
797 FillShapes(aShapes);
799 return aShapes.size();
802 uno::Reference< XAccessible > ScChildrenShapes::GetSelected(sal_Int32 nSelectedChildIndex, bool bTabSelected) const
804 uno::Reference< XAccessible > xAccessible;
806 if (maZOrderedShapes.size() <= 1)
807 GetCount(); // fill list with shapes
809 if (!bTabSelected)
811 std::vector < uno::Reference < drawing::XShape > > aShapes;
812 FillShapes(aShapes);
814 if (nSelectedChildIndex < 0 || o3tl::make_unsigned(nSelectedChildIndex) >= aShapes.size())
815 return xAccessible;
817 SortedShapes::iterator aItr;
818 if (FindShape(aShapes[nSelectedChildIndex], aItr))
819 xAccessible = Get(*aItr);
821 else
823 if (mbShapesNeedSorting)
825 std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
826 mbShapesNeedSorting = false;
828 for(const auto& rpShape : maZOrderedShapes)
830 if (!rpShape || rpShape->bSelected)
832 if (nSelectedChildIndex == 0)
834 if (rpShape)
835 xAccessible = rpShape->pAccShape.get();
836 break;
838 else
839 --nSelectedChildIndex;
844 return xAccessible;
847 void ScChildrenShapes::Deselect(sal_Int32 nChildIndex)
849 uno::Reference<drawing::XShape> xShape;
850 if (!IsSelected(nChildIndex, xShape)) // returns false if it is the sheet
851 return;
853 if (!xShape.is())
854 return;
856 uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
857 if (xShapes.is())
858 xShapes->remove(xShape);
862 xSelectionSupplier->select(uno::makeAny(xShapes));
864 catch (lang::IllegalArgumentException&)
866 OSL_FAIL("something not selectable");
869 maZOrderedShapes[nChildIndex]->bSelected = false;
870 if (maZOrderedShapes[nChildIndex]->pAccShape.is())
871 maZOrderedShapes[nChildIndex]->pAccShape->ResetState(AccessibleStateType::SELECTED);
874 SdrPage* ScChildrenShapes::GetDrawPage() const
876 SCTAB nTab(mpAccessibleDocument->getVisibleTable());
877 SdrPage* pDrawPage = nullptr;
878 if (mpViewShell)
880 ScDocument& rDoc = mpViewShell->GetViewData().GetDocument();
881 if (ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer())
883 if (pDrawLayer->HasObjects() && (pDrawLayer->GetPageCount() > nTab))
884 pDrawPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(static_cast<sal_Int16>(nTab)));
887 return pDrawPage;
890 utl::AccessibleRelationSetHelper* ScChildrenShapes::GetRelationSet(const ScAddress* pAddress) const
892 utl::AccessibleRelationSetHelper* pRelationSet = nullptr;
893 for (const ScAccessibleShapeData* pAccShapeData : maZOrderedShapes)
895 if (pAccShapeData &&
896 ((!pAccShapeData->xRelationCell && !pAddress) ||
897 (pAccShapeData->xRelationCell && pAddress && (*(pAccShapeData->xRelationCell) == *pAddress))))
899 if (!pRelationSet)
900 pRelationSet = new utl::AccessibleRelationSetHelper();
902 AccessibleRelation aRelation;
903 aRelation.TargetSet.realloc(1);
904 aRelation.TargetSet[0] = Get(pAccShapeData);
905 aRelation.RelationType = AccessibleRelationType::CONTROLLER_FOR;
907 pRelationSet->AddRelation(aRelation);
910 return pRelationSet;
913 bool ScChildrenShapes::FindSelectedShapesChanges(const uno::Reference<drawing::XShapes>& xShapes) const
915 bool bResult(false);
916 SortedShapes aShapesList;
917 if (xShapes.is())
919 mnShapesSelected = xShapes->getCount();
920 for (sal_uInt32 i = 0; i < mnShapesSelected; ++i)
922 uno::Reference< drawing::XShape > xShape;
923 xShapes->getByIndex(i) >>= xShape;
924 if (xShape.is())
926 ScAccessibleShapeData* pShapeData = new ScAccessibleShapeData(xShape);
927 aShapesList.push_back(pShapeData);
931 else
932 mnShapesSelected = 0;
933 SdrObject *pFocusedObj = nullptr;
934 if( mnShapesSelected == 1 && aShapesList.size() == 1)
936 pFocusedObj = GetSdrObjectFromXShape(aShapesList[0]->xShape);
938 std::sort(aShapesList.begin(), aShapesList.end(), ScShapeDataLess());
939 SortedShapes vecSelectedShapeAdd;
940 SortedShapes vecSelectedShapeRemove;
941 bool bHasSelect=false;
942 SortedShapes::iterator aXShapesItr(aShapesList.begin());
943 SortedShapes::const_iterator aXShapesEndItr(aShapesList.end());
944 SortedShapes::iterator aDataItr(maZOrderedShapes.begin());
945 SortedShapes::const_iterator aDataEndItr(maZOrderedShapes.end());
946 SortedShapes::const_iterator aFocusedItr = aDataEndItr;
947 while(aDataItr != aDataEndItr)
949 if (*aDataItr) // is it really a shape or only the sheet
951 sal_Int8 nComp(0);
952 if (aXShapesItr == aXShapesEndItr)
953 nComp = -1; // simulate that the Shape is lower, so the selection state will be removed
954 else
955 nComp = Compare(*aDataItr, *aXShapesItr);
956 if (nComp == 0)
958 if (!(*aDataItr)->bSelected)
960 (*aDataItr)->bSelected = true;
961 if ((*aDataItr)->pAccShape.is())
963 (*aDataItr)->pAccShape->SetState(AccessibleStateType::SELECTED);
964 (*aDataItr)->pAccShape->SetState(AccessibleStateType::FOCUSED);
965 bResult = true;
966 vecSelectedShapeAdd.push_back(*aDataItr);
968 aFocusedItr = aDataItr;
970 else
972 bHasSelect = true;
974 ++aDataItr;
975 ++aXShapesItr;
977 else if (nComp < 0)
979 if ((*aDataItr)->bSelected)
981 (*aDataItr)->bSelected = false;
982 if ((*aDataItr)->pAccShape.is())
984 (*aDataItr)->pAccShape->ResetState(AccessibleStateType::SELECTED);
985 (*aDataItr)->pAccShape->ResetState(AccessibleStateType::FOCUSED);
986 bResult = true;
987 vecSelectedShapeRemove.push_back(*aDataItr);
990 ++aDataItr;
992 else
994 OSL_FAIL("here is a selected shape which is not in the childlist");
995 ++aXShapesItr;
996 --mnShapesSelected;
999 else
1000 ++aDataItr;
1002 bool bWinFocus=false;
1003 if (mpViewShell)
1005 ScGridWindow* pWin = static_cast<ScGridWindow*>(mpViewShell->GetWindowByPos(meSplitPos));
1006 if (pWin)
1008 bWinFocus = pWin->HasFocus();
1011 const SdrMarkList* pMarkList = nullptr;
1012 SdrObject* pMarkedObj = nullptr;
1013 bool bIsFocuseMarked = true;
1014 if( mpViewShell && mnShapesSelected == 1 && bWinFocus)
1016 ScDrawView* pScDrawView = mpViewShell->GetViewData().GetScDrawView();
1017 if( pScDrawView )
1019 if( pScDrawView->GetMarkedObjectList().GetMarkCount() == 1 )
1021 pMarkList = &(pScDrawView->GetMarkedObjectList());
1022 pMarkedObj = pMarkList->GetMark(0)->GetMarkedSdrObj();
1023 uno::Reference< drawing::XShape > xMarkedXShape (pMarkedObj->getUnoShape(), uno::UNO_QUERY);
1024 if( aFocusedItr != aDataEndItr &&
1025 (*aFocusedItr)->xShape.is() &&
1026 xMarkedXShape.is() &&
1027 (*aFocusedItr)->xShape != xMarkedXShape )
1028 bIsFocuseMarked = false;
1032 //if ((aFocusedItr != aDataEndItr) && (*aFocusedItr)->pAccShape.is() && (mnShapesSelected == 1))
1033 if ( bIsFocuseMarked && (aFocusedItr != aDataEndItr) && (*aFocusedItr)->pAccShape.is() && (mnShapesSelected == 1) && bWinFocus)
1035 (*aFocusedItr)->pAccShape->SetState(AccessibleStateType::FOCUSED);
1037 else if( pFocusedObj && bWinFocus && pMarkList && pMarkList->GetMarkCount() == 1 && mnShapesSelected == 1 )
1039 if( pMarkedObj )
1041 uno::Reference< drawing::XShape > xMarkedXShape (pMarkedObj->getUnoShape(), uno::UNO_QUERY);
1042 SdrObject* pUpObj = pMarkedObj->getParentSdrObjectFromSdrObject();
1044 if( pMarkedObj == pFocusedObj && pUpObj )
1046 uno::Reference< drawing::XShape > xUpGroupXShape (pUpObj->getUnoShape(), uno::UNO_QUERY);
1047 uno::Reference < XAccessible > xAccGroupShape =
1048 const_cast<ScChildrenShapes*>(this)->GetAccessibleCaption( xUpGroupXShape );
1049 if( xAccGroupShape.is() )
1051 ::accessibility::AccessibleShape* pAccGroupShape =
1052 static_cast< ::accessibility::AccessibleShape* >(xAccGroupShape.get());
1053 if( pAccGroupShape )
1055 sal_Int32 nCount = pAccGroupShape->getAccessibleChildCount();
1056 for( sal_Int32 i = 0; i < nCount; i++ )
1058 uno::Reference<XAccessible> xAccShape = pAccGroupShape->getAccessibleChild(i);
1059 if (xAccShape.is())
1061 ::accessibility::AccessibleShape* pChildAccShape = static_cast< ::accessibility::AccessibleShape* >(xAccShape.get());
1062 uno::Reference< drawing::XShape > xChildShape = pChildAccShape->GetXShape();
1063 if (xChildShape == xMarkedXShape)
1065 pChildAccShape->SetState(AccessibleStateType::FOCUSED);
1067 else
1069 pChildAccShape->ResetState(AccessibleStateType::FOCUSED);
1078 if (vecSelectedShapeAdd.size() >= 10 )
1080 AccessibleEventObject aEvent;
1081 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_WITHIN;
1082 aEvent.Source = uno::Reference< XAccessible >(mpAccessibleDocument);
1083 mpAccessibleDocument->CommitChange(aEvent);
1085 else
1087 for (const auto& rpShape : vecSelectedShapeAdd)
1089 AccessibleEventObject aEvent;
1090 if (bHasSelect)
1092 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_ADD;
1094 else
1096 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED;
1098 aEvent.Source = uno::Reference< XAccessible >(mpAccessibleDocument);
1099 uno::Reference< XAccessible > xChild( rpShape->pAccShape.get());
1100 aEvent.NewValue <<= xChild;
1101 mpAccessibleDocument->CommitChange(aEvent);
1104 for (const auto& rpShape : vecSelectedShapeRemove)
1106 AccessibleEventObject aEvent;
1107 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_REMOVE;
1108 aEvent.Source = uno::Reference< XAccessible >(mpAccessibleDocument);
1109 uno::Reference< XAccessible > xChild( rpShape->pAccShape.get());
1110 aEvent.NewValue <<= xChild;
1111 mpAccessibleDocument->CommitChange(aEvent);
1113 for(ScAccessibleShapeData*& pShapeData : aShapesList)
1115 delete pShapeData;
1116 pShapeData = nullptr;
1118 return bResult;
1121 std::optional<ScAddress> ScChildrenShapes::GetAnchor(const uno::Reference<drawing::XShape>& xShape) const
1123 if (mpViewShell)
1125 SvxShape* pShapeImp = comphelper::getUnoTunnelImplementation<SvxShape>(xShape);
1126 uno::Reference<beans::XPropertySet> xShapeProp(xShape, uno::UNO_QUERY);
1127 if (pShapeImp && xShapeProp.is())
1129 if (SdrObject *pSdrObj = pShapeImp->GetSdrObject())
1131 if (ScDrawObjData *pAnchor = ScDrawLayer::GetObjData(pSdrObj))
1132 return std::optional<ScAddress>(pAnchor->maStart);
1137 return std::optional<ScAddress>();
1140 uno::Reference<XAccessibleRelationSet> ScChildrenShapes::GetRelationSet(const ScAccessibleShapeData* pData) const
1142 utl::AccessibleRelationSetHelper* pRelationSet = new utl::AccessibleRelationSetHelper();
1144 if (pData && mpAccessibleDocument)
1146 uno::Reference<XAccessible> xAccessible = mpAccessibleDocument->GetAccessibleSpreadsheet(); // should be the current table
1147 if (pData->xRelationCell && xAccessible.is())
1149 sal_Int32 nRow = pData->xRelationCell->Row();
1150 sal_Int32 nColumn = pData->xRelationCell->Col();
1151 bool bPositionUnset = nRow == -1 && nColumn == -1;
1152 if (!bPositionUnset)
1154 uno::Reference<XAccessibleTable> xAccTable(xAccessible->getAccessibleContext(), uno::UNO_QUERY);
1155 if (xAccTable.is())
1156 xAccessible = xAccTable->getAccessibleCellAt(nRow, nColumn);
1159 AccessibleRelation aRelation;
1160 aRelation.TargetSet.realloc(1);
1161 aRelation.TargetSet[0] = xAccessible;
1162 aRelation.RelationType = AccessibleRelationType::CONTROLLED_BY;
1163 pRelationSet->AddRelation(aRelation);
1166 return pRelationSet;
1169 void ScChildrenShapes::SetAnchor(const uno::Reference<drawing::XShape>& xShape, ScAccessibleShapeData* pData) const
1171 if (pData)
1173 std::optional<ScAddress> xAddress = GetAnchor(xShape);
1174 if ((xAddress && pData->xRelationCell && (*xAddress != *(pData->xRelationCell))) ||
1175 (!xAddress && pData->xRelationCell) || (xAddress && !pData->xRelationCell))
1177 pData->xRelationCell = xAddress;
1178 if (pData->pAccShape.is())
1179 pData->pAccShape->SetRelationSet(GetRelationSet(pData));
1184 void ScChildrenShapes::AddShape(const uno::Reference<drawing::XShape>& xShape, bool bCommitChange) const
1186 assert( maShapesMap.find(xShape) == maShapesMap.end());
1188 ScAccessibleShapeData* pShape = new ScAccessibleShapeData(xShape);
1189 maZOrderedShapes.push_back(pShape);
1190 mbShapesNeedSorting = true;
1191 maShapesMap[xShape] = pShape;
1192 SetAnchor(xShape, pShape);
1194 uno::Reference< beans::XPropertySet > xShapeProp(xShape, uno::UNO_QUERY);
1195 if (xShapeProp.is())
1197 uno::Any aPropAny = xShapeProp->getPropertyValue("LayerID");
1198 sal_Int16 nLayerID = 0;
1199 if( aPropAny >>= nLayerID )
1201 if( (SdrLayerID(nLayerID) == SC_LAYER_INTERN) || (SdrLayerID(nLayerID) == SC_LAYER_HIDDEN) )
1202 pShape->bSelectable = false;
1203 else
1204 pShape->bSelectable = true;
1208 if (!xSelectionSupplier.is())
1209 throw uno::RuntimeException();
1211 uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
1212 uno::Reference<container::XEnumerationAccess> xEnumAcc(xShapes, uno::UNO_QUERY);
1213 if (xEnumAcc.is())
1215 uno::Reference<container::XEnumeration> xEnum = xEnumAcc->createEnumeration();
1216 if (xEnum.is())
1218 uno::Reference<drawing::XShape> xSelectedShape;
1219 bool bFound(false);
1220 while (!bFound && xEnum->hasMoreElements())
1222 xEnum->nextElement() >>= xSelectedShape;
1223 if (xShape.is() && (xShape.get() == xSelectedShape.get()))
1225 pShape->bSelected = true;
1226 bFound = true;
1231 if (mpAccessibleDocument && bCommitChange)
1233 AccessibleEventObject aEvent;
1234 aEvent.EventId = AccessibleEventId::CHILD;
1235 aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument);
1236 aEvent.NewValue <<= Get(pShape);
1238 mpAccessibleDocument->CommitChange(aEvent); // new child - event
1242 void ScChildrenShapes::RemoveShape(const uno::Reference<drawing::XShape>& xShape) const
1244 if (mbShapesNeedSorting)
1246 std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
1247 mbShapesNeedSorting = false;
1249 SortedShapes::iterator aItr;
1250 if (FindShape(xShape, aItr))
1252 if (mpAccessibleDocument)
1254 uno::Reference<XAccessible> xOldAccessible (Get(*aItr));
1256 delete *aItr;
1257 maShapesMap.erase((*aItr)->xShape);
1258 maZOrderedShapes.erase(aItr);
1260 AccessibleEventObject aEvent;
1261 aEvent.EventId = AccessibleEventId::CHILD;
1262 aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument);
1263 aEvent.OldValue <<= xOldAccessible;
1265 mpAccessibleDocument->CommitChange(aEvent); // child is gone - event
1267 else
1269 delete *aItr;
1270 maShapesMap.erase((*aItr)->xShape);
1271 maZOrderedShapes.erase(aItr);
1274 else
1276 OSL_FAIL("shape was not in internal list");
1280 bool ScChildrenShapes::FindShape(const uno::Reference<drawing::XShape>& xShape, ScChildrenShapes::SortedShapes::iterator& rItr) const
1282 if (mbShapesNeedSorting)
1284 std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
1285 mbShapesNeedSorting = false;
1287 bool bResult(false);
1288 ScAccessibleShapeData aShape(xShape);
1289 rItr = std::lower_bound(maZOrderedShapes.begin(), maZOrderedShapes.end(), &aShape, ScShapeDataLess());
1290 if ((rItr != maZOrderedShapes.end()) && (*rItr != nullptr) && ((*rItr)->xShape.get() == xShape.get()))
1291 bResult = true; // if the shape is found
1293 #if OSL_DEBUG_LEVEL > 0 // test whether it finds truly the correct shape (perhaps it is not really sorted)
1294 SortedShapes::iterator aDebugItr = std::find_if(maZOrderedShapes.begin(), maZOrderedShapes.end(),
1295 [&xShape](const ScAccessibleShapeData* pShape) { return pShape && (pShape->xShape.get() == xShape.get()); });
1296 bool bResult2 = (aDebugItr != maZOrderedShapes.end());
1297 OSL_ENSURE((bResult == bResult2) && ((bResult && (rItr == aDebugItr)) || !bResult), "wrong Shape found");
1298 #endif
1299 return bResult;
1302 sal_Int8 ScChildrenShapes::Compare(const ScAccessibleShapeData* pData1,
1303 const ScAccessibleShapeData* pData2)
1305 ScShapeDataLess aLess;
1307 bool bResult1(aLess(pData1, pData2));
1308 bool bResult2(aLess(pData2, pData1));
1310 sal_Int8 nResult(0);
1311 if (!bResult1 && bResult2)
1312 nResult = 1;
1313 else if (bResult1 && !bResult2)
1314 nResult = -1;
1316 return nResult;
1319 void ScChildrenShapes::VisAreaChanged() const
1321 for (const ScAccessibleShapeData* pAccShapeData: maZOrderedShapes)
1322 if (pAccShapeData && pAccShapeData->pAccShape.is())
1323 pAccShapeData->pAccShape->ViewForwarderChanged();
1326 ScAccessibleDocument::ScAccessibleDocument(
1327 const uno::Reference<XAccessible>& rxParent,
1328 ScTabViewShell* pViewShell,
1329 ScSplitPos eSplitPos)
1330 : ScAccessibleDocumentBase(rxParent),
1331 mpViewShell(pViewShell),
1332 meSplitPos(eSplitPos),
1333 mpTempAccEdit(nullptr),
1334 mbCompleteSheetSelected(false)
1336 maVisArea = GetVisibleArea_Impl();
1339 void ScAccessibleDocument::PreInit()
1341 if (!mpViewShell)
1342 return;
1344 mpViewShell->AddAccessibilityObject(*this);
1345 vcl::Window *pWin = mpViewShell->GetWindowByPos(meSplitPos);
1346 if( pWin )
1348 pWin->AddChildEventListener( LINK( this, ScAccessibleDocument, WindowChildEventListener ));
1349 sal_uInt16 nCount = pWin->GetChildCount();
1350 for( sal_uInt16 i=0; i < nCount; ++i )
1352 vcl::Window *pChildWin = pWin->GetChild( i );
1353 if( pChildWin &&
1354 AccessibleRole::EMBEDDED_OBJECT == pChildWin->GetAccessibleRole() )
1355 AddChild( pChildWin->GetAccessible(), false );
1358 ScViewData& rViewData = mpViewShell->GetViewData();
1359 if (rViewData.HasEditView(meSplitPos))
1361 uno::Reference<XAccessible> xAcc = new ScAccessibleEditObject(this, rViewData.GetEditView(meSplitPos),
1362 mpViewShell->GetWindowByPos(meSplitPos), GetCurrentCellName(), GetCurrentCellDescription(),
1363 ScAccessibleEditObject::CellInEditMode);
1364 AddChild(xAcc, false);
1368 void ScAccessibleDocument::Init()
1370 if(!mpChildrenShapes)
1371 mpChildrenShapes.reset( new ScChildrenShapes(this, mpViewShell, meSplitPos) );
1374 ScAccessibleDocument::~ScAccessibleDocument()
1376 if (!ScAccessibleContextBase::IsDefunc() && !rBHelper.bInDispose)
1378 // increment refcount to prevent double call off dtor
1379 osl_atomic_increment( &m_refCount );
1380 dispose();
1384 void SAL_CALL ScAccessibleDocument::disposing()
1386 SolarMutexGuard aGuard;
1387 FreeAccessibleSpreadsheet();
1388 if (mpViewShell)
1390 vcl::Window *pWin = mpViewShell->GetWindowByPos(meSplitPos);
1391 if( pWin )
1392 pWin->RemoveChildEventListener( LINK( this, ScAccessibleDocument, WindowChildEventListener ));
1394 mpViewShell->RemoveAccessibilityObject(*this);
1395 mpViewShell = nullptr;
1397 mpChildrenShapes.reset();
1399 ScAccessibleDocumentBase::disposing();
1402 void SAL_CALL ScAccessibleDocument::disposing( const lang::EventObject& /* Source */ )
1404 disposing();
1407 //===== SfxListener =====================================================
1409 IMPL_LINK( ScAccessibleDocument, WindowChildEventListener, VclWindowEvent&, rEvent, void )
1411 OSL_ENSURE( rEvent.GetWindow(), "Window???" );
1412 switch ( rEvent.GetId() )
1414 case VclEventId::WindowShow: // send create on show for direct accessible children
1416 vcl::Window* pChildWin = static_cast < vcl::Window * >( rEvent.GetData() );
1417 if( pChildWin && AccessibleRole::EMBEDDED_OBJECT == pChildWin->GetAccessibleRole() )
1419 AddChild( pChildWin->GetAccessible(), true );
1422 break;
1423 case VclEventId::WindowHide: // send destroy on hide for direct accessible children
1425 vcl::Window* pChildWin = static_cast < vcl::Window * >( rEvent.GetData() );
1426 if( pChildWin && AccessibleRole::EMBEDDED_OBJECT == pChildWin->GetAccessibleRole() )
1428 RemoveChild( pChildWin->GetAccessible(), true );
1431 break;
1432 default: break;
1436 void ScAccessibleDocument::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
1438 if (auto pFocusLostHint = dynamic_cast<const ScAccGridWinFocusLostHint*>(&rHint) )
1440 if (pFocusLostHint->GetOldGridWin() == meSplitPos)
1442 if (mxTempAcc.is() && mpTempAccEdit)
1443 mpTempAccEdit->LostFocus();
1444 else if (mpAccessibleSpreadsheet.is())
1445 mpAccessibleSpreadsheet->LostFocus();
1446 else
1447 CommitFocusLost();
1450 else if (auto pFocusGotHint = dynamic_cast<const ScAccGridWinFocusGotHint*>(&rHint) )
1452 if (pFocusGotHint->GetNewGridWin() == meSplitPos)
1454 uno::Reference<XAccessible> xAccessible;
1455 if (mpChildrenShapes)
1457 bool bTabMarked(IsTableSelected());
1458 xAccessible = mpChildrenShapes->GetSelected(0, bTabMarked);
1460 if( xAccessible.is() )
1462 uno::Any aNewValue;
1463 aNewValue<<=AccessibleStateType::FOCUSED;
1464 static_cast< ::accessibility::AccessibleShape* >(xAccessible.get())->
1465 CommitChange(AccessibleEventId::STATE_CHANGED,
1466 aNewValue,
1467 uno::Any() );
1469 else
1471 if (mxTempAcc.is() && mpTempAccEdit)
1472 mpTempAccEdit->GotFocus();
1473 else if (mpAccessibleSpreadsheet.is())
1474 mpAccessibleSpreadsheet->GotFocus();
1475 else
1476 CommitFocusGained();
1480 else
1482 // only notify if child exist, otherwise it is not necessary
1483 if ((rHint.GetId() == SfxHintId::ScAccTableChanged) &&
1484 mpAccessibleSpreadsheet.is())
1486 FreeAccessibleSpreadsheet();
1488 // Shapes / form controls after reload not accessible, rebuild the
1489 // mpChildrenShapes variable.
1490 mpChildrenShapes.reset( new ScChildrenShapes( this, mpViewShell, meSplitPos ) );
1492 AccessibleEventObject aEvent;
1493 aEvent.EventId = AccessibleEventId::INVALIDATE_ALL_CHILDREN;
1494 aEvent.Source = uno::Reference< XAccessibleContext >(this);
1495 CommitChange(aEvent); // all children changed
1497 if (mpAccessibleSpreadsheet.is())
1498 mpAccessibleSpreadsheet->FireFirstCellFocus();
1500 else if (rHint.GetId() == SfxHintId::ScAccMakeDrawLayer)
1502 if (mpChildrenShapes)
1503 mpChildrenShapes->SetDrawBroadcaster();
1505 else if (rHint.GetId() == SfxHintId::ScAccEnterEditMode) // this event comes only on creating edit field of a cell
1507 if (mpViewShell->GetViewData().GetEditActivePart() == meSplitPos)
1509 ScViewData& rViewData = mpViewShell->GetViewData();
1510 const EditEngine* pEditEng = rViewData.GetEditView(meSplitPos)->GetEditEngine();
1511 if (pEditEng && pEditEng->GetUpdateMode())
1513 mpTempAccEdit = new ScAccessibleEditObject(this, rViewData.GetEditView(meSplitPos),
1514 mpViewShell->GetWindowByPos(meSplitPos), GetCurrentCellName(),
1515 ScResId(STR_ACC_EDITLINE_DESCR), ScAccessibleEditObject::CellInEditMode);
1516 uno::Reference<XAccessible> xAcc = mpTempAccEdit;
1518 AddChild(xAcc, true);
1520 if (mpAccessibleSpreadsheet.is())
1521 mpAccessibleSpreadsheet->LostFocus();
1522 else
1523 CommitFocusLost();
1525 mpTempAccEdit->GotFocus();
1529 else if (rHint.GetId() == SfxHintId::ScAccLeaveEditMode)
1531 if (mxTempAcc.is())
1533 if (mpTempAccEdit)
1535 mpTempAccEdit->LostFocus();
1537 RemoveChild(mxTempAcc, true);
1538 if (mpTempAccEdit)
1540 // tdf#125982 a11y use-after-free of editengine by
1541 // ScAccessibleEditObjectTextData living past the
1542 // the editengine of the editview passed in above
1543 // in ScAccEnterEditMode
1544 mpTempAccEdit->dispose();
1545 mpTempAccEdit = nullptr;
1547 if (mpAccessibleSpreadsheet.is() && mpViewShell && mpViewShell->IsActive())
1548 mpAccessibleSpreadsheet->GotFocus();
1549 else if( mpViewShell && mpViewShell->IsActive())
1550 CommitFocusGained();
1553 else if ((rHint.GetId() == SfxHintId::ScAccVisAreaChanged) || (rHint.GetId() == SfxHintId::ScAccWindowResized))
1555 tools::Rectangle aOldVisArea(maVisArea);
1556 maVisArea = GetVisibleArea_Impl();
1558 if (maVisArea != aOldVisArea)
1560 if (maVisArea.GetSize() != aOldVisArea.GetSize())
1562 AccessibleEventObject aEvent;
1563 aEvent.EventId = AccessibleEventId::BOUNDRECT_CHANGED;
1564 aEvent.Source = uno::Reference< XAccessibleContext >(this);
1566 CommitChange(aEvent);
1568 if (mpAccessibleSpreadsheet.is())
1569 mpAccessibleSpreadsheet->BoundingBoxChanged();
1570 if (mpAccessibleSpreadsheet.is() && mpViewShell && mpViewShell->IsActive())
1571 mpAccessibleSpreadsheet->FireFirstCellFocus();
1573 else if (mpAccessibleSpreadsheet.is())
1575 mpAccessibleSpreadsheet->VisAreaChanged();
1577 if (mpChildrenShapes)
1578 mpChildrenShapes->VisAreaChanged();
1583 ScAccessibleDocumentBase::Notify(rBC, rHint);
1586 void SAL_CALL ScAccessibleDocument::selectionChanged( const lang::EventObject& /* aEvent */ )
1588 bool bSelectionChanged(false);
1589 if (mpAccessibleSpreadsheet.is())
1591 bool bOldSelected(mbCompleteSheetSelected);
1592 mbCompleteSheetSelected = IsTableSelected();
1593 if (bOldSelected != mbCompleteSheetSelected)
1595 mpAccessibleSpreadsheet->CompleteSelectionChanged(mbCompleteSheetSelected);
1596 bSelectionChanged = true;
1600 if (mpChildrenShapes && mpChildrenShapes->SelectionChanged())
1601 bSelectionChanged = true;
1603 if (bSelectionChanged)
1605 AccessibleEventObject aEvent;
1606 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED;
1607 aEvent.Source = uno::Reference< XAccessibleContext >(this);
1609 CommitChange(aEvent);
1613 //===== XInterface =====================================================
1615 uno::Any SAL_CALL ScAccessibleDocument::queryInterface( uno::Type const & rType )
1617 uno::Any aAny (ScAccessibleDocumentImpl::queryInterface(rType));
1618 return aAny.hasValue() ? aAny : ScAccessibleContextBase::queryInterface(rType);
1621 void SAL_CALL ScAccessibleDocument::acquire()
1622 throw ()
1624 ScAccessibleContextBase::acquire();
1627 void SAL_CALL ScAccessibleDocument::release()
1628 throw ()
1630 ScAccessibleContextBase::release();
1633 //===== XAccessibleComponent ============================================
1635 uno::Reference< XAccessible > SAL_CALL ScAccessibleDocument::getAccessibleAtPoint(
1636 const awt::Point& rPoint )
1638 uno::Reference<XAccessible> xAccessible;
1639 if (containsPoint(rPoint))
1641 SolarMutexGuard aGuard;
1642 IsObjectValid();
1643 if (mpChildrenShapes)
1644 xAccessible = mpChildrenShapes->GetAt(rPoint);
1645 if(!xAccessible.is())
1647 if (mxTempAcc.is())
1649 uno::Reference< XAccessibleContext > xCont(mxTempAcc->getAccessibleContext());
1650 uno::Reference< XAccessibleComponent > xComp(xCont, uno::UNO_QUERY);
1651 if (xComp.is())
1653 tools::Rectangle aBound(VCLRectangle(xComp->getBounds()));
1654 if (aBound.IsInside(VCLPoint(rPoint)))
1655 xAccessible = mxTempAcc;
1658 if (!xAccessible.is())
1659 xAccessible = GetAccessibleSpreadsheet();
1662 return xAccessible;
1665 void SAL_CALL ScAccessibleDocument::grabFocus( )
1667 SolarMutexGuard aGuard;
1668 IsObjectValid();
1669 if (!getAccessibleParent().is())
1670 return;
1672 uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY);
1673 if (xAccessibleComponent.is())
1675 xAccessibleComponent->grabFocus();
1676 // grab only focus if it does not have the focus and it is not hidden
1677 if (mpViewShell &&
1678 (mpViewShell->GetViewData().GetActivePart() != meSplitPos) &&
1679 mpViewShell->GetWindowByPos(meSplitPos)->IsVisible())
1681 mpViewShell->ActivatePart(meSplitPos);
1686 //===== XAccessibleContext ==============================================
1688 /// Return the number of currently visible children.
1689 sal_Int32 SAL_CALL
1690 ScAccessibleDocument::getAccessibleChildCount()
1692 SolarMutexGuard aGuard;
1693 IsObjectValid();
1694 sal_Int32 nCount(1);
1695 if (mpChildrenShapes)
1696 nCount = mpChildrenShapes->GetCount(); // returns the count of the shapes inclusive the table
1698 if (mxTempAcc.is())
1699 ++nCount;
1701 return nCount;
1704 /// Return the specified child or NULL if index is invalid.
1705 uno::Reference<XAccessible> SAL_CALL
1706 ScAccessibleDocument::getAccessibleChild(sal_Int32 nIndex)
1708 SolarMutexGuard aGuard;
1709 IsObjectValid();
1710 uno::Reference<XAccessible> xAccessible;
1711 if (nIndex >= 0)
1713 sal_Int32 nCount(1);
1714 if (mpChildrenShapes)
1716 xAccessible = mpChildrenShapes->Get(nIndex); // returns NULL if it is the table or out of range
1717 nCount = mpChildrenShapes->GetCount(); //there is always a table
1719 if (!xAccessible.is())
1721 if (nIndex < nCount)
1722 xAccessible = GetAccessibleSpreadsheet();
1723 else if (nIndex == nCount && mxTempAcc.is())
1724 xAccessible = mxTempAcc;
1728 if (!xAccessible.is())
1729 throw lang::IndexOutOfBoundsException();
1731 return xAccessible;
1734 /// Return the set of current states.
1735 uno::Reference<XAccessibleStateSet> SAL_CALL
1736 ScAccessibleDocument::getAccessibleStateSet()
1738 SolarMutexGuard aGuard;
1739 uno::Reference<XAccessibleStateSet> xParentStates;
1740 if (getAccessibleParent().is())
1742 uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext();
1743 xParentStates = xParentContext->getAccessibleStateSet();
1745 utl::AccessibleStateSetHelper* pStateSet = new utl::AccessibleStateSetHelper();
1746 if (IsDefunc(xParentStates))
1747 pStateSet->AddState(AccessibleStateType::DEFUNC);
1748 else
1750 pStateSet->AddState(AccessibleStateType::EDITABLE);
1751 pStateSet->AddState(AccessibleStateType::ENABLED);
1752 pStateSet->AddState(AccessibleStateType::OPAQUE);
1753 if (isShowing())
1754 pStateSet->AddState(AccessibleStateType::SHOWING);
1755 if (isVisible())
1756 pStateSet->AddState(AccessibleStateType::VISIBLE);
1758 return pStateSet;
1761 OUString SAL_CALL
1762 ScAccessibleDocument::getAccessibleName()
1764 SolarMutexGuard g;
1766 OUString aName = ScResId(STR_ACC_DOC_SPREADSHEET);
1767 ScDocument* pScDoc = GetDocument();
1768 if (!pScDoc)
1769 return aName;
1771 SfxObjectShell* pObjSh = pScDoc->GetDocumentShell();
1772 if (!pObjSh)
1773 return aName;
1775 OUString aFileName;
1776 SfxMedium* pMed = pObjSh->GetMedium();
1777 if (pMed)
1778 aFileName = pMed->GetName();
1780 if (aFileName.isEmpty())
1781 aFileName = pObjSh->GetTitle(SFX_TITLE_APINAME);
1783 if (!aFileName.isEmpty())
1785 OUString aReadOnly;
1786 if (pObjSh->IsReadOnly())
1787 aReadOnly = ScResId(STR_ACC_DOC_SPREADSHEET_READONLY);
1789 aName = aFileName + aReadOnly + " - " + aName;
1791 return aName;
1794 ///===== XAccessibleSelection ===========================================
1796 void SAL_CALL
1797 ScAccessibleDocument::selectAccessibleChild( sal_Int32 nChildIndex )
1799 SolarMutexGuard aGuard;
1800 IsObjectValid();
1802 if (!(mpChildrenShapes && mpViewShell))
1803 return;
1805 sal_Int32 nCount(mpChildrenShapes->GetCount()); // all shapes and the table
1806 if (mxTempAcc.is())
1807 ++nCount;
1808 if (nChildIndex < 0 || nChildIndex >= nCount)
1809 throw lang::IndexOutOfBoundsException();
1811 uno::Reference < XAccessible > xAccessible = mpChildrenShapes->Get(nChildIndex);
1812 if (xAccessible.is())
1814 bool bWasTableSelected(IsTableSelected());
1815 mpChildrenShapes->Select(nChildIndex); // throws no lang::IndexOutOfBoundsException if Index is too high
1816 if (bWasTableSelected)
1817 mpViewShell->SelectAll();
1819 else
1821 mpViewShell->SelectAll();
1825 sal_Bool SAL_CALL
1826 ScAccessibleDocument::isAccessibleChildSelected( sal_Int32 nChildIndex )
1828 SolarMutexGuard aGuard;
1829 IsObjectValid();
1830 bool bResult(false);
1832 if (mpChildrenShapes)
1834 sal_Int32 nCount(mpChildrenShapes->GetCount()); // all shapes and the table
1835 if (mxTempAcc.is())
1836 ++nCount;
1837 if (nChildIndex < 0 || nChildIndex >= nCount)
1838 throw lang::IndexOutOfBoundsException();
1840 uno::Reference < XAccessible > xAccessible = mpChildrenShapes->Get(nChildIndex);
1841 if (xAccessible.is())
1843 uno::Reference<drawing::XShape> xShape;
1844 bResult = mpChildrenShapes->IsSelected(nChildIndex, xShape); // throws no lang::IndexOutOfBoundsException if Index is too high
1846 else
1848 if (mxTempAcc.is() && nChildIndex == nCount)
1849 bResult = true;
1850 else
1851 bResult = IsTableSelected();
1854 return bResult;
1857 void SAL_CALL
1858 ScAccessibleDocument::clearAccessibleSelection( )
1860 SolarMutexGuard aGuard;
1861 IsObjectValid();
1863 if (mpChildrenShapes)
1864 mpChildrenShapes->DeselectAll(); //deselects all (also the table)
1867 void SAL_CALL
1868 ScAccessibleDocument::selectAllAccessibleChildren( )
1870 SolarMutexGuard aGuard;
1871 IsObjectValid();
1873 if (mpChildrenShapes)
1874 mpChildrenShapes->SelectAll();
1876 // select table after shapes, because while selecting shapes the table will be deselected
1877 if (mpViewShell)
1879 mpViewShell->SelectAll();
1883 sal_Int32 SAL_CALL
1884 ScAccessibleDocument::getSelectedAccessibleChildCount( )
1886 SolarMutexGuard aGuard;
1887 IsObjectValid();
1888 sal_Int32 nCount(0);
1890 if (mpChildrenShapes)
1891 nCount = mpChildrenShapes->GetSelectedCount();
1893 if (IsTableSelected())
1894 ++nCount;
1896 if (mxTempAcc.is())
1897 ++nCount;
1899 return nCount;
1902 uno::Reference<XAccessible > SAL_CALL
1903 ScAccessibleDocument::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex )
1905 SolarMutexGuard aGuard;
1906 IsObjectValid();
1907 uno::Reference<XAccessible> xAccessible;
1908 if (mpChildrenShapes)
1910 sal_Int32 nCount(getSelectedAccessibleChildCount()); //all shapes and the table
1911 if (nSelectedChildIndex < 0 || nSelectedChildIndex >= nCount)
1912 throw lang::IndexOutOfBoundsException();
1914 bool bTabMarked(IsTableSelected());
1916 if (mpChildrenShapes)
1917 xAccessible = mpChildrenShapes->GetSelected(nSelectedChildIndex, bTabMarked); // throws no lang::IndexOutOfBoundsException if Index is too high
1918 if (mxTempAcc.is() && nSelectedChildIndex == nCount - 1)
1919 xAccessible = mxTempAcc;
1920 else if (bTabMarked)
1921 xAccessible = GetAccessibleSpreadsheet();
1924 OSL_ENSURE(xAccessible.is(), "here should always be an accessible object or an exception thrown");
1926 return xAccessible;
1929 void SAL_CALL
1930 ScAccessibleDocument::deselectAccessibleChild( sal_Int32 nChildIndex )
1932 SolarMutexGuard aGuard;
1933 IsObjectValid();
1935 if (!(mpChildrenShapes && mpViewShell))
1936 return;
1938 sal_Int32 nCount(mpChildrenShapes->GetCount()); // all shapes and the table
1939 if (mxTempAcc.is())
1940 ++nCount;
1941 if (nChildIndex < 0 || nChildIndex >= nCount)
1942 throw lang::IndexOutOfBoundsException();
1944 bool bTabMarked(IsTableSelected());
1946 uno::Reference < XAccessible > xAccessible = mpChildrenShapes->Get(nChildIndex);
1947 if (xAccessible.is())
1949 mpChildrenShapes->Deselect(nChildIndex); // throws no lang::IndexOutOfBoundsException if Index is too high
1950 if (bTabMarked)
1951 mpViewShell->SelectAll(); // select the table again
1953 else if (bTabMarked)
1954 mpViewShell->Unmark();
1957 //===== XServiceInfo ====================================================
1959 OUString SAL_CALL
1960 ScAccessibleDocument::getImplementationName()
1962 return "ScAccessibleDocument";
1965 uno::Sequence< OUString> SAL_CALL
1966 ScAccessibleDocument::getSupportedServiceNames()
1968 uno::Sequence< OUString > aSequence = ScAccessibleContextBase::getSupportedServiceNames();
1969 sal_Int32 nOldSize(aSequence.getLength());
1970 aSequence.realloc(nOldSize + 1);
1972 aSequence[nOldSize] = "com.sun.star.AccessibleSpreadsheetDocumentView";
1974 return aSequence;
1977 //===== XTypeProvider =======================================================
1979 uno::Sequence< uno::Type > SAL_CALL ScAccessibleDocument::getTypes()
1981 return comphelper::concatSequences(ScAccessibleDocumentImpl::getTypes(), ScAccessibleContextBase::getTypes());
1984 uno::Sequence<sal_Int8> SAL_CALL
1985 ScAccessibleDocument::getImplementationId()
1987 return css::uno::Sequence<sal_Int8>();
1990 ///===== IAccessibleViewForwarder ========================================
1992 tools::Rectangle ScAccessibleDocument::GetVisibleArea_Impl() const
1994 tools::Rectangle aVisRect(GetBoundingBox());
1996 if (mpViewShell)
1998 Point aPoint(mpViewShell->GetViewData().GetPixPos(meSplitPos)); // returns a negative Point
1999 aPoint.setX(-aPoint.getX());
2000 aPoint.setY(-aPoint.getY());
2001 aVisRect.SetPos(aPoint);
2003 ScGridWindow* pWin = static_cast<ScGridWindow*>(mpViewShell->GetWindowByPos(meSplitPos));
2004 if (pWin)
2005 aVisRect = pWin->PixelToLogic(aVisRect, pWin->GetDrawMapMode());
2008 return aVisRect;
2011 tools::Rectangle ScAccessibleDocument::GetVisibleArea() const
2013 SolarMutexGuard aGuard;
2014 IsObjectValid();
2015 return maVisArea;
2018 Point ScAccessibleDocument::LogicToPixel (const Point& rPoint) const
2020 SolarMutexGuard aGuard;
2021 IsObjectValid();
2022 Point aPoint;
2023 ScGridWindow* pWin = static_cast<ScGridWindow*>(mpViewShell->GetWindowByPos(meSplitPos));
2024 if (pWin)
2026 aPoint = pWin->LogicToPixel(rPoint, pWin->GetDrawMapMode());
2027 aPoint += pWin->GetWindowExtentsRelative(nullptr).TopLeft();
2029 return aPoint;
2032 Size ScAccessibleDocument::LogicToPixel (const Size& rSize) const
2034 SolarMutexGuard aGuard;
2035 IsObjectValid();
2036 Size aSize;
2037 ScGridWindow* pWin = static_cast<ScGridWindow*>(mpViewShell->GetWindowByPos(meSplitPos));
2038 if (pWin)
2039 aSize = pWin->LogicToPixel(rSize, pWin->GetDrawMapMode());
2040 return aSize;
2043 //===== internal ========================================================
2045 utl::AccessibleRelationSetHelper* ScAccessibleDocument::GetRelationSet(const ScAddress* pAddress) const
2047 utl::AccessibleRelationSetHelper* pRelationSet = nullptr;
2048 if (mpChildrenShapes)
2049 pRelationSet = mpChildrenShapes->GetRelationSet(pAddress);
2050 return pRelationSet;
2053 OUString
2054 ScAccessibleDocument::createAccessibleDescription()
2056 return STR_ACC_DOC_DESCR;
2059 OUString
2060 ScAccessibleDocument::createAccessibleName()
2062 SolarMutexGuard aGuard;
2063 IsObjectValid();
2064 OUString sName = ScResId(STR_ACC_DOC_NAME);
2065 sal_Int32 nNumber(sal_Int32(meSplitPos) + 1);
2066 sName += OUString::number(nNumber);
2067 return sName;
2070 tools::Rectangle ScAccessibleDocument::GetBoundingBoxOnScreen() const
2072 tools::Rectangle aRect;
2073 if (mpViewShell)
2075 vcl::Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos);
2076 if (pWindow)
2077 aRect = pWindow->GetWindowExtentsRelative(nullptr);
2079 return aRect;
2082 tools::Rectangle ScAccessibleDocument::GetBoundingBox() const
2084 tools::Rectangle aRect;
2085 if (mpViewShell)
2087 vcl::Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos);
2088 if (pWindow)
2089 aRect = pWindow->GetWindowExtentsRelative(pWindow->GetAccessibleParentWindow());
2091 return aRect;
2094 SCTAB ScAccessibleDocument::getVisibleTable() const
2096 SCTAB nVisibleTable(0);
2097 if (mpViewShell)
2098 nVisibleTable = mpViewShell->GetViewData().GetTabNo();
2099 return nVisibleTable;
2102 uno::Reference < XAccessible >
2103 ScAccessibleDocument::GetAccessibleSpreadsheet()
2105 if (!mpAccessibleSpreadsheet.is() && mpViewShell)
2107 mpAccessibleSpreadsheet = new ScAccessibleSpreadsheet(this, mpViewShell, getVisibleTable(), meSplitPos);
2108 mpAccessibleSpreadsheet->Init();
2109 mbCompleteSheetSelected = IsTableSelected();
2111 return mpAccessibleSpreadsheet.get();
2114 void ScAccessibleDocument::FreeAccessibleSpreadsheet()
2116 if (mpAccessibleSpreadsheet.is())
2118 mpAccessibleSpreadsheet->dispose();
2119 mpAccessibleSpreadsheet.clear();
2123 bool ScAccessibleDocument::IsTableSelected() const
2125 bool bResult (false);
2126 if(mpViewShell)
2128 SCTAB nTab(getVisibleTable());
2129 //#103800#; use a copy of MarkData
2130 ScMarkData aMarkData(mpViewShell->GetViewData().GetMarkData());
2131 aMarkData.MarkToMulti();
2132 ScDocument* pDoc = GetDocument();
2133 if (aMarkData.IsAllMarked( ScRange( 0, 0, nTab, pDoc->MaxCol(), pDoc->MaxRow(), nTab)))
2134 bResult = true;
2136 return bResult;
2139 bool ScAccessibleDocument::IsDefunc(
2140 const uno::Reference<XAccessibleStateSet>& rxParentStates)
2142 return ScAccessibleContextBase::IsDefunc() || (mpViewShell == nullptr) || !getAccessibleParent().is() ||
2143 (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC));
2146 void ScAccessibleDocument::AddChild(const uno::Reference<XAccessible>& xAcc, bool bFireEvent)
2148 OSL_ENSURE(!mxTempAcc.is(), "this object should be removed before");
2149 if (xAcc.is())
2151 mxTempAcc = xAcc;
2152 if( bFireEvent )
2154 AccessibleEventObject aEvent;
2155 aEvent.Source = uno::Reference<XAccessibleContext>(this);
2156 aEvent.EventId = AccessibleEventId::CHILD;
2157 aEvent.NewValue <<= mxTempAcc;
2158 CommitChange( aEvent );
2163 void ScAccessibleDocument::RemoveChild(const uno::Reference<XAccessible>& xAcc, bool bFireEvent)
2165 OSL_ENSURE(mxTempAcc.is(), "this object should be added before");
2166 if (!xAcc.is())
2167 return;
2169 OSL_ENSURE(xAcc.get() == mxTempAcc.get(), "only the same object should be removed");
2170 if( bFireEvent )
2172 AccessibleEventObject aEvent;
2173 aEvent.Source = uno::Reference<XAccessibleContext>(this);
2174 aEvent.EventId = AccessibleEventId::CHILD;
2175 aEvent.OldValue <<= mxTempAcc;
2176 CommitChange( aEvent );
2178 mxTempAcc = nullptr;
2181 OUString ScAccessibleDocument::GetCurrentCellName() const
2183 OUString sName(ScResId(STR_ACC_CELL_NAME));
2184 if (mpViewShell)
2186 // Document not needed, because only the cell address, but not the tablename is needed
2187 OUString sAddress(mpViewShell->GetViewData().GetCurPos().Format(ScRefFlags::VALID));
2188 sName = sName.replaceFirst("%1", sAddress);
2190 return sName;
2193 OUString ScAccessibleDocument::GetCurrentCellDescription()
2195 return OUString();
2198 ScDocument *ScAccessibleDocument::GetDocument() const
2200 return mpViewShell ? &mpViewShell->GetViewData().GetDocument() : nullptr;
2203 ScAddress ScAccessibleDocument::GetCurCellAddress() const
2205 return mpViewShell ? mpViewShell->GetViewData().GetCurPos() : ScAddress();
2208 uno::Any SAL_CALL ScAccessibleDocument::getExtendedAttributes()
2210 SolarMutexGuard g;
2212 uno::Any anyAttribute;
2214 sal_uInt16 sheetIndex;
2215 OUString sSheetName;
2216 sheetIndex = getVisibleTable();
2217 if(GetDocument()==nullptr)
2218 return anyAttribute;
2219 GetDocument()->GetName(sheetIndex,sSheetName);
2220 OUString sValue = "page-name:" + sSheetName +
2221 ";page-number:" + OUString::number(sheetIndex+1) +
2222 ";total-pages:" + OUString::number(GetDocument()->GetTableCount()) + ";";
2223 anyAttribute <<= sValue;
2224 return anyAttribute;
2227 sal_Int32 SAL_CALL ScAccessibleDocument::getForeground( )
2229 return sal_Int32(COL_BLACK);
2232 sal_Int32 SAL_CALL ScAccessibleDocument::getBackground( )
2234 SolarMutexGuard aGuard;
2235 IsObjectValid();
2236 return sal_Int32(SC_MOD()->GetColorConfig().GetColorValue( ::svtools::DOCCOLOR ).nColor);
2239 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */