android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / core / access / accmap.cxx
blob0650b3d29a9338892a2736fbee20287bfe155fe5
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 <rtl/ref.hxx>
21 #include <cppuhelper/weakref.hxx>
22 #include <utility>
23 #include <vcl/window.hxx>
24 #include <svx/svdmodel.hxx>
25 #include <svx/unomod.hxx>
26 #include <algorithm>
27 #include <map>
28 #include <unordered_map>
29 #include <list>
30 #include <vector>
31 #include <accmap.hxx>
32 #include "acccontext.hxx"
33 #include "accdoc.hxx"
34 #include <strings.hrc>
35 #include "accpreview.hxx"
36 #include "accpage.hxx"
37 #include "accpara.hxx"
38 #include "accheaderfooter.hxx"
39 #include "accfootnote.hxx"
40 #include "acctextframe.hxx"
41 #include "accgraphic.hxx"
42 #include "accembedded.hxx"
43 #include "acccell.hxx"
44 #include "acctable.hxx"
45 #include <fesh.hxx>
46 #include <istype.hxx>
47 #include <rootfrm.hxx>
48 #include <txtfrm.hxx>
49 #include <hffrm.hxx>
50 #include <ftnfrm.hxx>
51 #include <cellfrm.hxx>
52 #include <tabfrm.hxx>
53 #include <pagefrm.hxx>
54 #include <flyfrm.hxx>
55 #include <ndtyp.hxx>
56 #include <IDocumentDrawModelAccess.hxx>
57 #include <svx/AccessibleShapeInfo.hxx>
58 #include <svx/ShapeTypeHandler.hxx>
59 #include <svx/SvxShapeTypes.hxx>
60 #include <svx/svdpage.hxx>
61 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
62 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
63 #include <com/sun/star/accessibility/AccessibleRole.hpp>
64 #include <com/sun/star/beans/XPropertySet.hpp>
65 #include <com/sun/star/document/XShapeEventBroadcaster.hpp>
66 #include <cppuhelper/implbase.hxx>
67 #include <comphelper/interfacecontainer4.hxx>
68 #include <pagepreviewlayout.hxx>
69 #include <dcontact.hxx>
70 #include <svx/svdmark.hxx>
71 #include <doc.hxx>
72 #include <drawdoc.hxx>
73 #include <pam.hxx>
74 #include <ndtxt.hxx>
75 #include <dflyobj.hxx>
76 #include <prevwpage.hxx>
77 #include <calbck.hxx>
78 #include <undobj.hxx>
79 #include <comphelper/diagnose_ex.hxx>
80 #include <tools/debug.hxx>
82 using namespace ::com::sun::star;
83 using namespace ::com::sun::star::accessibility;
84 using namespace ::sw::access;
86 class SwAccessibleContextMap_Impl
88 public:
89 typedef const SwFrame * key_type;
90 typedef uno::WeakReference < XAccessible > mapped_type;
91 typedef std::pair<const key_type,mapped_type> value_type;
92 typedef std::unordered_map<key_type, mapped_type>::iterator iterator;
93 typedef std::unordered_map<key_type, mapped_type>::const_iterator const_iterator;
94 private:
95 std::unordered_map <key_type, mapped_type> maMap;
96 public:
98 #if OSL_DEBUG_LEVEL > 0
99 bool mbLocked;
100 #endif
102 SwAccessibleContextMap_Impl()
103 #if OSL_DEBUG_LEVEL > 0
104 : mbLocked( false )
105 #endif
108 iterator begin() { return maMap.begin(); }
109 iterator end() { return maMap.end(); }
110 bool empty() const { return maMap.empty(); }
111 void clear() { maMap.clear(); }
112 iterator find(const key_type& key) { return maMap.find(key); }
113 template<class... Args>
114 std::pair<iterator,bool> emplace(Args&&... args) { return maMap.emplace(std::forward<Args>(args)...); }
115 iterator erase(const_iterator const & pos) { return maMap.erase(pos); }
118 namespace {
120 class SwDrawModellListener_Impl : public SfxListener,
121 public ::cppu::WeakImplHelper< document::XShapeEventBroadcaster >
123 mutable std::mutex maListenerMutex;
124 ::comphelper::OInterfaceContainerHelper4<css::document::XEventListener> maEventListeners;
125 std::unordered_multimap<css::uno::Reference< css::drawing::XShape >, css::uno::Reference< css::document::XShapeEventListener >> maShapeListeners;
126 SdrModel *mpDrawModel;
127 protected:
128 virtual ~SwDrawModellListener_Impl() override;
130 public:
131 explicit SwDrawModellListener_Impl( SdrModel *pDrawModel );
133 // css::document::XEventBroadcaster
134 virtual void SAL_CALL addEventListener( const uno::Reference< document::XEventListener >& xListener ) override;
135 virtual void SAL_CALL removeEventListener( const uno::Reference< document::XEventListener >& xListener ) override;
136 // css::document::XShapeEventBroadcaster
137 virtual void SAL_CALL addShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape, const css::uno::Reference< css::document::XShapeEventListener >& xListener ) override;
138 virtual void SAL_CALL removeShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape, const css::uno::Reference< css::document::XShapeEventListener >& xListener ) override;
140 virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
141 void Dispose();
146 SwDrawModellListener_Impl::SwDrawModellListener_Impl( SdrModel *pDrawModel ) :
147 mpDrawModel( pDrawModel )
149 StartListening( *mpDrawModel );
152 SwDrawModellListener_Impl::~SwDrawModellListener_Impl()
154 Dispose();
157 void SAL_CALL SwDrawModellListener_Impl::addEventListener( const uno::Reference< document::XEventListener >& xListener )
159 std::unique_lock g(maListenerMutex);
160 maEventListeners.addInterface( g, xListener );
163 void SAL_CALL SwDrawModellListener_Impl::removeEventListener( const uno::Reference< document::XEventListener >& xListener )
165 std::unique_lock g(maListenerMutex);
166 maEventListeners.removeInterface( g, xListener );
169 void SAL_CALL SwDrawModellListener_Impl::addShapeEventListener(
170 const css::uno::Reference< css::drawing::XShape >& xShape,
171 const uno::Reference< document::XShapeEventListener >& xListener )
173 assert(xShape.is() && "no shape?");
174 std::unique_lock aGuard(maListenerMutex);
175 maShapeListeners.emplace(xShape, xListener);
178 void SAL_CALL SwDrawModellListener_Impl::removeShapeEventListener(
179 const css::uno::Reference< css::drawing::XShape >& xShape,
180 const uno::Reference< document::XShapeEventListener >& xListener )
182 std::unique_lock aGuard(maListenerMutex);
183 auto [itBegin, itEnd] = maShapeListeners.equal_range(xShape);
184 for (auto it = itBegin; it != itEnd; ++it)
185 if (it->second == xListener)
187 maShapeListeners.erase(it);
188 return;
192 void SwDrawModellListener_Impl::Notify( SfxBroadcaster& /*rBC*/,
193 const SfxHint& rHint )
195 // do not broadcast notifications for writer fly frames, because there
196 // are no shapes that need to know about them.
197 if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint)
198 return;
199 const SdrHint *pSdrHint = static_cast<const SdrHint*>( &rHint );
200 const SdrObject* pObj = pSdrHint->GetObject();
201 if (pObj &&
202 ( dynamic_cast< const SwFlyDrawObj* >(pObj) ||
203 dynamic_cast< const SwVirtFlyDrawObj* >(pObj) ||
204 pObj->GetObjIdentifier() == SdrObjKind::NewFrame ) )
206 return;
209 OSL_ENSURE( mpDrawModel, "draw model listener is disposed" );
210 if( !mpDrawModel )
211 return;
213 document::EventObject aEvent;
214 if( !SvxUnoDrawMSFactory::createEvent( mpDrawModel, pSdrHint, aEvent ) )
215 return;
218 std::unique_lock g(maListenerMutex);
219 ::comphelper::OInterfaceIteratorHelper4 aIter( g, maEventListeners );
220 g.unlock();
221 while( aIter.hasMoreElements() )
225 aIter.next()->notifyEvent( aEvent );
227 catch( uno::RuntimeException const & )
229 TOOLS_WARN_EXCEPTION("sw.a11y", "Runtime exception caught while notifying shape");
234 // right now, we're only handling the specific event necessary to fix this performance problem
235 if (pSdrHint->GetKind() == SdrHintKind::ObjectChange)
237 auto pSdrObject = const_cast<SdrObject*>(pSdrHint->GetObject());
238 uno::Reference<drawing::XShape> xShape(pSdrObject->getUnoShape(), uno::UNO_QUERY);
239 std::unique_lock aGuard(maListenerMutex);
240 auto [itBegin, itEnd] = maShapeListeners.equal_range(xShape);
241 for (auto it = itBegin; it != itEnd; ++it)
242 it->second->notifyShapeEvent(aEvent);
246 void SwDrawModellListener_Impl::Dispose()
248 if (mpDrawModel != nullptr) {
249 EndListening( *mpDrawModel );
251 mpDrawModel = nullptr;
254 typedef std::pair < const SdrObject *, ::rtl::Reference < ::accessibility::AccessibleShape > > SwAccessibleObjShape_Impl;
256 class SwAccessibleShapeMap_Impl
258 public:
260 typedef const SdrObject * key_type;
261 typedef uno::WeakReference<XAccessible> mapped_type;
262 typedef std::pair<const key_type,mapped_type> value_type;
263 typedef std::map<key_type, mapped_type>::iterator iterator;
264 typedef std::map<key_type, mapped_type>::const_iterator const_iterator;
266 private:
268 ::accessibility::AccessibleShapeTreeInfo maInfo;
269 std::map<key_type, mapped_type> maMap;
271 public:
273 explicit SwAccessibleShapeMap_Impl( SwAccessibleMap const *pMap )
275 maInfo.SetSdrView( pMap->GetShell()->GetDrawView() );
276 maInfo.SetWindow( pMap->GetShell()->GetWin() );
277 maInfo.SetViewForwarder( pMap );
278 uno::Reference < document::XShapeEventBroadcaster > xModelBroadcaster =
279 new SwDrawModellListener_Impl(
280 pMap->GetShell()->getIDocumentDrawModelAccess().GetOrCreateDrawModel() );
281 maInfo.SetModelBroadcaster( xModelBroadcaster );
284 ~SwAccessibleShapeMap_Impl();
286 const ::accessibility::AccessibleShapeTreeInfo& GetInfo() const { return maInfo; }
288 std::unique_ptr<SwAccessibleObjShape_Impl[]> Copy( size_t& rSize,
289 const SwFEShell *pFESh,
290 SwAccessibleObjShape_Impl **pSelShape ) const;
292 iterator end() { return maMap.end(); }
293 const_iterator cbegin() const { return maMap.cbegin(); }
294 const_iterator cend() const { return maMap.cend(); }
295 bool empty() const { return maMap.empty(); }
296 iterator find(const key_type& key) { return maMap.find(key); }
297 template<class... Args>
298 std::pair<iterator,bool> emplace(Args&&... args) { return maMap.emplace(std::forward<Args>(args)...); }
299 iterator erase(const_iterator const & pos) { return maMap.erase(pos); }
302 SwAccessibleShapeMap_Impl::~SwAccessibleShapeMap_Impl()
304 uno::Reference < document::XEventBroadcaster > xBrd( maInfo.GetModelBroadcaster() );
305 if( xBrd.is() )
306 static_cast < SwDrawModellListener_Impl * >( xBrd.get() )->Dispose();
309 std::unique_ptr<SwAccessibleObjShape_Impl[]>
310 SwAccessibleShapeMap_Impl::Copy(
311 size_t& rSize, const SwFEShell *pFESh,
312 SwAccessibleObjShape_Impl **pSelStart ) const
314 std::unique_ptr<SwAccessibleObjShape_Impl[]> pShapes;
315 SwAccessibleObjShape_Impl *pSelShape = nullptr;
317 size_t nSelShapes = pFESh ? pFESh->IsObjSelected() : 0;
318 rSize = maMap.size();
320 if( rSize > 0 )
322 pShapes.reset(new SwAccessibleObjShape_Impl[rSize]);
324 SwAccessibleObjShape_Impl *pShape = pShapes.get();
325 pSelShape = &(pShapes[rSize]);
326 for( const auto& rEntry : maMap )
328 const SdrObject *pObj = rEntry.first;
329 uno::Reference < XAccessible > xAcc( rEntry.second );
330 if( nSelShapes && pFESh && pFESh->IsObjSelected( *pObj ) )
332 // selected objects are inserted from the back
333 --pSelShape;
334 pSelShape->first = pObj;
335 pSelShape->second =
336 static_cast < ::accessibility::AccessibleShape* >(
337 xAcc.get() );
338 --nSelShapes;
340 else
342 pShape->first = pObj;
343 pShape->second =
344 static_cast < ::accessibility::AccessibleShape* >(
345 xAcc.get() );
346 ++pShape;
349 assert(pSelShape == pShape);
352 if( pSelStart )
353 *pSelStart = pSelShape;
355 return pShapes;
358 struct SwAccessibleEvent_Impl
360 public:
361 enum EventType { CARET_OR_STATES,
362 INVALID_CONTENT,
363 POS_CHANGED,
364 CHILD_POS_CHANGED,
365 SHAPE_SELECTION,
366 DISPOSE,
367 INVALID_ATTR };
369 private:
370 SwRect maOldBox; // the old bounds for CHILD_POS_CHANGED
371 // and POS_CHANGED
372 uno::WeakReference < XAccessible > mxAcc; // The object that fires the event
373 SwAccessibleChild maFrameOrObj; // the child for CHILD_POS_CHANGED and
374 // the same as xAcc for any other
375 // event type
376 EventType meType; // The event type
377 AccessibleStates mnStates; // check states or update caret pos
379 public:
380 const SwFrame* mpParentFrame; // The object that fires the event
381 bool IsNoXaccParentFrame() const
383 return CHILD_POS_CHANGED == meType && mpParentFrame != nullptr;
386 public:
387 SwAccessibleEvent_Impl( EventType eT,
388 SwAccessibleContext *pA,
389 SwAccessibleChild aFrameOrObj )
390 : mxAcc( pA ),
391 maFrameOrObj(std::move( aFrameOrObj )),
392 meType( eT ),
393 mnStates( AccessibleStates::NONE ),
394 mpParentFrame( nullptr )
397 SwAccessibleEvent_Impl( EventType eT,
398 SwAccessibleChild aFrameOrObj )
399 : maFrameOrObj(std::move( aFrameOrObj )),
400 meType( eT ),
401 mnStates( AccessibleStates::NONE ),
402 mpParentFrame( nullptr )
404 assert(SwAccessibleEvent_Impl::DISPOSE == meType &&
405 "wrong event constructor, DISPOSE only");
408 explicit SwAccessibleEvent_Impl( EventType eT )
409 : meType( eT ),
410 mnStates( AccessibleStates::NONE ),
411 mpParentFrame( nullptr )
413 assert(SwAccessibleEvent_Impl::SHAPE_SELECTION == meType &&
414 "wrong event constructor, SHAPE_SELECTION only" );
417 SwAccessibleEvent_Impl( EventType eT,
418 SwAccessibleContext *pA,
419 SwAccessibleChild aFrameOrObj,
420 const SwRect& rR )
421 : maOldBox( rR ),
422 mxAcc( pA ),
423 maFrameOrObj(std::move( aFrameOrObj )),
424 meType( eT ),
425 mnStates( AccessibleStates::NONE ),
426 mpParentFrame( nullptr )
428 assert((SwAccessibleEvent_Impl::CHILD_POS_CHANGED == meType ||
429 SwAccessibleEvent_Impl::POS_CHANGED == meType) &&
430 "wrong event constructor, (CHILD_)POS_CHANGED only" );
433 SwAccessibleEvent_Impl( EventType eT,
434 SwAccessibleContext *pA,
435 SwAccessibleChild aFrameOrObj,
436 const AccessibleStates _nStates )
437 : mxAcc( pA ),
438 maFrameOrObj(std::move( aFrameOrObj )),
439 meType( eT ),
440 mnStates( _nStates ),
441 mpParentFrame( nullptr )
443 assert( SwAccessibleEvent_Impl::CARET_OR_STATES == meType &&
444 "wrong event constructor, CARET_OR_STATES only" );
447 SwAccessibleEvent_Impl( EventType eT, const SwFrame *pParentFrame,
448 SwAccessibleChild aFrameOrObj, const SwRect& rR ) :
449 maOldBox( rR ),
450 maFrameOrObj(std::move( aFrameOrObj )),
451 meType( eT ),
452 mnStates( AccessibleStates::NONE ),
453 mpParentFrame( pParentFrame )
455 assert( SwAccessibleEvent_Impl::CHILD_POS_CHANGED == meType &&
456 "wrong event constructor, CHILD_POS_CHANGED only" );
459 // <SetType(..)> only used in method <SwAccessibleMap::AppendEvent(..)>
460 void SetType( EventType eT )
462 meType = eT;
464 EventType GetType() const
466 return meType;
469 ::rtl::Reference < SwAccessibleContext > GetContext() const
471 uno::Reference < XAccessible > xTmp( mxAcc );
472 ::rtl::Reference < SwAccessibleContext > xAccImpl(
473 static_cast<SwAccessibleContext*>( xTmp.get() ) );
475 return xAccImpl;
478 const SwRect& GetOldBox() const
480 return maOldBox;
482 // <SetOldBox(..)> only used in method <SwAccessibleMap::AppendEvent(..)>
483 void SetOldBox( const SwRect& rOldBox )
485 maOldBox = rOldBox;
488 const SwAccessibleChild& GetFrameOrObj() const
490 return maFrameOrObj;
493 // <SetStates(..)> only used in method <SwAccessibleMap::AppendEvent(..)>
494 void SetStates( AccessibleStates _nStates )
496 mnStates |= _nStates;
499 bool IsUpdateCursorPos() const
501 return bool(mnStates & AccessibleStates::CARET);
503 bool IsInvalidateStates() const
505 return bool(mnStates & (AccessibleStates::EDITABLE | AccessibleStates::OPAQUE));
507 bool IsInvalidateRelation() const
509 return bool(mnStates & (AccessibleStates::RELATION_FROM | AccessibleStates::RELATION_TO));
511 bool IsInvalidateTextSelection() const
513 return bool( mnStates & AccessibleStates::TEXT_SELECTION_CHANGED );
516 bool IsInvalidateTextAttrs() const
518 return bool( mnStates & AccessibleStates::TEXT_ATTRIBUTE_CHANGED );
521 AccessibleStates GetStates() const
523 return mnStates;
526 AccessibleStates GetAllStates() const
528 return mnStates;
532 class SwAccessibleEventList_Impl
534 std::list<SwAccessibleEvent_Impl> maEvents;
535 bool mbFiring;
537 public:
538 SwAccessibleEventList_Impl()
539 : mbFiring( false )
542 void SetFiring()
544 mbFiring = true;
546 bool IsFiring() const
548 return mbFiring;
551 void MoveMissingXAccToEnd();
553 size_t size() const { return maEvents.size(); }
554 std::list<SwAccessibleEvent_Impl>::iterator begin() { return maEvents.begin(); }
555 std::list<SwAccessibleEvent_Impl>::iterator end() { return maEvents.end(); }
556 std::list<SwAccessibleEvent_Impl>::iterator insert( const std::list<SwAccessibleEvent_Impl>::iterator& aIter,
557 const SwAccessibleEvent_Impl& rEvent )
559 return maEvents.insert( aIter, rEvent );
561 std::list<SwAccessibleEvent_Impl>::iterator erase( const std::list<SwAccessibleEvent_Impl>::iterator& aPos )
563 return maEvents.erase( aPos );
567 // see comment in SwAccessibleMap::InvalidatePosOrSize()
568 // last case "else if(pParent)" for why this surprising hack exists
569 void SwAccessibleEventList_Impl::MoveMissingXAccToEnd()
571 size_t nSize = size();
572 if (nSize < 2 )
574 return;
576 SwAccessibleEventList_Impl lstEvent;
577 for (auto li = begin(); li != end(); )
579 if (li->IsNoXaccParentFrame())
581 lstEvent.insert(lstEvent.end(), *li);
582 li = erase(li);
584 else
585 ++li;
587 assert(size() + lstEvent.size() == nSize);
588 maEvents.insert(end(),lstEvent.begin(),lstEvent.end());
589 assert(size() == nSize);
592 namespace {
594 struct SwAccessibleChildFunc
596 bool operator()( const SwAccessibleChild& r1,
597 const SwAccessibleChild& r2 ) const
599 const void *p1 = r1.GetSwFrame()
600 ? static_cast < const void * >( r1.GetSwFrame())
601 : ( r1.GetDrawObject()
602 ? static_cast < const void * >( r1.GetDrawObject() )
603 : static_cast < const void * >( r1.GetWindow() ) );
604 const void *p2 = r2.GetSwFrame()
605 ? static_cast < const void * >( r2.GetSwFrame())
606 : ( r2.GetDrawObject()
607 ? static_cast < const void * >( r2.GetDrawObject() )
608 : static_cast < const void * >( r2.GetWindow() ) );
609 return p1 < p2;
615 class SwAccessibleEventMap_Impl
617 public:
618 typedef SwAccessibleChild key_type;
619 typedef std::list<SwAccessibleEvent_Impl>::iterator mapped_type;
620 typedef std::pair<const key_type,mapped_type> value_type;
621 typedef SwAccessibleChildFunc key_compare;
622 typedef std::map<key_type,mapped_type,key_compare>::iterator iterator;
623 typedef std::map<key_type,mapped_type,key_compare>::const_iterator const_iterator;
624 private:
625 std::map <key_type,mapped_type,key_compare> maMap;
626 public:
627 iterator end() { return maMap.end(); }
628 iterator find(const key_type& key) { return maMap.find(key); }
629 template<class... Args>
630 std::pair<iterator,bool> emplace(Args&&... args) { return maMap.emplace(std::forward<Args>(args)...); }
631 iterator erase(const_iterator const & pos) { return maMap.erase(pos); }
634 namespace {
636 struct SwAccessibleParaSelection
638 TextFrameIndex nStartOfSelection;
639 TextFrameIndex nEndOfSelection;
641 SwAccessibleParaSelection(const TextFrameIndex nStartOfSelection_,
642 const TextFrameIndex nEndOfSelection_)
643 : nStartOfSelection(nStartOfSelection_)
644 , nEndOfSelection(nEndOfSelection_)
648 struct SwXAccWeakRefComp
650 bool operator()( const uno::WeakReference<XAccessible>& _rXAccWeakRef1,
651 const uno::WeakReference<XAccessible>& _rXAccWeakRef2 ) const
653 return _rXAccWeakRef1.get() < _rXAccWeakRef2.get();
659 class SwAccessibleSelectedParas_Impl
661 public:
662 typedef uno::WeakReference < XAccessible > key_type;
663 typedef SwAccessibleParaSelection mapped_type;
664 typedef std::pair<const key_type,mapped_type> value_type;
665 typedef SwXAccWeakRefComp key_compare;
666 typedef std::map<key_type,mapped_type,key_compare>::iterator iterator;
667 typedef std::map<key_type,mapped_type,key_compare>::const_iterator const_iterator;
668 private:
669 std::map<key_type,mapped_type,key_compare> maMap;
670 public:
671 iterator begin() { return maMap.begin(); }
672 iterator end() { return maMap.end(); }
673 iterator find(const key_type& key) { return maMap.find(key); }
674 template<class... Args>
675 std::pair<iterator,bool> emplace(Args&&... args) { return maMap.emplace(std::forward<Args>(args)...); }
676 iterator erase(const_iterator const & pos) { return maMap.erase(pos); }
679 // helper class that stores preview data
680 class SwAccPreviewData
682 typedef std::vector<tools::Rectangle> Rectangles;
683 Rectangles maPreviewRects;
684 Rectangles maLogicRects;
686 SwRect maVisArea;
687 Fraction maScale;
689 const SwPageFrame *mpSelPage;
691 /** adjust logic page rectangle to its visible part
693 @param _iorLogicPgSwRect
694 input/output parameter - reference to the logic page rectangle, which
695 has to be adjusted.
697 @param _rPreviewPgSwRect
698 input parameter - constant reference to the corresponding preview page
699 rectangle; needed to determine the visible part of the logic page rectangle.
701 @param _rPreviewWinSize
702 input parameter - constant reference to the preview window size in TWIP;
703 needed to determine the visible part of the logic page rectangle
705 static void AdjustLogicPgRectToVisibleArea( SwRect& _iorLogicPgSwRect,
706 const SwRect& _rPreviewPgSwRect,
707 const Size& _rPreviewWinSize );
709 public:
710 SwAccPreviewData();
712 void Update( const SwAccessibleMap& rAccMap,
713 const std::vector<std::unique_ptr<PreviewPage>>& _rPreviewPages,
714 const Fraction& _rScale,
715 const SwPageFrame* _pSelectedPageFrame,
716 const Size& _rPreviewWinSize );
718 void InvalidateSelection( const SwPageFrame* _pSelectedPageFrame );
720 const SwRect& GetVisArea() const { return maVisArea;}
722 /** Adjust the MapMode so that the preview page appears at the
723 * proper position. rPoint identifies the page for which the
724 * MapMode should be adjusted. If bFromPreview is true, rPoint is
725 * a preview coordinate; else it's a document coordinate. */
726 void AdjustMapMode( MapMode& rMapMode,
727 const Point& rPoint ) const;
729 const SwPageFrame *GetSelPage() const { return mpSelPage; }
731 void DisposePage(const SwPageFrame *pPageFrame );
734 SwAccPreviewData::SwAccPreviewData() :
735 mpSelPage( nullptr )
739 void SwAccPreviewData::Update( const SwAccessibleMap& rAccMap,
740 const std::vector<std::unique_ptr<PreviewPage>>& _rPreviewPages,
741 const Fraction& _rScale,
742 const SwPageFrame* _pSelectedPageFrame,
743 const Size& _rPreviewWinSize )
745 // store preview scaling, maximal preview page size and selected page
746 maScale = _rScale;
747 mpSelPage = _pSelectedPageFrame;
749 // prepare loop on preview pages
750 maPreviewRects.clear();
751 maLogicRects.clear();
752 SwAccessibleChild aPage;
753 maVisArea.Clear();
755 // loop on preview pages to calculate <maPreviewRects>, <maLogicRects> and
756 // <maVisArea>
757 for ( auto & rpPreviewPage : _rPreviewPages )
759 aPage = rpPreviewPage->pPage;
761 // add preview page rectangle to <maPreviewRects>
762 tools::Rectangle aPreviewPgRect( rpPreviewPage->aPreviewWinPos, rpPreviewPage->aPageSize );
763 maPreviewRects.push_back( aPreviewPgRect );
765 // add logic page rectangle to <maLogicRects>
766 SwRect aLogicPgSwRect( aPage.GetBox( rAccMap ) );
767 tools::Rectangle aLogicPgRect( aLogicPgSwRect.SVRect() );
768 maLogicRects.push_back( aLogicPgRect );
769 // union visible area with visible part of logic page rectangle
770 if ( rpPreviewPage->bVisible )
772 if ( !rpPreviewPage->pPage->IsEmptyPage() )
774 AdjustLogicPgRectToVisibleArea( aLogicPgSwRect,
775 SwRect( aPreviewPgRect ),
776 _rPreviewWinSize );
778 if ( maVisArea.IsEmpty() )
779 maVisArea = aLogicPgSwRect;
780 else
781 maVisArea.Union( aLogicPgSwRect );
786 void SwAccPreviewData::InvalidateSelection( const SwPageFrame* _pSelectedPageFrame )
788 mpSelPage = _pSelectedPageFrame;
789 assert(mpSelPage);
792 namespace {
794 struct ContainsPredicate
796 const Point& mrPoint;
797 explicit ContainsPredicate( const Point& rPoint ) : mrPoint(rPoint) {}
798 bool operator() ( const tools::Rectangle& rRect ) const
800 return rRect.Contains( mrPoint );
806 void SwAccPreviewData::AdjustMapMode( MapMode& rMapMode,
807 const Point& rPoint ) const
809 // adjust scale
810 rMapMode.SetScaleX( maScale );
811 rMapMode.SetScaleY( maScale );
813 // find proper rectangle
814 Rectangles::const_iterator aBegin = maLogicRects.begin();
815 Rectangles::const_iterator aEnd = maLogicRects.end();
816 Rectangles::const_iterator aFound = std::find_if( aBegin, aEnd,
817 ContainsPredicate( rPoint ) );
819 if( aFound != aEnd )
821 // found! set new origin
822 Point aPoint = (maPreviewRects.begin() + (aFound - aBegin))->TopLeft();
823 aPoint -= (maLogicRects.begin() + (aFound-aBegin))->TopLeft();
824 rMapMode.SetOrigin( aPoint );
826 // else: don't adjust MapMode
829 void SwAccPreviewData::DisposePage(const SwPageFrame *pPageFrame )
831 if( mpSelPage == pPageFrame )
832 mpSelPage = nullptr;
835 // adjust logic page rectangle to its visible part
836 void SwAccPreviewData::AdjustLogicPgRectToVisibleArea(
837 SwRect& _iorLogicPgSwRect,
838 const SwRect& _rPreviewPgSwRect,
839 const Size& _rPreviewWinSize )
841 // determine preview window rectangle
842 const SwRect aPreviewWinSwRect( Point( 0, 0 ), _rPreviewWinSize );
843 // calculate visible preview page rectangle
844 SwRect aVisPreviewPgSwRect( _rPreviewPgSwRect );
845 aVisPreviewPgSwRect.Intersection( aPreviewWinSwRect );
846 // adjust logic page rectangle
847 SwTwips nTmpDiff;
848 // left
849 nTmpDiff = aVisPreviewPgSwRect.Left() - _rPreviewPgSwRect.Left();
850 _iorLogicPgSwRect.AddLeft( nTmpDiff );
851 // top
852 nTmpDiff = aVisPreviewPgSwRect.Top() - _rPreviewPgSwRect.Top();
853 _iorLogicPgSwRect.AddTop( nTmpDiff );
854 // right
855 nTmpDiff = _rPreviewPgSwRect.Right() - aVisPreviewPgSwRect.Right();
856 _iorLogicPgSwRect.AddRight( - nTmpDiff );
857 // bottom
858 nTmpDiff = _rPreviewPgSwRect.Bottom() - aVisPreviewPgSwRect.Bottom();
859 _iorLogicPgSwRect.AddBottom( - nTmpDiff );
862 static bool AreInSameTable( const uno::Reference< XAccessible >& rAcc,
863 const SwFrame *pFrame )
865 bool bRet = false;
867 if( pFrame && pFrame->IsCellFrame() && rAcc.is() )
869 // Is it in the same table? We check that
870 // by comparing the last table frame in the
871 // follow chain, because that's cheaper than
872 // searching the first one.
873 SwAccessibleContext *pAccImpl =
874 static_cast< SwAccessibleContext *>( rAcc.get() );
875 if( pAccImpl->GetFrame()->IsCellFrame() )
877 const SwTabFrame *pTabFrame1 = pAccImpl->GetFrame()->FindTabFrame();
878 if (pTabFrame1)
880 while (pTabFrame1->GetFollow())
881 pTabFrame1 = pTabFrame1->GetFollow();
884 const SwTabFrame *pTabFrame2 = pFrame->FindTabFrame();
885 if (pTabFrame2)
887 while (pTabFrame2->GetFollow())
888 pTabFrame2 = pTabFrame2->GetFollow();
891 bRet = (pTabFrame1 == pTabFrame2);
895 return bRet;
898 void SwAccessibleMap::FireEvent( const SwAccessibleEvent_Impl& rEvent )
900 ::rtl::Reference < SwAccessibleContext > xAccImpl( rEvent.GetContext() );
901 if (!xAccImpl.is() && rEvent.mpParentFrame != nullptr)
903 SwAccessibleContextMap_Impl::iterator aIter =
904 mpFrameMap->find( rEvent.mpParentFrame );
905 if( aIter != mpFrameMap->end() )
907 uno::Reference < XAccessible > xAcc( (*aIter).second );
908 if (xAcc.is())
910 uno::Reference < XAccessibleContext > xContext(xAcc,uno::UNO_QUERY);
911 if (xContext.is() && xContext->getAccessibleRole() == AccessibleRole::PARAGRAPH)
913 xAccImpl = static_cast< SwAccessibleContext *>( xAcc.get() );
918 if( SwAccessibleEvent_Impl::SHAPE_SELECTION == rEvent.GetType() )
920 DoInvalidateShapeSelection();
922 else if( xAccImpl.is() && xAccImpl->GetFrame() )
924 if ( rEvent.GetType() != SwAccessibleEvent_Impl::DISPOSE &&
925 rEvent.IsInvalidateTextAttrs() )
927 xAccImpl->InvalidateAttr();
929 switch( rEvent.GetType() )
931 case SwAccessibleEvent_Impl::INVALID_CONTENT:
932 xAccImpl->InvalidateContent();
933 break;
934 case SwAccessibleEvent_Impl::POS_CHANGED:
935 xAccImpl->InvalidatePosOrSize( rEvent.GetOldBox() );
936 break;
937 case SwAccessibleEvent_Impl::CHILD_POS_CHANGED:
938 xAccImpl->InvalidateChildPosOrSize( rEvent.GetFrameOrObj(),
939 rEvent.GetOldBox() );
940 break;
941 case SwAccessibleEvent_Impl::DISPOSE:
942 assert(!"dispose event has been stored");
943 break;
944 case SwAccessibleEvent_Impl::INVALID_ATTR:
945 // nothing to do here - handled above
946 break;
947 default:
948 break;
950 if( SwAccessibleEvent_Impl::DISPOSE != rEvent.GetType() )
952 if( rEvent.IsUpdateCursorPos() )
953 xAccImpl->InvalidateCursorPos();
954 if( rEvent.IsInvalidateStates() )
955 xAccImpl->InvalidateStates( rEvent.GetStates() );
956 if( rEvent.IsInvalidateRelation() )
958 // both events CONTENT_FLOWS_FROM_RELATION_CHANGED and
959 // CONTENT_FLOWS_TO_RELATION_CHANGED are possible
960 if ( rEvent.GetAllStates() & AccessibleStates::RELATION_FROM )
962 xAccImpl->InvalidateRelation(
963 AccessibleEventId::CONTENT_FLOWS_FROM_RELATION_CHANGED );
965 if ( rEvent.GetAllStates() & AccessibleStates::RELATION_TO )
967 xAccImpl->InvalidateRelation(
968 AccessibleEventId::CONTENT_FLOWS_TO_RELATION_CHANGED );
972 if ( rEvent.IsInvalidateTextSelection() )
974 xAccImpl->InvalidateTextSelection();
980 void SwAccessibleMap::AppendEvent( const SwAccessibleEvent_Impl& rEvent )
982 osl::MutexGuard aGuard( maEventMutex );
984 if( !mpEvents )
985 mpEvents.reset(new SwAccessibleEventList_Impl);
986 if( !mpEventMap )
987 mpEventMap.reset(new SwAccessibleEventMap_Impl);
989 if( mpEvents->IsFiring() )
991 // While events are fired new ones are generated. They have to be fired
992 // now. This does not work for DISPOSE events!
993 OSL_ENSURE( rEvent.GetType() != SwAccessibleEvent_Impl::DISPOSE,
994 "dispose event while firing events" );
995 FireEvent( rEvent );
997 else
1000 SwAccessibleEventMap_Impl::iterator aIter =
1001 mpEventMap->find( rEvent.GetFrameOrObj() );
1002 if( aIter != mpEventMap->end() )
1004 SwAccessibleEvent_Impl aEvent( *(*aIter).second );
1005 assert( aEvent.GetType() != SwAccessibleEvent_Impl::DISPOSE &&
1006 "dispose events should not be stored" );
1007 bool bAppendEvent = true;
1008 switch( rEvent.GetType() )
1010 case SwAccessibleEvent_Impl::CARET_OR_STATES:
1011 // A CARET_OR_STATES event is added to any other
1012 // event only. It is broadcasted after any other event, so the
1013 // event should be put to the back.
1014 OSL_ENSURE( aEvent.GetType() != SwAccessibleEvent_Impl::CHILD_POS_CHANGED,
1015 "invalid event combination" );
1016 aEvent.SetStates( rEvent.GetAllStates() );
1017 break;
1018 case SwAccessibleEvent_Impl::INVALID_CONTENT:
1019 // An INVALID_CONTENT event overwrites a CARET_OR_STATES
1020 // event (but keeps its flags) and it is contained in a
1021 // POS_CHANGED event.
1022 // Therefore, the event's type has to be adapted and the event
1023 // has to be put at the end.
1025 // fdo#56031 An INVALID_CONTENT event overwrites a INVALID_ATTR
1026 // event and overwrites its flags
1027 OSL_ENSURE( aEvent.GetType() != SwAccessibleEvent_Impl::CHILD_POS_CHANGED,
1028 "invalid event combination" );
1029 if( aEvent.GetType() == SwAccessibleEvent_Impl::CARET_OR_STATES )
1030 aEvent.SetType( SwAccessibleEvent_Impl::INVALID_CONTENT );
1031 else if ( aEvent.GetType() == SwAccessibleEvent_Impl::INVALID_ATTR )
1033 aEvent.SetType( SwAccessibleEvent_Impl::INVALID_CONTENT );
1034 aEvent.SetStates( rEvent.GetAllStates() );
1037 break;
1038 case SwAccessibleEvent_Impl::POS_CHANGED:
1039 // A pos changed event overwrites CARET_STATES (keeping its
1040 // flags) as well as INVALID_CONTENT. The old box position
1041 // has to be stored however if the old event is not a
1042 // POS_CHANGED itself.
1043 OSL_ENSURE( aEvent.GetType() != SwAccessibleEvent_Impl::CHILD_POS_CHANGED,
1044 "invalid event combination" );
1045 if( aEvent.GetType() != SwAccessibleEvent_Impl::POS_CHANGED )
1046 aEvent.SetOldBox( rEvent.GetOldBox() );
1047 aEvent.SetType( SwAccessibleEvent_Impl::POS_CHANGED );
1048 break;
1049 case SwAccessibleEvent_Impl::CHILD_POS_CHANGED:
1050 // CHILD_POS_CHANGED events can only follow CHILD_POS_CHANGED
1051 // events. The only action that needs to be done again is
1052 // to put the old event to the back. The new one cannot be used,
1053 // because we are interested in the old frame bounds.
1054 OSL_ENSURE( aEvent.GetType() == SwAccessibleEvent_Impl::CHILD_POS_CHANGED,
1055 "invalid event combination" );
1056 break;
1057 case SwAccessibleEvent_Impl::SHAPE_SELECTION:
1058 OSL_ENSURE( aEvent.GetType() == SwAccessibleEvent_Impl::SHAPE_SELECTION,
1059 "invalid event combination" );
1060 break;
1061 case SwAccessibleEvent_Impl::DISPOSE:
1062 // DISPOSE events overwrite all others. They are not stored
1063 // but executed immediately to avoid broadcasting of
1064 // nonfunctional objects. So what needs to be done here is to
1065 // remove all events for the frame in question.
1066 bAppendEvent = false;
1067 break;
1068 case SwAccessibleEvent_Impl::INVALID_ATTR:
1069 // tdf#150708 if the old is CARET_OR_STATES then try updating it
1070 // with the additional states
1071 if (aEvent.GetType() == SwAccessibleEvent_Impl::CARET_OR_STATES)
1072 aEvent.SetStates(rEvent.GetAllStates());
1073 else
1075 OSL_ENSURE( aEvent.GetType() == SwAccessibleEvent_Impl::INVALID_ATTR,
1076 "invalid event combination" );
1078 break;
1080 if( bAppendEvent )
1082 mpEvents->erase( (*aIter).second );
1083 (*aIter).second = mpEvents->insert( mpEvents->end(), aEvent );
1085 else
1087 mpEvents->erase( (*aIter).second );
1088 mpEventMap->erase( aIter );
1091 else if( SwAccessibleEvent_Impl::DISPOSE != rEvent.GetType() )
1093 mpEventMap->emplace( rEvent.GetFrameOrObj(),
1094 mpEvents->insert( mpEvents->end(), rEvent ) );
1099 void SwAccessibleMap::InvalidateCursorPosition(
1100 const uno::Reference< XAccessible >& rAcc )
1102 SwAccessibleContext *pAccImpl =
1103 static_cast< SwAccessibleContext *>( rAcc.get() );
1104 assert(pAccImpl);
1105 assert(pAccImpl->GetFrame());
1106 if( GetShell()->ActionPend() )
1108 SwAccessibleEvent_Impl aEvent( SwAccessibleEvent_Impl::CARET_OR_STATES,
1109 pAccImpl,
1110 SwAccessibleChild(pAccImpl->GetFrame()),
1111 AccessibleStates::CARET );
1112 AppendEvent( aEvent );
1114 else
1116 FireEvents();
1117 // While firing events the current frame might have
1118 // been disposed because it moved out of the visible area.
1119 // Setting the cursor for such frames is useless and even
1120 // causes asserts.
1121 if( pAccImpl->GetFrame() )
1122 pAccImpl->InvalidateCursorPos();
1126 void SwAccessibleMap::InvalidateShapeSelection()
1128 if( GetShell()->ActionPend() )
1130 SwAccessibleEvent_Impl aEvent(
1131 SwAccessibleEvent_Impl::SHAPE_SELECTION );
1132 AppendEvent( aEvent );
1134 else
1136 FireEvents();
1137 DoInvalidateShapeSelection();
1141 //This method should implement the following functions:
1142 //1.find the shape objects and set the selected state.
1143 //2.find the Swframe objects and set the selected state.
1144 //3.find the paragraph objects and set the selected state.
1145 void SwAccessibleMap::InvalidateShapeInParaSelection()
1147 DBG_TESTSOLARMUTEX();
1149 std::unique_ptr<SwAccessibleObjShape_Impl[]> pShapes;
1150 SwAccessibleObjShape_Impl *pSelShape = nullptr;
1151 size_t nShapes = 0;
1153 const SwViewShell *pVSh = GetShell();
1154 const SwFEShell *pFESh = dynamic_cast<const SwFEShell*>(pVSh);
1155 SwPaM* pCursor = pFESh ? pFESh->GetCursor( false /* ??? */ ) : nullptr;
1157 //const size_t nSelShapes = pFESh ? pFESh->IsObjSelected() : 0;
1159 if( mpShapeMap )
1160 pShapes = mpShapeMap->Copy( nShapes, pFESh, &pSelShape );
1162 bool bIsSelAll =IsDocumentSelAll();
1164 if( mpShapeMap )
1166 //Checked for shapes.
1167 SwAccessibleShapeMap_Impl::const_iterator aIter = mpShapeMap->cbegin();
1168 SwAccessibleShapeMap_Impl::const_iterator aEndIter = mpShapeMap->cend();
1170 if( bIsSelAll)
1172 while( aIter != aEndIter )
1174 uno::Reference < XAccessible > xAcc( (*aIter).second );
1175 if( xAcc.is() )
1176 static_cast < ::accessibility::AccessibleShape* >(xAcc.get())->SetState( AccessibleStateType::SELECTED );
1178 ++aIter;
1181 else
1183 while( aIter != aEndIter )
1185 const SwFrameFormat *pFrameFormat = (*aIter).first ? ::FindFrameFormat( (*aIter).first ) : nullptr;
1186 if( !pFrameFormat )
1188 ++aIter;
1189 continue;
1191 const SwFormatAnchor& rAnchor = pFrameFormat->GetAnchor();
1192 const SwNode *pAnchorNode = rAnchor.GetAnchorNode();
1194 if(rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PAGE)
1196 uno::Reference < XAccessible > xAcc( (*aIter).second );
1197 if(xAcc.is())
1198 static_cast < ::accessibility::AccessibleShape* >(xAcc.get())->ResetState( AccessibleStateType::SELECTED );
1200 ++aIter;
1201 continue;
1204 if( !pAnchorNode )
1206 ++aIter;
1207 continue;
1209 if( pAnchorNode->GetTextNode() )
1211 sal_Int32 nIndex = rAnchor.GetAnchorContentOffset();
1212 bool bMarked = false;
1213 if( pCursor != nullptr )
1215 const SwTextNode* pNode = pAnchorNode->GetTextNode();
1216 SwTextFrame const*const pFrame(static_cast<SwTextFrame*>(pNode->getLayoutFrame(pVSh->GetLayout())));
1217 SwNodeOffset nFirstNode(pFrame->GetTextNodeFirst()->GetIndex());
1218 SwNodeOffset nLastNode;
1219 if (sw::MergedPara const*const pMerged = pFrame->GetMergedPara())
1221 nLastNode = pMerged->pLastNode->GetIndex();
1223 else
1225 nLastNode = nFirstNode;
1228 SwNodeOffset nHere = pNode->GetIndex();
1230 for(SwPaM& rTmpCursor : pCursor->GetRingContainer())
1232 // ignore, if no mark
1233 if( rTmpCursor.HasMark() )
1235 bMarked = true;
1236 // check whether nHere is 'inside' pCursor
1237 SwPosition* pStart = rTmpCursor.Start();
1238 SwNodeOffset nStartIndex = pStart->GetNodeIndex();
1239 SwPosition* pEnd = rTmpCursor.End();
1240 SwNodeOffset nEndIndex = pEnd->GetNodeIndex();
1241 if ((nStartIndex <= nLastNode) && (nFirstNode <= nEndIndex))
1243 if( rAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR )
1245 if( ( ((nHere == nStartIndex) && (nIndex >= pStart->GetContentIndex())) || (nHere > nStartIndex) )
1246 &&( ((nHere == nEndIndex) && (nIndex < pEnd->GetContentIndex())) || (nHere < nEndIndex) ) )
1248 uno::Reference < XAccessible > xAcc( (*aIter).second );
1249 if( xAcc.is() )
1250 static_cast < ::accessibility::AccessibleShape* >(xAcc.get())->SetState( AccessibleStateType::SELECTED );
1252 else
1254 uno::Reference < XAccessible > xAcc( (*aIter).second );
1255 if( xAcc.is() )
1256 static_cast < ::accessibility::AccessibleShape* >(xAcc.get())->ResetState( AccessibleStateType::SELECTED );
1259 else if( rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PARA )
1261 uno::Reference<XAccessible> const xAcc((*aIter).second);
1262 if (xAcc.is())
1264 if (IsSelectFrameAnchoredAtPara(*rAnchor.GetContentAnchor(), *pStart, *pEnd))
1266 static_cast < ::accessibility::AccessibleShape* >(xAcc.get())->SetState( AccessibleStateType::SELECTED );
1268 else
1270 static_cast < ::accessibility::AccessibleShape* >(xAcc.get())->ResetState( AccessibleStateType::SELECTED );
1274 else if (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_CHAR)
1276 uno::Reference<XAccessible> const xAcc((*aIter).second);
1277 if (xAcc.is())
1279 if (IsDestroyFrameAnchoredAtChar(*rAnchor.GetContentAnchor(), *pStart, *pEnd))
1281 static_cast<::accessibility::AccessibleShape*>(xAcc.get())->SetState( AccessibleStateType::SELECTED );
1283 else
1285 static_cast<::accessibility::AccessibleShape*>(xAcc.get())->ResetState( AccessibleStateType::SELECTED );
1293 if( !bMarked )
1295 SwAccessibleObjShape_Impl *pShape = pShapes.get();
1296 size_t nNumShapes = nShapes;
1297 while( nNumShapes )
1299 if( pShape < pSelShape && (pShape->first==(*aIter).first) )
1301 uno::Reference < XAccessible > xAcc( (*aIter).second );
1302 if(xAcc.is())
1303 static_cast < ::accessibility::AccessibleShape* >(xAcc.get())->ResetState( AccessibleStateType::SELECTED );
1305 --nNumShapes;
1306 ++pShape;
1311 ++aIter;
1312 }//while( aIter != aEndIter )
1313 }//else
1316 pShapes.reset();
1318 //Checked for FlyFrame
1319 if (mpFrameMap)
1321 SwAccessibleContextMap_Impl::iterator aIter = mpFrameMap->begin();
1322 while( aIter != mpFrameMap->end() )
1324 const SwFrame *pFrame = (*aIter).first;
1325 if(pFrame->IsFlyFrame())
1327 uno::Reference < XAccessible > xAcc = (*aIter).second;
1329 if(xAcc.is())
1331 SwAccessibleFrameBase *pAccFrame = static_cast< SwAccessibleFrameBase * >(xAcc.get());
1332 bool bFrameChanged = pAccFrame->SetSelectedState( true );
1333 if (bFrameChanged)
1335 const SwFlyFrame *pFlyFrame = static_cast< const SwFlyFrame * >( pFrame );
1336 const SwFrameFormat *pFrameFormat = pFlyFrame->GetFormat();
1337 if (pFrameFormat)
1339 const SwFormatAnchor& rAnchor = pFrameFormat->GetAnchor();
1340 if( rAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR )
1342 uno::Reference< XAccessible > xAccParent = pAccFrame->getAccessibleParent();
1343 if (xAccParent.is())
1345 uno::Reference< XAccessibleContext > xAccContext = xAccParent->getAccessibleContext();
1346 if(xAccContext.is() && xAccContext->getAccessibleRole() == AccessibleRole::PARAGRAPH)
1348 SwAccessibleParagraph* pAccPara = static_cast< SwAccessibleParagraph *>(xAccContext.get());
1349 if(pAccFrame->IsSelectedInDoc())
1351 m_setParaAdd.insert(pAccPara);
1353 else if(m_setParaAdd.count(pAccPara) == 0)
1355 m_setParaRemove.insert(pAccPara);
1364 ++aIter;
1368 typedef std::vector< SwAccessibleContext* > VEC_PARA;
1369 VEC_PARA vecAdd;
1370 VEC_PARA vecRemove;
1371 //Checked for Paras.
1372 bool bMarkChanged = false;
1373 SwAccessibleContextMap_Impl mapTemp;
1374 if( pCursor != nullptr )
1376 for(SwPaM& rTmpCursor : pCursor->GetRingContainer())
1378 if( rTmpCursor.HasMark() )
1380 SwNodeIndex nStartIndex( rTmpCursor.Start()->GetNode() );
1381 SwNodeIndex nEndIndex( rTmpCursor.End()->GetNode() );
1382 for (; nStartIndex <= nEndIndex; ++nStartIndex)
1384 SwFrame *pFrame = nullptr;
1385 if(nStartIndex.GetNode().IsContentNode())
1387 SwContentNode* pCNd = static_cast<SwContentNode*>(&(nStartIndex.GetNode()));
1388 pFrame = SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti>(*pCNd).First();
1389 if (mapTemp.find(pFrame) != mapTemp.end())
1391 continue; // sw_redlinehide: once is enough
1394 else if( nStartIndex.GetNode().IsTableNode() )
1396 SwTableNode * pTable = static_cast<SwTableNode *>(&(nStartIndex.GetNode()));
1397 SwTableFormat* pFormat = pTable->GetTable().GetFrameFormat();
1398 pFrame = SwIterator<SwFrame, SwTableFormat>(*pFormat).First();
1401 if( pFrame && mpFrameMap)
1403 SwAccessibleContextMap_Impl::iterator aIter = mpFrameMap->find( pFrame );
1404 if( aIter != mpFrameMap->end() )
1406 uno::Reference < XAccessible > xAcc = (*aIter).second;
1407 bool isChanged = false;
1408 if( xAcc.is() )
1410 isChanged = static_cast< SwAccessibleContext * >(xAcc.get())->SetSelectedState( true );
1412 if(!isChanged)
1414 SwAccessibleContextMap_Impl::iterator aEraseIter = mpSelectedFrameMap->find( pFrame );
1415 if(aEraseIter != mpSelectedFrameMap->end())
1416 mpSelectedFrameMap->erase(aEraseIter);
1418 else
1420 bMarkChanged = true;
1421 vecAdd.push_back(static_cast< SwAccessibleContext * >(xAcc.get()));
1424 mapTemp.emplace( pFrame, xAcc );
1431 if( !mpSelectedFrameMap )
1432 mpSelectedFrameMap.reset( new SwAccessibleContextMap_Impl );
1433 if( !mpSelectedFrameMap->empty() )
1435 SwAccessibleContextMap_Impl::iterator aIter = mpSelectedFrameMap->begin();
1436 while( aIter != mpSelectedFrameMap->end() )
1438 uno::Reference < XAccessible > xAcc = (*aIter).second;
1439 if(xAcc.is())
1440 static_cast< SwAccessibleContext * >(xAcc.get())->SetSelectedState( false );
1441 ++aIter;
1442 vecRemove.push_back(static_cast< SwAccessibleContext * >(xAcc.get()));
1444 bMarkChanged = true;
1445 mpSelectedFrameMap->clear();
1448 SwAccessibleContextMap_Impl::iterator aIter = mapTemp.begin();
1449 while( aIter != mapTemp.end() )
1451 mpSelectedFrameMap->emplace( (*aIter).first, (*aIter).second );
1452 ++aIter;
1454 mapTemp.clear();
1456 if( !(bMarkChanged && mpFrameMap))
1457 return;
1459 for (SwAccessibleContext* pAccPara : vecAdd)
1461 AccessibleEventObject aEvent;
1462 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED;
1463 if (pAccPara)
1465 pAccPara->FireAccessibleEvent( aEvent );
1468 for (SwAccessibleContext* pAccPara : vecRemove)
1470 AccessibleEventObject aEvent;
1471 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_REMOVE;
1472 if (pAccPara)
1474 pAccPara->FireAccessibleEvent( aEvent );
1479 //Merge with DoInvalidateShapeFocus
1480 void SwAccessibleMap::DoInvalidateShapeSelection(bool bInvalidateFocusMode /*=false*/)
1482 DBG_TESTSOLARMUTEX();
1484 std::unique_ptr<SwAccessibleObjShape_Impl[]> pShapes;
1485 SwAccessibleObjShape_Impl *pSelShape = nullptr;
1486 size_t nShapes = 0;
1488 const SwViewShell *pVSh = GetShell();
1489 const SwFEShell *pFESh = dynamic_cast<const SwFEShell*>(pVSh);
1490 const size_t nSelShapes = pFESh ? pFESh->IsObjSelected() : 0;
1492 //when InvalidateFocus Call this function ,and the current selected shape count is not 1 ,
1493 //return
1494 if (bInvalidateFocusMode && nSelShapes != 1)
1496 return;
1498 if( mpShapeMap )
1499 pShapes = mpShapeMap->Copy( nShapes, pFESh, &pSelShape );
1501 if( !pShapes )
1502 return;
1504 typedef std::vector< ::rtl::Reference < ::accessibility::AccessibleShape > > VEC_SHAPE;
1505 VEC_SHAPE vecxShapeAdd;
1506 VEC_SHAPE vecxShapeRemove;
1507 int nCountSelectedShape=0;
1509 vcl::Window *pWin = GetShell()->GetWin();
1510 bool bFocused = pWin && pWin->HasFocus();
1511 SwAccessibleObjShape_Impl *pShape = pShapes.get();
1512 int nShapeCount = nShapes;
1513 while( nShapeCount )
1515 if (pShape->second.is() && IsInSameLevel(pShape->first, pFESh))
1517 if( pShape < pSelShape )
1519 if(pShape->second->ResetState( AccessibleStateType::SELECTED ))
1521 vecxShapeRemove.push_back(pShape->second);
1523 pShape->second->ResetState( AccessibleStateType::FOCUSED );
1526 --nShapeCount;
1527 ++pShape;
1530 for (const auto& rpShape : vecxShapeRemove)
1532 ::accessibility::AccessibleShape *pAccShape = rpShape.get();
1533 if (pAccShape)
1535 pAccShape->CommitChange(AccessibleEventId::SELECTION_CHANGED_REMOVE, uno::Any(), uno::Any(), -1);
1539 pShape = pShapes.get();
1541 while( nShapes )
1543 if (pShape->second.is() && IsInSameLevel(pShape->first, pFESh))
1545 if( pShape >= pSelShape )
1547 //first fire focus event
1548 if( bFocused && 1 == nSelShapes )
1549 pShape->second->SetState( AccessibleStateType::FOCUSED );
1550 else
1551 pShape->second->ResetState( AccessibleStateType::FOCUSED );
1553 if(pShape->second->SetState( AccessibleStateType::SELECTED ))
1555 vecxShapeAdd.push_back(pShape->second);
1557 ++nCountSelectedShape;
1561 --nShapes;
1562 ++pShape;
1565 const unsigned int SELECTION_WITH_NUM = 10;
1566 if (vecxShapeAdd.size() > SELECTION_WITH_NUM )
1568 uno::Reference< XAccessible > xDoc = GetDocumentView( );
1569 SwAccessibleContext * pCont = static_cast<SwAccessibleContext *>(xDoc.get());
1570 if (pCont)
1572 AccessibleEventObject aEvent;
1573 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_WITHIN;
1574 pCont->FireAccessibleEvent(aEvent);
1577 else
1579 short nEventID = AccessibleEventId::SELECTION_CHANGED_ADD;
1580 if (nCountSelectedShape <= 1 && vecxShapeAdd.size() == 1 )
1582 nEventID = AccessibleEventId::SELECTION_CHANGED;
1584 for (const auto& rpShape : vecxShapeAdd)
1586 ::accessibility::AccessibleShape *pAccShape = rpShape.get();
1587 if (pAccShape)
1589 pAccShape->CommitChange(nEventID, uno::Any(), uno::Any(), -1);
1594 for (const auto& rpShape : vecxShapeAdd)
1596 ::accessibility::AccessibleShape *pAccShape = rpShape.get();
1597 if (pAccShape)
1599 SdrObject *pObj = SdrObject::getSdrObjectFromXShape(pAccShape->GetXShape());
1600 SwFrameFormat *pFrameFormat = pObj ? FindFrameFormat( pObj ) : nullptr;
1601 if (pFrameFormat)
1603 const SwFormatAnchor& rAnchor = pFrameFormat->GetAnchor();
1604 if( rAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR )
1606 uno::Reference< XAccessible > xPara = pAccShape->getAccessibleParent();
1607 if (xPara.is())
1609 uno::Reference< XAccessibleContext > xParaContext = xPara->getAccessibleContext();
1610 if (xParaContext.is() && xParaContext->getAccessibleRole() == AccessibleRole::PARAGRAPH)
1612 SwAccessibleParagraph* pAccPara = static_cast< SwAccessibleParagraph *>(xPara.get());
1613 if (pAccPara)
1615 m_setParaAdd.insert(pAccPara);
1623 for (const auto& rpShape : vecxShapeRemove)
1625 ::accessibility::AccessibleShape *pAccShape = rpShape.get();
1626 if (pAccShape && !pAccShape->IsDisposed())
1628 uno::Reference< XAccessible > xPara = pAccShape->getAccessibleParent();
1629 uno::Reference< XAccessibleContext > xParaContext = xPara->getAccessibleContext();
1630 if (xParaContext.is() && xParaContext->getAccessibleRole() == AccessibleRole::PARAGRAPH)
1632 SwAccessibleParagraph* pAccPara = static_cast< SwAccessibleParagraph *>(xPara.get());
1633 if (m_setParaAdd.count(pAccPara) == 0 )
1635 m_setParaRemove.insert(pAccPara);
1642 SwAccessibleMap::SwAccessibleMap( SwViewShell *pSh ) :
1643 mpVSh( pSh ),
1644 mbShapeSelected( false ),
1645 maDocName(SwAccessibleContext::GetResource(STR_ACCESS_DOC_NAME))
1647 pSh->GetLayout()->AddAccessibleShell();
1650 SwAccessibleMap::~SwAccessibleMap()
1652 DBG_TESTSOLARMUTEX();
1654 uno::Reference < XAccessible > xAcc;
1655 if( mpFrameMap )
1657 const SwRootFrame *pRootFrame = GetShell()->GetLayout();
1658 SwAccessibleContextMap_Impl::iterator aIter = mpFrameMap->find( pRootFrame );
1659 if( aIter != mpFrameMap->end() )
1660 xAcc = (*aIter).second;
1661 if( !xAcc.is() )
1662 assert(false); // let's hope this can't happen? the vcl::Window apparently owns the top-level
1663 //xAcc = new SwAccessibleDocument(shared_from_this());
1666 if(xAcc.is())
1668 SwAccessibleDocumentBase *const pAcc =
1669 static_cast<SwAccessibleDocumentBase *>(xAcc.get());
1670 pAcc->Dispose( true );
1672 #if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
1673 if( mpFrameMap )
1675 SwAccessibleContextMap_Impl::iterator aIter = mpFrameMap->begin();
1676 while( aIter != mpFrameMap->end() )
1678 uno::Reference < XAccessible > xTmp = (*aIter).second;
1679 if( xTmp.is() )
1681 SwAccessibleContext *pTmp = static_cast< SwAccessibleContext * >( xTmp.get() );
1682 assert(pTmp->GetMap() == nullptr); // must be disposed
1684 ++aIter;
1687 #endif
1688 assert((!mpFrameMap || mpFrameMap->empty()) &&
1689 "Frame map should be empty after disposing the root frame");
1690 assert((!mpShapeMap || mpShapeMap->empty()) &&
1691 "Object map should be empty after disposing the root frame");
1692 mpFrameMap.reset();
1693 mpShapeMap.reset();
1694 mvShapes.clear();
1695 mpSelectedParas.reset();
1697 mpPreview.reset();
1700 osl::MutexGuard aGuard( maEventMutex );
1701 assert(!mpEvents);
1702 assert(!mpEventMap);
1703 mpEventMap.reset();
1704 mpEvents.reset();
1706 mpVSh->GetLayout()->RemoveAccessibleShell();
1709 uno::Reference< XAccessible > SwAccessibleMap::GetDocumentView_(
1710 bool bPagePreview )
1712 DBG_TESTSOLARMUTEX();
1714 uno::Reference < XAccessible > xAcc;
1715 bool bSetVisArea = false;
1717 if( !mpFrameMap )
1719 mpFrameMap.reset(new SwAccessibleContextMap_Impl);
1720 #if OSL_DEBUG_LEVEL > 0
1721 mpFrameMap->mbLocked = false;
1722 #endif
1725 #if OSL_DEBUG_LEVEL > 0
1726 assert(!mpFrameMap->mbLocked);
1727 mpFrameMap->mbLocked = true;
1728 #endif
1730 const SwRootFrame *pRootFrame = GetShell()->GetLayout();
1731 SwAccessibleContextMap_Impl::iterator aIter = mpFrameMap->find( pRootFrame );
1732 if( aIter != mpFrameMap->end() )
1733 xAcc = (*aIter).second;
1734 if( xAcc.is() )
1736 bSetVisArea = true; // Set VisArea when map mutex is not locked
1738 else
1740 if( bPagePreview )
1741 xAcc = new SwAccessiblePreview(shared_from_this());
1742 else
1743 xAcc = new SwAccessibleDocument(shared_from_this());
1745 if( aIter != mpFrameMap->end() )
1747 (*aIter).second = xAcc;
1749 else
1751 mpFrameMap->emplace( pRootFrame, xAcc );
1755 #if OSL_DEBUG_LEVEL > 0
1756 mpFrameMap->mbLocked = false;
1757 #endif
1759 if( bSetVisArea )
1761 SwAccessibleDocumentBase *pAcc =
1762 static_cast< SwAccessibleDocumentBase * >( xAcc.get() );
1763 pAcc->SetVisArea();
1766 return xAcc;
1769 uno::Reference< XAccessible > SwAccessibleMap::GetDocumentView( )
1771 return GetDocumentView_( false );
1774 uno::Reference<XAccessible> SwAccessibleMap::GetDocumentPreview(
1775 const std::vector<std::unique_ptr<PreviewPage>>& _rPreviewPages,
1776 const Fraction& _rScale,
1777 const SwPageFrame* _pSelectedPageFrame,
1778 const Size& _rPreviewWinSize )
1780 // create & update preview data object
1781 if( mpPreview == nullptr )
1782 mpPreview.reset( new SwAccPreviewData() );
1783 mpPreview->Update( *this, _rPreviewPages, _rScale, _pSelectedPageFrame, _rPreviewWinSize );
1785 uno::Reference<XAccessible> xAcc = GetDocumentView_( true );
1786 return xAcc;
1789 uno::Reference< XAccessible> SwAccessibleMap::GetContext( const SwFrame *pFrame,
1790 bool bCreate )
1792 DBG_TESTSOLARMUTEX();
1794 uno::Reference < XAccessible > xAcc;
1795 uno::Reference < XAccessible > xOldCursorAcc;
1796 bool bOldShapeSelected = false;
1798 if( !mpFrameMap && bCreate )
1799 mpFrameMap.reset(new SwAccessibleContextMap_Impl);
1800 if( mpFrameMap )
1802 SwAccessibleContextMap_Impl::iterator aIter = mpFrameMap->find( pFrame );
1803 if( aIter != mpFrameMap->end() )
1804 xAcc = (*aIter).second;
1806 if( !xAcc.is() && bCreate )
1808 rtl::Reference<SwAccessibleContext> pAcc;
1809 switch( pFrame->GetType() )
1811 case SwFrameType::Txt:
1812 pAcc = new SwAccessibleParagraph(shared_from_this(),
1813 static_cast< const SwTextFrame& >( *pFrame ) );
1814 break;
1815 case SwFrameType::Header:
1816 pAcc = new SwAccessibleHeaderFooter(shared_from_this(),
1817 static_cast< const SwHeaderFrame *>( pFrame ) );
1818 break;
1819 case SwFrameType::Footer:
1820 pAcc = new SwAccessibleHeaderFooter(shared_from_this(),
1821 static_cast< const SwFooterFrame *>( pFrame ) );
1822 break;
1823 case SwFrameType::Ftn:
1825 const SwFootnoteFrame *pFootnoteFrame =
1826 static_cast < const SwFootnoteFrame * >( pFrame );
1827 bool bIsEndnote =
1828 SwAccessibleFootnote::IsEndnote( pFootnoteFrame );
1829 pAcc = new SwAccessibleFootnote(shared_from_this(), bIsEndnote,
1830 /*(bIsEndnote ? mnEndnote++ : mnFootnote++),*/
1831 pFootnoteFrame );
1833 break;
1834 case SwFrameType::Fly:
1836 const SwFlyFrame *pFlyFrame =
1837 static_cast < const SwFlyFrame * >( pFrame );
1838 switch( SwAccessibleFrameBase::GetNodeType( pFlyFrame ) )
1840 case SwNodeType::Grf:
1841 pAcc = new SwAccessibleGraphic(shared_from_this(), pFlyFrame );
1842 break;
1843 case SwNodeType::Ole:
1844 pAcc = new SwAccessibleEmbeddedObject(shared_from_this(), pFlyFrame );
1845 break;
1846 default:
1847 pAcc = new SwAccessibleTextFrame(shared_from_this(), *pFlyFrame );
1848 break;
1851 break;
1852 case SwFrameType::Cell:
1853 pAcc = new SwAccessibleCell(shared_from_this(),
1854 static_cast< const SwCellFrame *>( pFrame ) );
1855 break;
1856 case SwFrameType::Tab:
1857 pAcc = new SwAccessibleTable(shared_from_this(),
1858 static_cast< const SwTabFrame *>( pFrame ) );
1859 break;
1860 case SwFrameType::Page:
1861 OSL_ENSURE( GetShell()->IsPreview(),
1862 "accessible page frames only in PagePreview" );
1863 pAcc = new SwAccessiblePage(shared_from_this(), pFrame);
1864 break;
1865 default: break;
1867 xAcc = pAcc;
1868 assert(xAcc.is());
1870 if( aIter != mpFrameMap->end() )
1872 (*aIter).second = xAcc;
1874 else
1876 mpFrameMap->emplace( pFrame, xAcc );
1879 if( pAcc->HasCursor() &&
1880 !AreInSameTable( mxCursorContext, pFrame ) )
1882 // If the new context has the focus, and if we know
1883 // another context that had the focus, then the focus
1884 // just moves from the old context to the new one. We
1885 // then have to send a focus event and a caret event for
1886 // the old context. We have to do that now,
1887 // because after we have left this method, anyone might
1888 // call getStates for the new context and will get a
1889 // focused state then. Sending the focus changes event
1890 // after that seems to be strange. However, we cannot
1891 // send a focus event for the new context now, because
1892 // no one except us knows it. In any case, we remember
1893 // the new context as the one that has the focus
1894 // currently.
1896 xOldCursorAcc = mxCursorContext;
1897 mxCursorContext = xAcc;
1899 bOldShapeSelected = mbShapeSelected;
1900 mbShapeSelected = false;
1905 // Invalidate focus for old object when map is not locked
1906 if( xOldCursorAcc.is() )
1907 InvalidateCursorPosition( xOldCursorAcc );
1908 if( bOldShapeSelected )
1909 InvalidateShapeSelection();
1911 return xAcc;
1914 ::rtl::Reference < SwAccessibleContext > SwAccessibleMap::GetContextImpl(
1915 const SwFrame *pFrame,
1916 bool bCreate )
1918 uno::Reference < XAccessible > xAcc( GetContext( pFrame, bCreate ) );
1920 ::rtl::Reference < SwAccessibleContext > xAccImpl(
1921 static_cast< SwAccessibleContext * >( xAcc.get() ) );
1923 return xAccImpl;
1926 uno::Reference< XAccessible> SwAccessibleMap::GetContext(
1927 const SdrObject *pObj,
1928 SwAccessibleContext *pParentImpl,
1929 bool bCreate )
1931 DBG_TESTSOLARMUTEX();
1933 uno::Reference < XAccessible > xAcc;
1934 uno::Reference < XAccessible > xOldCursorAcc;
1936 if( !mpShapeMap && bCreate )
1937 mpShapeMap.reset(new SwAccessibleShapeMap_Impl( this ));
1938 if( mpShapeMap )
1940 SwAccessibleShapeMap_Impl::iterator aIter = mpShapeMap->find( pObj );
1941 if( aIter != mpShapeMap->end() )
1942 xAcc = (*aIter).second;
1944 if( !xAcc.is() && bCreate )
1946 rtl::Reference< ::accessibility::AccessibleShape> pAcc;
1947 uno::Reference < drawing::XShape > xShape(
1948 const_cast< SdrObject * >( pObj )->getUnoShape(),
1949 uno::UNO_QUERY );
1950 if( xShape.is() )
1952 ::accessibility::ShapeTypeHandler& rShapeTypeHandler =
1953 ::accessibility::ShapeTypeHandler::Instance();
1954 uno::Reference < XAccessible > xParent( pParentImpl );
1955 ::accessibility::AccessibleShapeInfo aShapeInfo(
1956 xShape, xParent, this );
1958 pAcc = rShapeTypeHandler.CreateAccessibleObject(
1959 aShapeInfo, mpShapeMap->GetInfo() );
1961 xAcc = pAcc.get();
1962 assert(xAcc.is());
1963 pAcc->Init();
1964 if( aIter != mpShapeMap->end() )
1966 (*aIter).second = xAcc;
1968 else
1970 mpShapeMap->emplace( pObj, xAcc );
1972 // TODO: focus!!!
1973 AddGroupContext(pObj, xAcc);
1977 // Invalidate focus for old object when map is not locked
1978 if( xOldCursorAcc.is() )
1979 InvalidateCursorPosition( xOldCursorAcc );
1981 return xAcc;
1984 bool SwAccessibleMap::IsInSameLevel(const SdrObject* pObj, const SwFEShell* pFESh)
1986 if (pFESh)
1987 return pFESh->IsObjSameLevelWithMarked(pObj);
1988 return false;
1991 void SwAccessibleMap::AddShapeContext(const SdrObject *pObj, uno::Reference < XAccessible > const & xAccShape)
1993 DBG_TESTSOLARMUTEX();
1995 if( mpShapeMap )
1997 mpShapeMap->emplace( pObj, xAccShape );
2001 //Added by yanjun for sym2_6407
2002 void SwAccessibleMap::RemoveGroupContext(const SdrObject *pParentObj)
2004 DBG_TESTSOLARMUTEX();
2006 // TODO: Why are sub-shapes of group shapes even added to our map?
2007 // Doesn't the AccessibleShape of the top-level shape create them
2008 // on demand anyway? Why does SwAccessibleMap need to know them?
2009 // We cannot rely on getAccessibleChild here to remove the sub-shapes
2010 // from mpShapes because the top-level shape may not only be disposed here
2011 // but also by visibility checks in svx, then it doesn't return children.
2012 if (mpShapeMap && pParentObj && pParentObj->IsGroupObject())
2014 SdrObjList *const pChildren(pParentObj->GetSubList());
2015 for (size_t i = 0; pChildren && i < pChildren->GetObjCount(); ++i)
2017 SdrObject *const pChild(pChildren->GetObj(i));
2018 assert(pChild);
2019 RemoveContext(pChild);
2023 //End
2025 void SwAccessibleMap::AddGroupContext(const SdrObject *pParentObj, uno::Reference < XAccessible > const & xAccParent)
2027 DBG_TESTSOLARMUTEX();
2029 if( !mpShapeMap )
2030 return;
2032 //here get all the sub list.
2033 if (!pParentObj->IsGroupObject())
2034 return;
2036 if (!xAccParent.is())
2037 return;
2039 uno::Reference < XAccessibleContext > xContext = xAccParent->getAccessibleContext();
2040 if (!xContext.is())
2041 return;
2043 sal_Int64 nChildren = xContext->getAccessibleChildCount();
2044 for(sal_Int64 i = 0; i<nChildren; i++)
2046 uno::Reference < XAccessible > xChild = xContext->getAccessibleChild(i);
2047 if (xChild.is())
2049 uno::Reference < XAccessibleContext > xChildContext = xChild->getAccessibleContext();
2050 if (xChildContext.is())
2052 short nRole = xChildContext->getAccessibleRole();
2053 if (nRole == AccessibleRole::SHAPE)
2055 ::accessibility::AccessibleShape* pAccShape = static_cast < ::accessibility::AccessibleShape* >( xChild.get());
2056 uno::Reference < drawing::XShape > xShape = pAccShape->GetXShape();
2057 if (xShape.is())
2059 SdrObject* pObj = SdrObject::getSdrObjectFromXShape(xShape);
2060 AddShapeContext(pObj, xChild);
2061 AddGroupContext(pObj,xChild);
2069 ::rtl::Reference < ::accessibility::AccessibleShape > SwAccessibleMap::GetContextImpl(
2070 const SdrObject *pObj,
2071 SwAccessibleContext *pParentImpl,
2072 bool bCreate )
2074 uno::Reference < XAccessible > xAcc( GetContext( pObj, pParentImpl, bCreate ) );
2076 ::rtl::Reference < ::accessibility::AccessibleShape > xAccImpl(
2077 static_cast< ::accessibility::AccessibleShape* >( xAcc.get() ) );
2079 return xAccImpl;
2082 void SwAccessibleMap::RemoveContext( const SwFrame *pFrame )
2084 DBG_TESTSOLARMUTEX();
2086 if( !mpFrameMap )
2087 return;
2089 SwAccessibleContextMap_Impl::iterator aIter =
2090 mpFrameMap->find( pFrame );
2091 if( aIter == mpFrameMap->end() )
2092 return;
2094 mpFrameMap->erase( aIter );
2096 if (mpSelectedFrameMap)
2098 SwAccessibleContextMap_Impl::iterator aSelectedIter = mpSelectedFrameMap->find(pFrame);
2099 if (aSelectedIter != mpSelectedFrameMap->end())
2100 mpSelectedFrameMap->erase(aSelectedIter);
2103 // Remove reference to old caret object. Though mxCursorContext
2104 // is a weak reference and cleared automatically, clearing it
2105 // directly makes sure to not keep a non-functional object.
2106 uno::Reference < XAccessible > xOldAcc( mxCursorContext );
2107 if( xOldAcc.is() )
2109 SwAccessibleContext *pOldAccImpl =
2110 static_cast< SwAccessibleContext *>( xOldAcc.get() );
2111 OSL_ENSURE( pOldAccImpl->GetFrame(), "old caret context is disposed" );
2112 if( pOldAccImpl->GetFrame() == pFrame )
2114 xOldAcc.clear(); // get an empty ref
2115 mxCursorContext = xOldAcc;
2119 if( mpFrameMap->empty() )
2121 mpFrameMap.reset();
2125 void SwAccessibleMap::RemoveContext( const SdrObject *pObj )
2127 DBG_TESTSOLARMUTEX();
2129 if( !mpShapeMap )
2130 return;
2132 SwAccessibleShapeMap_Impl::iterator aIter = mpShapeMap->find( pObj );
2133 if( aIter == mpShapeMap->end() )
2134 return;
2136 uno::Reference < XAccessible > xTempHold( (*aIter).second );
2137 mpShapeMap->erase( aIter );
2138 RemoveGroupContext(pObj);
2139 // The shape selection flag is not cleared, but one might do
2140 // so but has to make sure that the removed context is the one
2141 // that is selected.
2143 if( mpShapeMap && mpShapeMap->empty() )
2145 mpShapeMap.reset();
2149 bool SwAccessibleMap::Contains(const SwFrame *pFrame) const
2151 return (pFrame && mpFrameMap && mpFrameMap->find(pFrame) != mpFrameMap->end());
2154 void SwAccessibleMap::A11yDispose( const SwFrame *pFrame,
2155 const SdrObject *pObj,
2156 vcl::Window* pWindow,
2157 bool bRecursive,
2158 bool bCanSkipInvisible )
2160 DBG_TESTSOLARMUTEX();
2162 SwAccessibleChild aFrameOrObj( pFrame, pObj, pWindow );
2164 // Indeed, the following assert checks the frame's accessible flag,
2165 // because that's the one that is evaluated in the layout. The frame
2166 // might not be accessible anyway. That's the case for cell frames that
2167 // contain further cells.
2168 OSL_ENSURE( !aFrameOrObj.GetSwFrame() || aFrameOrObj.GetSwFrame()->IsAccessibleFrame(),
2169 "non accessible frame should be disposed" );
2171 if (!(aFrameOrObj.IsAccessible(GetShell()->IsPreview())
2172 // fdo#87199 dispose the darn thing if it ever was accessible
2173 || Contains(pFrame)))
2174 return;
2176 ::rtl::Reference< SwAccessibleContext > xAccImpl;
2177 ::rtl::Reference< SwAccessibleContext > xParentAccImpl;
2178 ::rtl::Reference< ::accessibility::AccessibleShape > xShapeAccImpl;
2179 // get accessible context for frame
2181 // First of all look for an accessible context for a frame
2182 if( aFrameOrObj.GetSwFrame() && mpFrameMap )
2184 SwAccessibleContextMap_Impl::iterator aIter =
2185 mpFrameMap->find( aFrameOrObj.GetSwFrame() );
2186 if( aIter != mpFrameMap->end() )
2188 uno::Reference < XAccessible > xAcc( (*aIter).second );
2189 xAccImpl = static_cast< SwAccessibleContext *>( xAcc.get() );
2192 if( !xAccImpl.is() && mpFrameMap )
2194 // If there is none, look if the parent is accessible.
2195 const SwFrame *pParent =
2196 SwAccessibleFrame::GetParent( aFrameOrObj,
2197 GetShell()->IsPreview());
2199 if( pParent )
2201 SwAccessibleContextMap_Impl::iterator aIter =
2202 mpFrameMap->find( pParent );
2203 if( aIter != mpFrameMap->end() )
2205 uno::Reference < XAccessible > xAcc( (*aIter).second );
2206 xParentAccImpl =
2207 static_cast< SwAccessibleContext *>( xAcc.get() );
2211 if( !xParentAccImpl.is() && !aFrameOrObj.GetSwFrame() && mpShapeMap )
2213 SwAccessibleShapeMap_Impl::iterator aIter =
2214 mpShapeMap->find( aFrameOrObj.GetDrawObject() );
2215 if( aIter != mpShapeMap->end() )
2217 uno::Reference < XAccessible > xAcc( (*aIter).second );
2218 xShapeAccImpl =
2219 static_cast< ::accessibility::AccessibleShape *>( xAcc.get() );
2222 if( pObj && GetShell()->ActionPend() &&
2223 (xParentAccImpl.is() || xShapeAccImpl.is()) )
2225 // Keep a reference to the XShape to avoid that it
2226 // is deleted with a SwFrameFormat::SwClientNotify.
2227 uno::Reference < drawing::XShape > xShape(
2228 const_cast< SdrObject * >( pObj )->getUnoShape(),
2229 uno::UNO_QUERY );
2230 if( xShape.is() )
2232 mvShapes.push_back( xShape );
2237 // remove events stored for the frame
2239 osl::MutexGuard aGuard( maEventMutex );
2240 if( mpEvents )
2242 SwAccessibleEventMap_Impl::iterator aIter =
2243 mpEventMap->find( aFrameOrObj );
2244 if( aIter != mpEventMap->end() )
2246 SwAccessibleEvent_Impl aEvent(
2247 SwAccessibleEvent_Impl::DISPOSE, aFrameOrObj );
2248 AppendEvent( aEvent );
2253 // If the frame is accessible and there is a context for it, dispose
2254 // the frame. If the frame is no context for it but disposing should
2255 // take place recursive, the frame's children have to be disposed
2256 // anyway, so we have to create the context then.
2257 if( xAccImpl.is() )
2259 xAccImpl->Dispose( bRecursive );
2261 else if( xParentAccImpl.is() )
2263 // If the frame is a cell frame, the table must be notified.
2264 // If we are in an action, a table model change event will
2265 // be broadcasted at the end of the action to give the table
2266 // a chance to generate a single table change event.
2268 xParentAccImpl->DisposeChild( aFrameOrObj, bRecursive, bCanSkipInvisible );
2270 else if( xShapeAccImpl.is() )
2272 RemoveContext( aFrameOrObj.GetDrawObject() );
2273 xShapeAccImpl->dispose();
2276 if( mpPreview && pFrame && pFrame->IsPageFrame() )
2277 mpPreview->DisposePage( static_cast< const SwPageFrame *>( pFrame ) );
2280 void SwAccessibleMap::InvalidatePosOrSize( const SwFrame *pFrame,
2281 const SdrObject *pObj,
2282 vcl::Window* pWindow,
2283 const SwRect& rOldBox )
2285 DBG_TESTSOLARMUTEX();
2287 SwAccessibleChild aFrameOrObj( pFrame, pObj, pWindow );
2288 if( !aFrameOrObj.IsAccessible( GetShell()->IsPreview() ) )
2289 return;
2291 ::rtl::Reference< SwAccessibleContext > xAccImpl;
2292 ::rtl::Reference< SwAccessibleContext > xParentAccImpl;
2293 const SwFrame *pParent =nullptr;
2294 if( mpFrameMap )
2296 if( aFrameOrObj.GetSwFrame() )
2298 SwAccessibleContextMap_Impl::iterator aIter =
2299 mpFrameMap->find( aFrameOrObj.GetSwFrame() );
2300 if( aIter != mpFrameMap->end() )
2302 // If there is an accessible object already it is
2303 // notified directly.
2304 uno::Reference < XAccessible > xAcc( (*aIter).second );
2305 xAccImpl =
2306 static_cast< SwAccessibleContext *>( xAcc.get() );
2309 if( !xAccImpl.is() )
2311 // Otherwise we look if the parent is accessible.
2312 // If not, there is nothing to do.
2313 pParent =
2314 SwAccessibleFrame::GetParent( aFrameOrObj,
2315 GetShell()->IsPreview());
2317 if( pParent )
2319 SwAccessibleContextMap_Impl::iterator aIter =
2320 mpFrameMap->find( pParent );
2321 if( aIter != mpFrameMap->end() )
2323 uno::Reference < XAccessible > xAcc( (*aIter).second );
2324 xParentAccImpl =
2325 static_cast< SwAccessibleContext *>( xAcc.get() );
2331 if( xAccImpl.is() )
2333 if( GetShell()->ActionPend() )
2335 SwAccessibleEvent_Impl aEvent(
2336 SwAccessibleEvent_Impl::POS_CHANGED, xAccImpl.get(),
2337 aFrameOrObj, rOldBox );
2338 AppendEvent( aEvent );
2340 else
2342 FireEvents();
2343 if (xAccImpl->GetFrame()) // not if disposed by FireEvents()
2345 xAccImpl->InvalidatePosOrSize(rOldBox);
2349 else if( xParentAccImpl.is() )
2351 if( GetShell()->ActionPend() )
2353 assert(pParent);
2354 // tdf#99722 faster not to buffer events that won't be sent
2355 if (!SwAccessibleChild(pParent).IsVisibleChildrenOnly()
2356 || xParentAccImpl->IsShowing(rOldBox)
2357 || xParentAccImpl->IsShowing(*this, aFrameOrObj))
2359 SwAccessibleEvent_Impl aEvent(
2360 SwAccessibleEvent_Impl::CHILD_POS_CHANGED,
2361 xParentAccImpl.get(), aFrameOrObj, rOldBox );
2362 AppendEvent( aEvent );
2365 else
2367 FireEvents();
2368 xParentAccImpl->InvalidateChildPosOrSize( aFrameOrObj,
2369 rOldBox );
2372 else if(pParent)
2375 For child graphic and its parent paragraph,if split 2 graphic to 2 paragraph,
2376 will delete one graphic swfrm and new create 1 graphic swfrm ,
2377 then the new paragraph and the new graphic SwFrame will add .
2378 but when add graphic SwFrame ,the accessible of the new Paragraph is not created yet.
2379 so the new graphic accessible 'parent is NULL,
2380 so run here: save the parent's SwFrame not the accessible object parent,
2382 bool bIsValidFrame = false;
2383 bool bIsTextParent = false;
2384 if (aFrameOrObj.GetSwFrame())
2386 if (SwFrameType::Fly == pFrame->GetType())
2388 bIsValidFrame =true;
2391 else if(pObj)
2393 if (SwFrameType::Txt == pParent->GetType())
2395 bIsTextParent =true;
2398 if( bIsValidFrame || bIsTextParent )
2400 if( GetShell()->ActionPend() )
2402 SwAccessibleEvent_Impl aEvent(
2403 SwAccessibleEvent_Impl::CHILD_POS_CHANGED,
2404 pParent, aFrameOrObj, rOldBox );
2405 AppendEvent( aEvent );
2407 else
2409 OSL_ENSURE(false,"");
2415 void SwAccessibleMap::InvalidateContent( const SwFrame *pFrame )
2417 DBG_TESTSOLARMUTEX();
2419 SwAccessibleChild aFrameOrObj( pFrame );
2420 if( !aFrameOrObj.IsAccessible( GetShell()->IsPreview() ) )
2421 return;
2423 if (!mpFrameMap)
2424 return;
2426 uno::Reference < XAccessible > xAcc;
2427 SwAccessibleContextMap_Impl::iterator aIter =
2428 mpFrameMap->find( aFrameOrObj.GetSwFrame() );
2429 if( aIter != mpFrameMap->end() )
2430 xAcc = (*aIter).second;
2432 if( !xAcc.is() )
2433 return;
2435 SwAccessibleContext *pAccImpl =
2436 static_cast< SwAccessibleContext *>( xAcc.get() );
2437 if( GetShell()->ActionPend() )
2439 SwAccessibleEvent_Impl aEvent(
2440 SwAccessibleEvent_Impl::INVALID_CONTENT, pAccImpl,
2441 std::move(aFrameOrObj) );
2442 AppendEvent( aEvent );
2444 else
2446 FireEvents();
2447 pAccImpl->InvalidateContent();
2451 void SwAccessibleMap::InvalidateAttr( const SwTextFrame& rTextFrame )
2453 DBG_TESTSOLARMUTEX();
2455 SwAccessibleChild aFrameOrObj( &rTextFrame );
2456 if( !aFrameOrObj.IsAccessible( GetShell()->IsPreview() ) )
2457 return;
2459 if (!mpFrameMap)
2460 return;
2462 uno::Reference < XAccessible > xAcc;
2463 SwAccessibleContextMap_Impl::iterator aIter =
2464 mpFrameMap->find( aFrameOrObj.GetSwFrame() );
2465 if( aIter != mpFrameMap->end() )
2466 xAcc = (*aIter).second;
2468 if( !xAcc.is() )
2469 return;
2471 SwAccessibleContext *pAccImpl =
2472 static_cast< SwAccessibleContext *>( xAcc.get() );
2473 if( GetShell()->ActionPend() )
2475 SwAccessibleEvent_Impl aEvent( SwAccessibleEvent_Impl::INVALID_ATTR,
2476 pAccImpl, std::move(aFrameOrObj) );
2477 aEvent.SetStates( AccessibleStates::TEXT_ATTRIBUTE_CHANGED );
2478 AppendEvent( aEvent );
2480 else
2482 FireEvents();
2483 pAccImpl->InvalidateAttr();
2487 void SwAccessibleMap::InvalidateCursorPosition( const SwFrame *pFrame )
2489 DBG_TESTSOLARMUTEX();
2491 SwAccessibleChild aFrameOrObj( pFrame );
2492 bool bShapeSelected = false;
2493 const SwViewShell *pVSh = GetShell();
2494 if( auto pCSh = dynamic_cast<const SwCursorShell*>(pVSh) )
2496 if( pCSh->IsTableMode() )
2498 while( aFrameOrObj.GetSwFrame() && !aFrameOrObj.GetSwFrame()->IsCellFrame() )
2499 aFrameOrObj = aFrameOrObj.GetSwFrame()->GetUpper();
2501 else if( auto pFESh = dynamic_cast<const SwFEShell*>(pVSh) )
2503 const SwFrame *pFlyFrame = pFESh->GetSelectedFlyFrame();
2504 if( pFlyFrame )
2506 OSL_ENSURE( !pFrame || pFrame->FindFlyFrame() == pFlyFrame,
2507 "cursor is not contained in fly frame" );
2508 aFrameOrObj = pFlyFrame;
2510 else if( pFESh->IsObjSelected() > 0 )
2512 bShapeSelected = true;
2513 aFrameOrObj = static_cast<const SwFrame *>( nullptr );
2518 OSL_ENSURE( bShapeSelected || aFrameOrObj.IsAccessible(GetShell()->IsPreview()),
2519 "frame is not accessible" );
2521 uno::Reference < XAccessible > xOldAcc;
2522 uno::Reference < XAccessible > xAcc;
2523 bool bOldShapeSelected = false;
2526 xOldAcc = mxCursorContext;
2527 mxCursorContext = xAcc; // clear reference
2529 bOldShapeSelected = mbShapeSelected;
2530 mbShapeSelected = bShapeSelected;
2532 if( aFrameOrObj.GetSwFrame() && mpFrameMap )
2534 SwAccessibleContextMap_Impl::iterator aIter =
2535 mpFrameMap->find( aFrameOrObj.GetSwFrame() );
2536 if( aIter != mpFrameMap->end() )
2537 xAcc = (*aIter).second;
2538 else
2540 SwRect rcEmpty;
2541 const SwTabFrame* pTabFrame = aFrameOrObj.GetSwFrame()->FindTabFrame();
2542 if (pTabFrame)
2544 InvalidatePosOrSize(pTabFrame, nullptr, nullptr, rcEmpty);
2546 else
2548 InvalidatePosOrSize(aFrameOrObj.GetSwFrame(), nullptr, nullptr, rcEmpty);
2551 aIter = mpFrameMap->find( aFrameOrObj.GetSwFrame() );
2552 if( aIter != mpFrameMap->end() )
2554 xAcc = (*aIter).second;
2558 // For cells, some extra thoughts are necessary,
2559 // because invalidating the cursor for one cell
2560 // invalidates the cursor for all cells of the same
2561 // table. For this reason, we don't want to
2562 // invalidate the cursor for the old cursor object
2563 // and the new one if they are within the same table,
2564 // because this would result in doing the work twice.
2565 // Moreover, we have to make sure to invalidate the
2566 // cursor even if the current cell has no accessible object.
2567 // If the old cursor objects exists and is in the same
2568 // table, it's the best choice, because using it avoids
2569 // an unnecessary cursor invalidation cycle when creating
2570 // a new object for the current cell.
2571 if( aFrameOrObj.GetSwFrame()->IsCellFrame() )
2573 if( xOldAcc.is() &&
2574 AreInSameTable( xOldAcc, aFrameOrObj.GetSwFrame() ) )
2576 if( xAcc.is() )
2577 xOldAcc = xAcc; // avoid extra invalidation
2578 else
2579 xAcc = xOldAcc; // make sure at least one
2581 if( !xAcc.is() )
2582 xAcc = GetContext( aFrameOrObj.GetSwFrame() );
2585 else if (bShapeSelected)
2587 const SwFEShell *pFESh = static_cast< const SwFEShell * >( pVSh );
2588 const SdrMarkList *pMarkList = pFESh->GetMarkList();
2589 if (pMarkList != nullptr && pMarkList->GetMarkCount() == 1)
2591 SdrObject *pObj = pMarkList->GetMark( 0 )->GetMarkedSdrObj();
2592 ::rtl::Reference < ::accessibility::AccessibleShape > pAccShapeImpl = GetContextImpl(pObj,nullptr,false);
2593 if (!pAccShapeImpl.is())
2595 while (pObj && pObj->getParentSdrObjectFromSdrObject())
2597 pObj = pObj->getParentSdrObjectFromSdrObject();
2599 if (pObj != nullptr)
2601 const SwFrame *pParent = SwAccessibleFrame::GetParent( SwAccessibleChild(pObj), GetShell()->IsPreview() );
2602 if( pParent )
2604 ::rtl::Reference< SwAccessibleContext > xParentAccImpl = GetContextImpl(pParent,false);
2605 if (!xParentAccImpl.is())
2607 const SwTabFrame* pTabFrame = pParent->FindTabFrame();
2608 if (pTabFrame)
2610 //The Table should not add in acc.because the "pParent" is not add to acc .
2611 uno::Reference< XAccessible> xAccParentTab = GetContext(pTabFrame);//Should Create.
2613 const SwFrame *pParentRoot = SwAccessibleFrame::GetParent( SwAccessibleChild(pTabFrame), GetShell()->IsPreview() );
2614 if (pParentRoot)
2616 ::rtl::Reference< SwAccessibleContext > xParentAccImplRoot = GetContextImpl(pParentRoot,false);
2617 if(xParentAccImplRoot.is())
2619 AccessibleEventObject aEvent;
2620 aEvent.EventId = AccessibleEventId::CHILD;
2621 aEvent.NewValue <<= xAccParentTab;
2622 aEvent.IndexHint = -1;
2623 xParentAccImplRoot->FireAccessibleEvent( aEvent );
2627 //Get "pParent" acc again.
2628 xParentAccImpl = GetContextImpl(pParent,false);
2630 else
2632 //directly create this acc para .
2633 xParentAccImpl = GetContextImpl(pParent);//Should Create.
2635 const SwFrame *pParentRoot = SwAccessibleFrame::GetParent( SwAccessibleChild(pParent), GetShell()->IsPreview() );
2637 ::rtl::Reference< SwAccessibleContext > xParentAccImplRoot = GetContextImpl(pParentRoot,false);
2638 if(xParentAccImplRoot.is())
2640 AccessibleEventObject aEvent;
2641 aEvent.EventId = AccessibleEventId::CHILD;
2642 aEvent.NewValue <<= uno::Reference< XAccessible>(xParentAccImpl);
2643 aEvent.IndexHint = -1;
2644 xParentAccImplRoot->FireAccessibleEvent( aEvent );
2648 if (xParentAccImpl.is())
2650 uno::Reference< XAccessible> xAccShape =
2651 GetContext(pObj,xParentAccImpl.get());
2653 AccessibleEventObject aEvent;
2654 aEvent.EventId = AccessibleEventId::CHILD;
2655 aEvent.NewValue <<= xAccShape;
2656 aEvent.IndexHint = -1;
2657 xParentAccImpl->FireAccessibleEvent( aEvent );
2666 m_setParaAdd.clear();
2667 m_setParaRemove.clear();
2668 if( xOldAcc.is() && xOldAcc != xAcc )
2669 InvalidateCursorPosition( xOldAcc );
2670 if( bOldShapeSelected || bShapeSelected )
2671 InvalidateShapeSelection();
2672 if( xAcc.is() )
2673 InvalidateCursorPosition( xAcc );
2675 InvalidateShapeInParaSelection();
2677 for (SwAccessibleParagraph* pAccPara : m_setParaRemove)
2679 if (pAccPara && !pAccPara->IsDisposed() &&
2680 pAccPara->getSelectedAccessibleChildCount() == 0 &&
2681 pAccPara->getSelectedText().getLength() == 0)
2683 if(pAccPara->SetSelectedState(false))
2685 AccessibleEventObject aEvent;
2686 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_REMOVE;
2687 pAccPara->FireAccessibleEvent( aEvent );
2691 for (SwAccessibleParagraph* pAccPara : m_setParaAdd)
2693 if(pAccPara && pAccPara->SetSelectedState(true))
2695 AccessibleEventObject aEvent;
2696 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED;
2697 pAccPara->FireAccessibleEvent( aEvent );
2702 void SwAccessibleMap::InvalidateFocus()
2704 DBG_TESTSOLARMUTEX();
2706 if(GetShell()->IsPreview())
2708 uno::Reference<XAccessible> xAcc = GetDocumentView_( true );
2709 if (xAcc)
2711 SwAccessiblePreview *pAccPreview = static_cast<SwAccessiblePreview *>(xAcc.get());
2712 if (pAccPreview)
2714 pAccPreview->InvalidateFocus();
2715 return ;
2720 uno::Reference < XAccessible > xAcc = mxCursorContext;
2721 if( xAcc.is() )
2723 SwAccessibleContext *pAccImpl = static_cast< SwAccessibleContext *>( xAcc.get() );
2724 pAccImpl->InvalidateFocus();
2726 else
2728 DoInvalidateShapeSelection(true);
2732 void SwAccessibleMap::SetCursorContext(
2733 const ::rtl::Reference < SwAccessibleContext >& rCursorContext )
2735 DBG_TESTSOLARMUTEX();
2736 uno::Reference < XAccessible > xAcc( rCursorContext );
2737 mxCursorContext = xAcc;
2740 void SwAccessibleMap::InvalidateEditableStates( const SwFrame* _pFrame )
2742 // Start with the frame or the first upper that is accessible
2743 SwAccessibleChild aFrameOrObj( _pFrame );
2744 while( aFrameOrObj.GetSwFrame() &&
2745 !aFrameOrObj.IsAccessible( GetShell()->IsPreview() ) )
2746 aFrameOrObj = aFrameOrObj.GetSwFrame()->GetUpper();
2747 if( !aFrameOrObj.GetSwFrame() )
2748 aFrameOrObj = GetShell()->GetLayout();
2750 uno::Reference< XAccessible > xAcc( GetContext( aFrameOrObj.GetSwFrame() ) );
2751 SwAccessibleContext *pAccImpl = static_cast< SwAccessibleContext *>( xAcc.get() );
2752 if( GetShell()->ActionPend() )
2754 SwAccessibleEvent_Impl aEvent( SwAccessibleEvent_Impl::CARET_OR_STATES,
2755 pAccImpl,
2756 SwAccessibleChild(pAccImpl->GetFrame()),
2757 AccessibleStates::EDITABLE );
2758 AppendEvent( aEvent );
2760 else
2762 FireEvents();
2763 pAccImpl->InvalidateStates( AccessibleStates::EDITABLE );
2767 void SwAccessibleMap::InvalidateRelationSet_( const SwFrame* pFrame,
2768 bool bFrom )
2770 DBG_TESTSOLARMUTEX();
2772 // first, see if this frame is accessible, and if so, get the respective
2773 SwAccessibleChild aFrameOrObj( pFrame );
2774 if( !aFrameOrObj.IsAccessible( GetShell()->IsPreview() ) )
2775 return;
2777 if (!mpFrameMap)
2778 return;
2780 uno::Reference < XAccessible > xAcc;
2781 SwAccessibleContextMap_Impl::iterator aIter =
2782 mpFrameMap->find( aFrameOrObj.GetSwFrame() );
2783 if( aIter != mpFrameMap->end() )
2785 xAcc = (*aIter).second;
2788 // deliver event directly, or queue event
2789 if( !xAcc.is() )
2790 return;
2792 SwAccessibleContext *pAccImpl =
2793 static_cast< SwAccessibleContext *>( xAcc.get() );
2794 if( GetShell()->ActionPend() )
2796 SwAccessibleEvent_Impl aEvent( SwAccessibleEvent_Impl::CARET_OR_STATES,
2797 pAccImpl, SwAccessibleChild(pFrame),
2798 ( bFrom
2799 ? AccessibleStates::RELATION_FROM
2800 : AccessibleStates::RELATION_TO ) );
2801 AppendEvent( aEvent );
2803 else
2805 FireEvents();
2806 pAccImpl->InvalidateRelation( bFrom
2807 ? AccessibleEventId::CONTENT_FLOWS_FROM_RELATION_CHANGED
2808 : AccessibleEventId::CONTENT_FLOWS_TO_RELATION_CHANGED );
2812 void SwAccessibleMap::InvalidateRelationSet( const SwFrame* pMaster,
2813 const SwFrame* pFollow )
2815 InvalidateRelationSet_( pMaster, false );
2816 InvalidateRelationSet_( pFollow, true );
2819 // invalidation of CONTENT_FLOW_FROM/_TO relation of a paragraph
2820 void SwAccessibleMap::InvalidateParaFlowRelation( const SwTextFrame& _rTextFrame,
2821 const bool _bFrom )
2823 InvalidateRelationSet_( &_rTextFrame, _bFrom );
2826 // invalidation of text selection of a paragraph
2827 void SwAccessibleMap::InvalidateParaTextSelection( const SwTextFrame& _rTextFrame )
2829 DBG_TESTSOLARMUTEX();
2831 // first, see if this frame is accessible, and if so, get the respective
2832 SwAccessibleChild aFrameOrObj( &_rTextFrame );
2833 if( !aFrameOrObj.IsAccessible( GetShell()->IsPreview() ) )
2834 return;
2836 if (!mpFrameMap)
2837 return;
2839 uno::Reference < XAccessible > xAcc;
2840 SwAccessibleContextMap_Impl::iterator aIter =
2841 mpFrameMap->find( aFrameOrObj.GetSwFrame() );
2842 if( aIter != mpFrameMap->end() )
2844 xAcc = (*aIter).second;
2847 // deliver event directly, or queue event
2848 if( !xAcc.is() )
2849 return;
2851 SwAccessibleContext *pAccImpl =
2852 static_cast< SwAccessibleContext *>( xAcc.get() );
2853 if( GetShell()->ActionPend() )
2855 SwAccessibleEvent_Impl aEvent(
2856 SwAccessibleEvent_Impl::CARET_OR_STATES,
2857 pAccImpl,
2858 SwAccessibleChild( &_rTextFrame ),
2859 AccessibleStates::TEXT_SELECTION_CHANGED );
2860 AppendEvent( aEvent );
2862 else
2864 FireEvents();
2865 pAccImpl->InvalidateTextSelection();
2869 sal_Int32 SwAccessibleMap::GetChildIndex( const SwFrame& rParentFrame,
2870 vcl::Window& rChild ) const
2872 DBG_TESTSOLARMUTEX();
2874 sal_Int32 nIndex( -1 );
2876 SwAccessibleChild aFrameOrObj( &rParentFrame );
2877 if( aFrameOrObj.IsAccessible( GetShell()->IsPreview() ) )
2879 uno::Reference < XAccessible > xAcc;
2881 if( mpFrameMap )
2883 SwAccessibleContextMap_Impl::iterator aIter =
2884 mpFrameMap->find( aFrameOrObj.GetSwFrame() );
2885 if( aIter != mpFrameMap->end() )
2887 xAcc = (*aIter).second;
2891 if( xAcc.is() )
2893 SwAccessibleContext *pAccImpl =
2894 static_cast< SwAccessibleContext *>( xAcc.get() );
2896 nIndex = pAccImpl->GetChildIndex( const_cast<SwAccessibleMap&>(*this),
2897 SwAccessibleChild( &rChild ) );
2901 return nIndex;
2904 void SwAccessibleMap::UpdatePreview( const std::vector<std::unique_ptr<PreviewPage>>& _rPreviewPages,
2905 const Fraction& _rScale,
2906 const SwPageFrame* _pSelectedPageFrame,
2907 const Size& _rPreviewWinSize )
2909 DBG_TESTSOLARMUTEX();
2910 assert(GetShell()->IsPreview() && "no preview?");
2911 assert(mpPreview != nullptr && "no preview data?");
2913 mpPreview->Update( *this, _rPreviewPages, _rScale, _pSelectedPageFrame, _rPreviewWinSize );
2915 // propagate change of VisArea through the document's
2916 // accessibility tree; this will also send appropriate scroll
2917 // events
2918 SwAccessibleContext* pDoc =
2919 GetContextImpl( GetShell()->GetLayout() ).get();
2920 static_cast<SwAccessibleDocumentBase*>( pDoc )->SetVisArea();
2922 uno::Reference < XAccessible > xOldAcc = mxCursorContext;
2923 uno::Reference < XAccessible > xAcc;
2925 const SwPageFrame *pSelPage = mpPreview->GetSelPage();
2926 if( pSelPage && mpFrameMap )
2928 SwAccessibleContextMap_Impl::iterator aIter =
2929 mpFrameMap->find( pSelPage );
2930 if( aIter != mpFrameMap->end() )
2931 xAcc = (*aIter).second;
2934 if( xOldAcc.is() && xOldAcc != xAcc )
2935 InvalidateCursorPosition( xOldAcc );
2936 if( xAcc.is() )
2937 InvalidateCursorPosition( xAcc );
2940 void SwAccessibleMap::InvalidatePreviewSelection( sal_uInt16 nSelPage )
2942 DBG_TESTSOLARMUTEX();
2943 assert(GetShell()->IsPreview());
2944 assert(mpPreview != nullptr);
2946 mpPreview->InvalidateSelection( GetShell()->GetLayout()->GetPageByPageNum( nSelPage ) );
2948 uno::Reference < XAccessible > xOldAcc = mxCursorContext;
2949 uno::Reference < XAccessible > xAcc;
2951 const SwPageFrame *pSelPage = mpPreview->GetSelPage();
2952 if( pSelPage && mpFrameMap )
2954 SwAccessibleContextMap_Impl::iterator aIter = mpFrameMap->find( pSelPage );
2955 if( aIter != mpFrameMap->end() )
2956 xAcc = (*aIter).second;
2959 if( xOldAcc.is() && xOldAcc != xAcc )
2960 InvalidateCursorPosition( xOldAcc );
2961 if( xAcc.is() )
2962 InvalidateCursorPosition( xAcc );
2965 bool SwAccessibleMap::IsPageSelected( const SwPageFrame *pPageFrame ) const
2967 return mpPreview && mpPreview->GetSelPage() == pPageFrame;
2970 void SwAccessibleMap::FireEvents()
2972 DBG_TESTSOLARMUTEX();
2974 osl::MutexGuard aGuard( maEventMutex );
2975 if( mpEvents )
2977 if (mpEvents->IsFiring())
2979 return; // prevent recursive FireEvents()
2982 mpEvents->SetFiring();
2983 mpEvents->MoveMissingXAccToEnd();
2984 for( auto const& aEvent : *mpEvents )
2985 FireEvent(aEvent);
2987 mpEventMap.reset();
2988 mpEvents.reset();
2991 mvShapes.clear();
2994 tools::Rectangle SwAccessibleMap::GetVisibleArea() const
2996 return o3tl::convert( GetVisArea().SVRect(), o3tl::Length::twip, o3tl::Length::mm100 );
2999 // Convert a MM100 value relative to the document root into a pixel value
3000 // relative to the screen!
3001 Point SwAccessibleMap::LogicToPixel( const Point& rPoint ) const
3003 Point aPoint = o3tl::toTwips( rPoint, o3tl::Length::mm100 );
3004 if (const vcl::Window* pWin = GetShell()->GetWin())
3006 MapMode aMapMode;
3007 GetMapMode( aPoint, aMapMode );
3008 aPoint = pWin->LogicToPixel( aPoint, aMapMode );
3009 aPoint = pWin->OutputToAbsoluteScreenPixel( aPoint );
3012 return aPoint;
3015 Size SwAccessibleMap::LogicToPixel( const Size& rSize ) const
3017 Size aSize( o3tl::toTwips( rSize, o3tl::Length::mm100 ) );
3018 if (const OutputDevice* pWin = GetShell()->GetWin()->GetOutDev())
3020 MapMode aMapMode;
3021 GetMapMode( Point(0,0), aMapMode );
3022 aSize = pWin->LogicToPixel( aSize, aMapMode );
3025 return aSize;
3028 bool SwAccessibleMap::ReplaceChild (
3029 ::accessibility::AccessibleShape* pCurrentChild,
3030 const uno::Reference< drawing::XShape >& _rxShape,
3031 const tools::Long /*_nIndex*/,
3032 const ::accessibility::AccessibleShapeTreeInfo& /*_rShapeTreeInfo*/
3035 DBG_TESTSOLARMUTEX();
3037 const SdrObject *pObj = nullptr;
3038 if( mpShapeMap )
3040 SwAccessibleShapeMap_Impl::const_iterator aIter = mpShapeMap->cbegin();
3041 SwAccessibleShapeMap_Impl::const_iterator aEndIter = mpShapeMap->cend();
3042 while( aIter != aEndIter && !pObj )
3044 uno::Reference < XAccessible > xAcc( (*aIter).second );
3045 ::accessibility::AccessibleShape *pAccShape =
3046 static_cast < ::accessibility::AccessibleShape* >( xAcc.get() );
3047 if( pAccShape == pCurrentChild )
3049 pObj = (*aIter).first;
3051 ++aIter;
3054 if( !pObj )
3055 return false;
3057 uno::Reference < drawing::XShape > xShape( _rxShape ); // keep reference to shape, because
3058 // we might be the only one that
3059 // holds it.
3060 // Also get keep parent.
3061 uno::Reference < XAccessible > xParent( pCurrentChild->getAccessibleParent() );
3062 pCurrentChild = nullptr; // will be released by dispose
3063 A11yDispose( nullptr, pObj, nullptr );
3065 if( !mpShapeMap )
3066 mpShapeMap.reset(new SwAccessibleShapeMap_Impl( this ));
3068 // create the new child
3069 ::accessibility::ShapeTypeHandler& rShapeTypeHandler =
3070 ::accessibility::ShapeTypeHandler::Instance();
3071 ::accessibility::AccessibleShapeInfo aShapeInfo(
3072 xShape, xParent, this );
3073 rtl::Reference< ::accessibility::AccessibleShape> pReplacement(
3074 rShapeTypeHandler.CreateAccessibleObject (
3075 aShapeInfo, mpShapeMap->GetInfo() ));
3077 uno::Reference < XAccessible > xAcc( pReplacement );
3078 if( xAcc.is() )
3080 pReplacement->Init();
3082 SwAccessibleShapeMap_Impl::iterator aIter = mpShapeMap->find( pObj );
3083 if( aIter != mpShapeMap->end() )
3085 (*aIter).second = xAcc;
3087 else
3089 mpShapeMap->emplace( pObj, xAcc );
3093 SwRect aEmptyRect;
3094 InvalidatePosOrSize( nullptr, pObj, nullptr, aEmptyRect );
3096 return true;
3099 //Get the accessible control shape from the model object, here model object is with XPropertySet type
3100 ::accessibility::AccessibleControlShape * SwAccessibleMap::GetAccControlShapeFromModel(css::beans::XPropertySet* pSet)
3102 if( mpShapeMap )
3104 SwAccessibleShapeMap_Impl::const_iterator aIter = mpShapeMap->cbegin();
3105 SwAccessibleShapeMap_Impl::const_iterator aEndIter = mpShapeMap->cend();
3106 while( aIter != aEndIter)
3108 uno::Reference < XAccessible > xAcc( (*aIter).second );
3109 ::accessibility::AccessibleShape *pAccShape =
3110 static_cast < ::accessibility::AccessibleShape* >( xAcc.get() );
3111 if(pAccShape && ::accessibility::ShapeTypeHandler::Instance().GetTypeId (pAccShape->GetXShape()) == ::accessibility::DRAWING_CONTROL)
3113 ::accessibility::AccessibleControlShape *pCtlAccShape = static_cast < ::accessibility::AccessibleControlShape* >(pAccShape);
3114 if (pCtlAccShape->GetControlModel() == pSet)
3115 return pCtlAccShape;
3117 ++aIter;
3120 return nullptr;
3123 css::uno::Reference< XAccessible >
3124 SwAccessibleMap::GetAccessibleCaption (const css::uno::Reference< css::drawing::XShape >&)
3126 return nullptr;
3129 Point SwAccessibleMap::PixelToCore( const Point& rPoint ) const
3131 Point aPoint;
3132 if (const OutputDevice* pWin = GetShell()->GetWin()->GetOutDev())
3134 MapMode aMapMode;
3135 GetMapMode( rPoint, aMapMode );
3136 aPoint = pWin->PixelToLogic( rPoint, aMapMode );
3138 return aPoint;
3141 static tools::Long lcl_CorrectCoarseValue(tools::Long aCoarseValue, tools::Long aFineValue,
3142 tools::Long aRefValue, bool bToLower)
3144 tools::Long aResult = aCoarseValue;
3146 if (bToLower)
3148 if (aFineValue < aRefValue)
3149 aResult -= 1;
3151 else
3153 if (aFineValue > aRefValue)
3154 aResult += 1;
3157 return aResult;
3160 static void lcl_CorrectRectangle(tools::Rectangle & rRect,
3161 const tools::Rectangle & rSource,
3162 const tools::Rectangle & rInGrid)
3164 rRect.SetLeft( lcl_CorrectCoarseValue(rRect.Left(), rSource.Left(),
3165 rInGrid.Left(), false) );
3166 rRect.SetTop( lcl_CorrectCoarseValue(rRect.Top(), rSource.Top(),
3167 rInGrid.Top(), false) );
3168 rRect.SetRight( lcl_CorrectCoarseValue(rRect.Right(), rSource.Right(),
3169 rInGrid.Right(), true) );
3170 rRect.SetBottom( lcl_CorrectCoarseValue(rRect.Bottom(), rSource.Bottom(),
3171 rInGrid.Bottom(), true) );
3174 tools::Rectangle SwAccessibleMap::CoreToPixel( const SwRect& rRect ) const
3176 tools::Rectangle aRect;
3177 if (const OutputDevice* pWin = GetShell()->GetWin()->GetOutDev())
3179 MapMode aMapMode;
3180 GetMapMode( rRect.TopLeft(), aMapMode );
3181 aRect = pWin->LogicToPixel( rRect.SVRect(), aMapMode );
3183 tools::Rectangle aTmpRect = pWin->PixelToLogic( aRect, aMapMode );
3184 lcl_CorrectRectangle(aRect, rRect.SVRect(), aTmpRect);
3187 return aRect;
3190 /** get mapping mode for LogicToPixel and PixelToLogic conversions
3192 Method returns mapping mode of current output device and adjusts it,
3193 if the shell is in page/print preview.
3194 Necessary, because <PreviewAdjust(..)> changes mapping mode at current
3195 output device for mapping logic document positions to page preview window
3196 positions and vice versa and doesn't take care to recover its changes.
3198 void SwAccessibleMap::GetMapMode( const Point& _rPoint,
3199 MapMode& _orMapMode ) const
3201 MapMode aMapMode = GetShell()->GetWin()->GetMapMode();
3202 if( GetShell()->IsPreview() )
3204 assert(mpPreview != nullptr);
3205 mpPreview->AdjustMapMode( aMapMode, _rPoint );
3207 _orMapMode = aMapMode;
3210 Size SwAccessibleMap::GetPreviewPageSize(sal_uInt16 const nPreviewPageNum) const
3212 assert(mpVSh->IsPreview());
3213 assert(mpPreview != nullptr);
3214 return mpVSh->PagePreviewLayout()->GetPreviewPageSizeByPageNum(nPreviewPageNum);
3217 /** method to build up a new data structure of the accessible paragraphs,
3218 which have a selection
3219 Important note: method has to be used inside a mutual exclusive section
3221 std::unique_ptr<SwAccessibleSelectedParas_Impl> SwAccessibleMap::BuildSelectedParas()
3223 // no accessible contexts, no selection
3224 if ( !mpFrameMap )
3226 return nullptr;
3229 // get cursor as an instance of its base class <SwPaM>
3230 SwPaM* pCursor( nullptr );
3232 SwCursorShell* pCursorShell = dynamic_cast<SwCursorShell*>(GetShell());
3233 if ( pCursorShell )
3235 SwFEShell* pFEShell = dynamic_cast<SwFEShell*>(pCursorShell);
3236 if ( !pFEShell ||
3237 ( !pFEShell->IsFrameSelected() &&
3238 pFEShell->IsObjSelected() == 0 ) )
3240 // get cursor without updating an existing table cursor.
3241 pCursor = pCursorShell->GetCursor( false );
3245 // no cursor, no selection
3246 if ( !pCursor )
3248 return nullptr;
3251 std::unique_ptr<SwAccessibleSelectedParas_Impl> pRetSelectedParas;
3253 // loop on all cursors
3254 SwPaM* pRingStart = pCursor;
3255 do {
3257 // for a selection the cursor has to have a mark.
3258 // for safety reasons assure that point and mark are in text nodes
3259 if ( pCursor->HasMark() &&
3260 pCursor->GetPoint()->GetNode().IsTextNode() &&
3261 pCursor->GetMark()->GetNode().IsTextNode() )
3263 auto [pStartPos, pEndPos] = pCursor->StartEnd(); // SwPosition*
3264 // loop on all text nodes inside the selection
3265 SwNodeIndex aIdx( pStartPos->GetNode() );
3266 for ( ; aIdx.GetIndex() <= pEndPos->GetNodeIndex(); ++aIdx )
3268 SwTextNode* pTextNode( aIdx.GetNode().GetTextNode() );
3269 if ( pTextNode )
3271 // loop on all text frames registered at the text node.
3272 SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*pTextNode);
3273 for( SwTextFrame* pTextFrame = aIter.First(); pTextFrame; pTextFrame = aIter.Next() )
3275 uno::WeakReference < XAccessible > xWeakAcc;
3276 SwAccessibleContextMap_Impl::iterator aMapIter =
3277 mpFrameMap->find( pTextFrame );
3278 if( aMapIter != mpFrameMap->end() )
3280 xWeakAcc = (*aMapIter).second;
3281 SwAccessibleParaSelection aDataEntry(
3282 sw::FrameContainsNode(*pTextFrame, pStartPos->GetNodeIndex())
3283 ? pTextFrame->MapModelToViewPos(*pStartPos)
3284 : TextFrameIndex(0),
3286 sw::FrameContainsNode(*pTextFrame, pEndPos->GetNodeIndex())
3287 ? pTextFrame->MapModelToViewPos(*pEndPos)
3288 : TextFrameIndex(COMPLETE_STRING));
3289 if ( !pRetSelectedParas )
3291 pRetSelectedParas.reset(
3292 new SwAccessibleSelectedParas_Impl);
3294 // sw_redlinehide: should be idempotent for multiple nodes in a merged para
3295 pRetSelectedParas->emplace( xWeakAcc, aDataEntry );
3302 // prepare next turn: get next cursor in ring
3303 pCursor = pCursor->GetNext();
3304 } while ( pCursor != pRingStart );
3306 return pRetSelectedParas;
3309 void SwAccessibleMap::InvalidateTextSelectionOfAllParas()
3311 DBG_TESTSOLARMUTEX();
3313 // keep previously known selected paragraphs
3314 std::unique_ptr<SwAccessibleSelectedParas_Impl> pPrevSelectedParas( std::move(mpSelectedParas) );
3316 // determine currently selected paragraphs
3317 mpSelectedParas = BuildSelectedParas();
3319 // compare currently selected paragraphs with the previously selected
3320 // paragraphs and submit corresponding TEXT_SELECTION_CHANGED events.
3321 // first, search for new and changed selections.
3322 // on the run remove selections from previously known ones, if they are
3323 // also in the current ones.
3324 if ( mpSelectedParas )
3326 SwAccessibleSelectedParas_Impl::iterator aIter = mpSelectedParas->begin();
3327 for ( ; aIter != mpSelectedParas->end(); ++aIter )
3329 bool bSubmitEvent( false );
3330 if ( !pPrevSelectedParas )
3332 // new selection
3333 bSubmitEvent = true;
3335 else
3337 SwAccessibleSelectedParas_Impl::iterator aPrevSelected =
3338 pPrevSelectedParas->find( (*aIter).first );
3339 if ( aPrevSelected != pPrevSelectedParas->end() )
3341 // check, if selection has changed
3342 if ( (*aIter).second.nStartOfSelection !=
3343 (*aPrevSelected).second.nStartOfSelection ||
3344 (*aIter).second.nEndOfSelection !=
3345 (*aPrevSelected).second.nEndOfSelection )
3347 // changed selection
3348 bSubmitEvent = true;
3350 pPrevSelectedParas->erase( aPrevSelected );
3352 else
3354 // new selection
3355 bSubmitEvent = true;
3359 if ( bSubmitEvent )
3361 uno::Reference < XAccessible > xAcc( (*aIter).first );
3362 if ( xAcc.is() )
3364 ::rtl::Reference < SwAccessibleContext > xAccImpl(
3365 static_cast<SwAccessibleContext*>( xAcc.get() ) );
3366 if ( xAccImpl.is() && xAccImpl->GetFrame() )
3368 const SwTextFrame* pTextFrame = xAccImpl->GetFrame()->DynCastTextFrame();
3369 OSL_ENSURE( pTextFrame,
3370 "<SwAccessibleMap::_SubmitTextSelectionChangedEvents()> - unexpected type of frame" );
3371 if ( pTextFrame )
3373 InvalidateParaTextSelection( *pTextFrame );
3381 // second, handle previous selections - after the first step the data
3382 // structure of the previously known only contains the 'old' selections
3383 if ( !pPrevSelectedParas )
3384 return;
3386 SwAccessibleSelectedParas_Impl::iterator aIter = pPrevSelectedParas->begin();
3387 for ( ; aIter != pPrevSelectedParas->end(); ++aIter )
3389 uno::Reference < XAccessible > xAcc( (*aIter).first );
3390 if ( xAcc.is() )
3392 ::rtl::Reference < SwAccessibleContext > xAccImpl(
3393 static_cast<SwAccessibleContext*>( xAcc.get() ) );
3394 if ( xAccImpl.is() && xAccImpl->GetFrame() )
3396 const SwTextFrame* pTextFrame = xAccImpl->GetFrame()->DynCastTextFrame();
3397 OSL_ENSURE( pTextFrame,
3398 "<SwAccessibleMap::_SubmitTextSelectionChangedEvents()> - unexpected type of frame" );
3399 if ( pTextFrame )
3401 InvalidateParaTextSelection( *pTextFrame );
3408 const SwRect& SwAccessibleMap::GetVisArea() const
3410 assert(!GetShell()->IsPreview() || (mpPreview != nullptr));
3412 return GetShell()->IsPreview()
3413 ? mpPreview->GetVisArea()
3414 : GetShell()->VisArea();
3417 bool SwAccessibleMap::IsDocumentSelAll()
3419 return GetShell()->GetDoc()->IsPrepareSelAll();
3422 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */