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