1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20 #include <vcl/window.hxx>
21 #include <swtypes.hxx>
22
23 #include <com/sun/star/accessibility/XAccessible.hpp>
24 #include <com/sun/star/accessibility/XAccessibleStateSet.hpp>
25 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
26 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
27 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
28 #include <osl/mutex.hxx>
29 #include <sal/log.hxx>
30 #include <vcl/svapp.hxx>
31 #include <vcl/settings.hxx>
32 #include <i18nlangtag/languagetag.hxx>
33 #include <unotools/accessiblestatesethelper.hxx>
34 #include <unotools/accessiblerelationsethelper.hxx>
35 #include <viewsh.hxx>
36 #include <crsrsh.hxx>
37 #include <fesh.hxx>
38 #include <wrtsh.hxx>
39 #include <txtfrm.hxx>
40 #include <ndtxt.hxx>
41 #include <pagefrm.hxx>
42 #include <flyfrm.hxx>
43 #include <dflyobj.hxx>
44 #include <pam.hxx>
45 #include <accmap.hxx>
46 #include "accfrmobjslist.hxx"
47 #include "acccontext.hxx"
48 #include <svx/AccessibleShape.hxx>
49 #include <comphelper/accessibleeventnotifier.hxx>
50 #include <cppuhelper/supportsservice.hxx>
51 #include <PostItMgr.hxx>
52
53 using namespace sw::access;
54 using namespace ::com::sun::star;
55 using namespace ::com::sun::star::accessibility;
56
InitStates()57 void SwAccessibleContext::InitStates()
58 {
59 m_isShowingState = GetMap() && IsShowing( *(GetMap()) );
60
61 SwViewShell *pVSh = GetMap()->GetShell();
62 m_isEditableState = pVSh && IsEditable( pVSh );
63 m_isOpaqueState = pVSh && IsOpaque( pVSh );
64 m_isDefuncState = false;
65 }
66
SetParent(SwAccessibleContext * pParent)67 void SwAccessibleContext::SetParent( SwAccessibleContext *pParent )
68 {
69 osl::MutexGuard aGuard( m_Mutex );
70
71 uno::Reference < XAccessible > xParent( pParent );
72 m_xWeakParent = xParent;
73 }
74
GetWeakParent() const75 uno::Reference< XAccessible > SwAccessibleContext::GetWeakParent() const
76 {
77 osl::MutexGuard aGuard( m_Mutex );
78
79 uno::Reference< XAccessible > xParent( m_xWeakParent );
80 return xParent;
81 }
82
GetWindow()83 vcl::Window *SwAccessibleContext::GetWindow()
84 {
85 vcl::Window *pWin = nullptr;
86
87 if( GetMap() )
88 {
89 const SwViewShell *pVSh = GetMap()->GetShell();
90 OSL_ENSURE( pVSh, "no view shell" );
91 if( pVSh )
92 pWin = pVSh->GetWin();
93
94 OSL_ENSURE( pWin, "no window" );
95 }
96
97 return pWin;
98 }
99
100 // get SwViewShell from accessibility map, and cast to cursor shell
GetCursorShell()101 SwCursorShell* SwAccessibleContext::GetCursorShell()
102 {
103 SwViewShell* pViewShell = GetMap() ? GetMap()->GetShell() : nullptr;
104 OSL_ENSURE( pViewShell, "no view shell" );
105 return dynamic_cast<SwCursorShell*>( pViewShell);
106 }
107
GetCursorShell() const108 const SwCursorShell* SwAccessibleContext::GetCursorShell() const
109 {
110 // just like non-const GetCursorShell
111 const SwViewShell* pViewShell = GetMap() ? GetMap()->GetShell() : nullptr;
112 OSL_ENSURE( pViewShell, "no view shell" );
113 return dynamic_cast<const SwCursorShell*>( pViewShell);
114 }
115
116 namespace {
117
118 enum class Action { NONE, SCROLLED, SCROLLED_WITHIN,
119 SCROLLED_IN, SCROLLED_OUT };
120
121 }
122
ChildrenScrolled(const SwFrame * pFrame,const SwRect & rOldVisArea)123 void SwAccessibleContext::ChildrenScrolled( const SwFrame *pFrame,
124 const SwRect& rOldVisArea )
125 {
126 const SwRect& rNewVisArea = GetVisArea();
127 const bool bVisibleChildrenOnly = SwAccessibleChild( pFrame ).IsVisibleChildrenOnly();
128
129 const SwAccessibleChildSList aList( *pFrame, *(GetMap()) );
130 SwAccessibleChildSList::const_iterator aIter( aList.begin() );
131 while( aIter != aList.end() )
132 {
133 const SwAccessibleChild& rLower = *aIter;
134 const SwRect aBox( rLower.GetBox( *(GetMap()) ) );
135 if( rLower.IsAccessible( GetShell()->IsPreview() ) )
136 {
137 Action eAction = Action::NONE;
138 if( aBox.IsOver( rNewVisArea ) )
139 {
140 if( aBox.IsOver( rOldVisArea ) )
141 {
142 eAction = Action::SCROLLED_WITHIN;
143 }
144 else
145 {
146 if ( bVisibleChildrenOnly &&
147 !rLower.AlwaysIncludeAsChild() )
148 {
149 eAction = Action::SCROLLED_IN;
150 }
151 else
152 {
153 eAction = Action::SCROLLED;
154 }
155 }
156 }
157 else if( aBox.IsOver( rOldVisArea ) )
158 {
159 if ( bVisibleChildrenOnly &&
160 !rLower.AlwaysIncludeAsChild() )
161 {
162 eAction = Action::SCROLLED_OUT;
163 }
164 else
165 {
166 eAction = Action::SCROLLED;
167 }
168 }
169 else if( !bVisibleChildrenOnly ||
170 rLower.AlwaysIncludeAsChild() )
171 {
172 // This wouldn't be required if the SwAccessibleFrame,
173 // wouldn't know about the visible area.
174 eAction = Action::SCROLLED;
175 }
176 if( Action::NONE != eAction )
177 {
178 if ( rLower.GetSwFrame() )
179 {
180 OSL_ENSURE( !rLower.AlwaysIncludeAsChild(),
181 "<SwAccessibleContext::ChildrenScrolled(..)> - always included child not considered!" );
182 const SwFrame* pLower( rLower.GetSwFrame() );
183 ::rtl::Reference< SwAccessibleContext > xAccImpl =
184 GetMap()->GetContextImpl( pLower );
185 if( xAccImpl.is() )
186 {
187 switch( eAction )
188 {
189 case Action::SCROLLED:
190 xAccImpl->Scrolled( rOldVisArea );
191 break;
192 case Action::SCROLLED_WITHIN:
193 xAccImpl->ScrolledWithin( rOldVisArea );
194 break;
195 case Action::SCROLLED_IN:
196 xAccImpl->ScrolledIn();
197 break;
198 case Action::SCROLLED_OUT:
199 xAccImpl->ScrolledOut( rOldVisArea );
200 break;
201 case Action::NONE:
202 break;
203 }
204 }
205 else
206 {
207 ChildrenScrolled( pLower, rOldVisArea );
208 }
209 }
210 else if ( rLower.GetDrawObject() )
211 {
212 OSL_ENSURE( !rLower.AlwaysIncludeAsChild(),
213 "<SwAccessibleContext::ChildrenScrolled(..)> - always included child not considered!" );
214 ::rtl::Reference< ::accessibility::AccessibleShape > xAccImpl =
215 GetMap()->GetContextImpl( rLower.GetDrawObject(),
216 this );
217 if( xAccImpl.is() )
218 {
219 switch( eAction )
220 {
221 case Action::SCROLLED:
222 case Action::SCROLLED_WITHIN:
223 xAccImpl->ViewForwarderChanged();
224 break;
225 case Action::SCROLLED_IN:
226 ScrolledInShape( xAccImpl.get() );
227 break;
228 case Action::SCROLLED_OUT:
229 {
230 xAccImpl->ViewForwarderChanged();
231 // this DisposeShape call was removed by
232 // IAccessibility2 implementation
233 // without giving any reason why
234 DisposeShape( rLower.GetDrawObject(),
235 xAccImpl.get() );
236 }
237 break;
238 // coverity[dead_error_begin] - following conditions exist to avoid compiler warning
239 case Action::NONE:
240 break;
241 }
242 }
243 }
244 else if ( rLower.GetWindow() )
245 {
246 // nothing to do - as such children are always included as children.
247 OSL_ENSURE( rLower.AlwaysIncludeAsChild(),
248 "<SwAccessibleContext::ChildrenScrolled(..)> - not always included child not considered!" );
249 }
250 }
251 }
252 else if ( rLower.GetSwFrame() &&
253 ( !bVisibleChildrenOnly ||
254 aBox.IsOver( rOldVisArea ) ||
255 aBox.IsOver( rNewVisArea ) ) )
256 {
257 // There are no unaccessible SdrObjects that need to be notified
258 ChildrenScrolled( rLower.GetSwFrame(), rOldVisArea );
259 }
260 ++aIter;
261 }
262 }
263
Scrolled(const SwRect & rOldVisArea)264 void SwAccessibleContext::Scrolled( const SwRect& rOldVisArea )
265 {
266 SetVisArea( GetMap()->GetVisArea() );
267
268 ChildrenScrolled( GetFrame(), rOldVisArea );
269
270 bool bIsOldShowingState;
271 bool bIsNewShowingState = IsShowing( *(GetMap()) );
272 {
273 osl::MutexGuard aGuard( m_Mutex );
274 bIsOldShowingState = m_isShowingState;
275 m_isShowingState = bIsNewShowingState;
276 }
277
278 if( bIsOldShowingState != bIsNewShowingState )
279 FireStateChangedEvent( AccessibleStateType::SHOWING,
280 bIsNewShowingState );
281 }
282
ScrolledWithin(const SwRect & rOldVisArea)283 void SwAccessibleContext::ScrolledWithin( const SwRect& rOldVisArea )
284 {
285 SetVisArea( GetMap()->GetVisArea() );
286
287 ChildrenScrolled( GetFrame(), rOldVisArea );
288
289 FireVisibleDataEvent();
290 }
291
ScrolledIn()292 void SwAccessibleContext::ScrolledIn()
293 {
294 // This accessible should be freshly created, because it
295 // was not visible before. Therefore, its visible area must already
296 // reflect the scrolling.
297 OSL_ENSURE( GetVisArea() == GetMap()->GetVisArea(),
298 "Visible area of child is wrong. Did it exist already?" );
299
300 // Send child event at parent. That's all we have to do here.
301 const SwFrame* pParent = GetParent();
302 ::rtl::Reference< SwAccessibleContext > xParentImpl(
303 GetMap()->GetContextImpl( pParent, false ) );
304 uno::Reference < XAccessibleContext > xThis( this );
305 if( !xParentImpl.is() )
306 return;
307
308 SetParent( xParentImpl.get() );
309
310 AccessibleEventObject aEvent;
311 aEvent.EventId = AccessibleEventId::CHILD;
312 aEvent.NewValue <<= xThis;
313
314 xParentImpl->FireAccessibleEvent( aEvent );
315
316 if( HasCursor() )
317 {
318 vcl::Window *pWin = GetWindow();
319 if( pWin && pWin->HasFocus() )
320 {
321 FireStateChangedEvent( AccessibleStateType::FOCUSED, true );
322 }
323 }
324 }
325
ScrolledOut(const SwRect & rOldVisArea)326 void SwAccessibleContext::ScrolledOut( const SwRect& rOldVisArea )
327 {
328 SetVisArea( GetMap()->GetVisArea() );
329
330 // First of all, update the children. That's required to dispose
331 // all children that are existing only if they are visible. They
332 // are not disposed by the recursive Dispose call that follows later on,
333 // because this call will only dispose children that are in the
334 // new visible area. The children we want to dispose however are in the
335 // old visible area all.
336 ChildrenScrolled( GetFrame(), rOldVisArea );
337
338 // Broadcast a state changed event for the showing state.
339 // It might be that the child is freshly created just to send
340 // the child event. In this case no listener will exist.
341 FireStateChangedEvent( AccessibleStateType::SHOWING, false );
342
343 // this Dispose call was removed by IAccessibility2 implementation
344 // without giving any reason why - without it we get stale
345 // entries in SwAccessibleMap::mpFrameMap.
346 Dispose(true);
347 }
348
349 // #i27301# - use new type definition for <_nStates>
InvalidateChildrenStates(const SwFrame * _pFrame,AccessibleStates _nStates)350 void SwAccessibleContext::InvalidateChildrenStates( const SwFrame* _pFrame,
351 AccessibleStates _nStates )
352 {
353 const SwAccessibleChildSList aVisList( GetVisArea(), *_pFrame, *(GetMap()) );
354
355 SwAccessibleChildSList::const_iterator aIter( aVisList.begin() );
356 while( aIter != aVisList.end() )
357 {
358 const SwAccessibleChild& rLower = *aIter;
359 const SwFrame* pLower = rLower.GetSwFrame();
360 if( pLower )
361 {
362 ::rtl::Reference< SwAccessibleContext > xAccImpl;
363 if( rLower.IsAccessible( GetShell()->IsPreview() ) )
364 xAccImpl = GetMap()->GetContextImpl( pLower, false );
365 if( xAccImpl.is() )
366 xAccImpl->InvalidateStates( _nStates );
367 else
368 InvalidateChildrenStates( pLower, _nStates );
369 }
370 else if ( rLower.GetDrawObject() )
371 {
372 // TODO: SdrObjects
373 }
374 else if ( rLower.GetWindow() )
375 {
376 // nothing to do ?
377 }
378
379 ++aIter;
380 }
381 }
382
DisposeChildren(const SwFrame * pFrame,bool bRecursive,bool bCanSkipInvisible)383 void SwAccessibleContext::DisposeChildren(const SwFrame *pFrame,
384 bool bRecursive,
385 bool bCanSkipInvisible)
386 {
387 const SwAccessibleChildSList aVisList( GetVisArea(), *pFrame, *(GetMap()) );
388 SwAccessibleChildSList::const_iterator aIter( aVisList.begin() );
389 while( aIter != aVisList.end() )
390 {
391 const SwAccessibleChild& rLower = *aIter;
392 const SwFrame* pLower = rLower.GetSwFrame();
393 if( pLower )
394 {
395 // tdf#117601 dispose the darn thing if it ever was accessible
396 ::rtl::Reference<SwAccessibleContext> xAccImpl = GetMap()->GetContextImpl(pLower, false);
397 if( xAccImpl.is() )
398 xAccImpl->Dispose( bRecursive );
399 else
400 {
401 // it's possible that the xAccImpl *does* exist with a
402 // ref-count of 0 and blocked in its dtor in another thread -
403 // this call here could be from SwAccessibleMap dtor so
404 // remove it from any maps now!
405 GetMap()->RemoveContext(pLower);
406 // in this case the context will check with a weak_ptr
407 // that the map is still alive so it's not necessary
408 // to clear its m_pMap here.
409 if (bRecursive)
410 {
411 DisposeChildren(pLower, bRecursive, bCanSkipInvisible);
412 }
413 }
414 }
415 else if ( rLower.GetDrawObject() )
416 {
417 ::rtl::Reference< ::accessibility::AccessibleShape > xAccImpl(
418 GetMap()->GetContextImpl( rLower.GetDrawObject(),
419 this, false ) );
420 if( xAccImpl.is() )
421 DisposeShape( rLower.GetDrawObject(), xAccImpl.get() );
422 }
423 else if ( rLower.GetWindow() )
424 {
425 DisposeChild(rLower, false, bCanSkipInvisible);
426 }
427 ++aIter;
428 }
429 }
430
InvalidateContent_(bool)431 void SwAccessibleContext::InvalidateContent_( bool )
432 {
433 }
434
InvalidateCursorPos_()435 void SwAccessibleContext::InvalidateCursorPos_()
436 {
437 }
438
InvalidateFocus_()439 void SwAccessibleContext::InvalidateFocus_()
440 {
441 }
442
FireAccessibleEvent(AccessibleEventObject & rEvent)443 void SwAccessibleContext::FireAccessibleEvent( AccessibleEventObject& rEvent )
444 {
445 OSL_ENSURE( GetFrame(), "fire event for disposed frame?" );
446 if( !GetFrame() )
447 return;
448
449 if( !rEvent.Source.is() )
450 {
451 uno::Reference < XAccessibleContext > xThis( this );
452 rEvent.Source = xThis;
453 }
454
455 if (m_nClientId)
456 comphelper::AccessibleEventNotifier::addEvent( m_nClientId, rEvent );
457 }
458
FireVisibleDataEvent()459 void SwAccessibleContext::FireVisibleDataEvent()
460 {
461 AccessibleEventObject aEvent;
462 aEvent.EventId = AccessibleEventId::VISIBLE_DATA_CHANGED;
463
464 FireAccessibleEvent( aEvent );
465 }
466
FireStateChangedEvent(sal_Int16 nState,bool bNewState)467 void SwAccessibleContext::FireStateChangedEvent( sal_Int16 nState,
468 bool bNewState )
469 {
470 AccessibleEventObject aEvent;
471
472 aEvent.EventId = AccessibleEventId::STATE_CHANGED;
473 if( bNewState )
474 aEvent.NewValue <<= nState;
475 else
476 aEvent.OldValue <<= nState;
477
478 FireAccessibleEvent( aEvent );
479 }
480
GetStates(::utl::AccessibleStateSetHelper & rStateSet)481 void SwAccessibleContext::GetStates(
482 ::utl::AccessibleStateSetHelper& rStateSet )
483 {
484 SolarMutexGuard aGuard;
485
486 // SHOWING
487 if (m_isShowingState)
488 rStateSet.AddState( AccessibleStateType::SHOWING );
489
490 // EDITABLE
491 if (m_isEditableState)
492 //Set editable state to graphic and other object when the document is editable
493 {
494 rStateSet.AddState( AccessibleStateType::EDITABLE );
495 rStateSet.AddState( AccessibleStateType::RESIZABLE );
496 rStateSet.AddState( AccessibleStateType::MOVEABLE );
497 }
498 // ENABLED
499 rStateSet.AddState( AccessibleStateType::ENABLED );
500
501 // OPAQUE
502 if (m_isOpaqueState)
503 rStateSet.AddState( AccessibleStateType::OPAQUE );
504
505 // VISIBLE
506 rStateSet.AddState( AccessibleStateType::VISIBLE );
507
508 if (m_isDefuncState)
509 rStateSet.AddState( AccessibleStateType::DEFUNC );
510 }
511
IsEditableState()512 bool SwAccessibleContext::IsEditableState()
513 {
514 bool bRet;
515 {
516 osl::MutexGuard aGuard( m_Mutex );
517 bRet = m_isEditableState;
518 }
519
520 return bRet;
521 }
522
ThrowIfDisposed()523 void SwAccessibleContext::ThrowIfDisposed()
524 {
525 if (!(GetFrame() && GetMap()))
526 {
527 throw lang::DisposedException("object is nonfunctional",
528 static_cast<cppu::OWeakObject*>(this));
529 }
530 }
531
SwAccessibleContext(std::shared_ptr<SwAccessibleMap> const & pMap,sal_Int16 const nRole,const SwFrame * pF)532 SwAccessibleContext::SwAccessibleContext(std::shared_ptr<SwAccessibleMap> const& pMap,
533 sal_Int16 const nRole,
534 const SwFrame *pF )
535 : SwAccessibleFrame( pMap->GetVisArea(), pF,
536 pMap->GetShell()->IsPreview() )
537 , m_pMap(pMap.get())
538 , m_wMap(pMap)
539 , m_nClientId(0)
540 , m_nRole(nRole)
541 , m_isDisposing( false )
542 , m_isRegisteredAtAccessibleMap( true )
543 , m_isSelectedInDoc(false)
544 {
545 InitStates();
546 }
547
~SwAccessibleContext()548 SwAccessibleContext::~SwAccessibleContext()
549 {
550 // must have for 2 reasons: 2. as long as this thread has SolarMutex
551 // another thread cannot destroy the SwAccessibleMap so our temporary
552 // taking a hard ref to SwAccessibleMap won't delay its destruction
553 SolarMutexGuard aGuard;
554 // must check with weak_ptr that m_pMap is still alive
555 std::shared_ptr<SwAccessibleMap> pMap(m_wMap.lock());
556 if (m_isRegisteredAtAccessibleMap && GetFrame() && pMap)
557 {
558 pMap->RemoveContext( GetFrame() );
559 }
560 }
561
562 uno::Reference< XAccessibleContext > SAL_CALL
getAccessibleContext()563 SwAccessibleContext::getAccessibleContext()
564 {
565 uno::Reference < XAccessibleContext > xRet( this );
566 return xRet;
567 }
568
getAccessibleChildCount()569 sal_Int32 SAL_CALL SwAccessibleContext::getAccessibleChildCount()
570 {
571 SolarMutexGuard aGuard;
572
573 ThrowIfDisposed();
574
575 return m_isDisposing ? 0 : GetChildCount( *(GetMap()) );
576 }
577
578 uno::Reference< XAccessible> SAL_CALL
getAccessibleChild(sal_Int32 nIndex)579 SwAccessibleContext::getAccessibleChild( sal_Int32 nIndex )
580 {
581 SolarMutexGuard aGuard;
582
583 ThrowIfDisposed();
584
585 const SwAccessibleChild aChild( GetChild( *(GetMap()), nIndex ) );
586 if( !aChild.IsValid() )
587 {
588 uno::Reference < XAccessibleContext > xThis( this );
589 lang::IndexOutOfBoundsException aExcept(
590 "index out of bounds",
591 xThis );
592 throw aExcept;
593 }
594
595 uno::Reference< XAccessible > xChild;
596 if( aChild.GetSwFrame() )
597 {
598 ::rtl::Reference < SwAccessibleContext > xChildImpl(
599 GetMap()->GetContextImpl( aChild.GetSwFrame(), !m_isDisposing ) );
600 if( xChildImpl.is() )
601 {
602 xChildImpl->SetParent( this );
603 xChild = xChildImpl.get();
604 }
605 }
606 else if ( aChild.GetDrawObject() )
607 {
608 ::rtl::Reference < ::accessibility::AccessibleShape > xChildImpl(
609 GetMap()->GetContextImpl( aChild.GetDrawObject(),
610 this, !m_isDisposing) );
611 if( xChildImpl.is() )
612 xChild = xChildImpl.get();
613 }
614 else if ( aChild.GetWindow() )
615 {
616 xChild = aChild.GetWindow()->GetAccessible();
617 }
618
619 return xChild;
620 }
621
622 css::uno::Sequence<uno::Reference<XAccessible>> SAL_CALL
getAccessibleChildren()623 SwAccessibleContext::getAccessibleChildren()
624 {
625 SolarMutexGuard aGuard;
626
627 ThrowIfDisposed();
628
629 std::list< sw::access::SwAccessibleChild > aChildren;
630 GetChildren( *GetMap(), aChildren );
631
632 std::vector<uno::Reference<XAccessible>> aRet;
633 aRet.reserve(aChildren.size());
634 for (const auto & rSwChild : aChildren)
635 {
636 uno::Reference< XAccessible > xChild;
637 if( rSwChild.GetSwFrame() )
638 {
639 ::rtl::Reference < SwAccessibleContext > xChildImpl(
640 GetMap()->GetContextImpl( rSwChild.GetSwFrame(), !m_isDisposing ) );
641 if( xChildImpl.is() )
642 {
643 xChildImpl->SetParent( this );
644 xChild = xChildImpl.get();
645 }
646 }
647 else if ( rSwChild.GetDrawObject() )
648 {
649 ::rtl::Reference < ::accessibility::AccessibleShape > xChildImpl(
650 GetMap()->GetContextImpl( rSwChild.GetDrawObject(),
651 this, !m_isDisposing) );
652 if( xChildImpl.is() )
653 xChild = xChildImpl.get();
654 }
655 else if ( rSwChild.GetWindow() )
656 {
657 xChild = rSwChild.GetWindow()->GetAccessible();
658 }
659 aRet.push_back(xChild);
660 }
661 return comphelper::containerToSequence(aRet);
662 }
663
getAccessibleParentImpl()664 uno::Reference< XAccessible> SwAccessibleContext::getAccessibleParentImpl()
665 {
666 SolarMutexGuard aGuard;
667
668 const SwFrame *pUpper = GetParent();
669 OSL_ENSURE( pUpper != nullptr || m_isDisposing, "no upper found" );
670
671 uno::Reference< XAccessible > xAcc;
672 if( pUpper )
673 xAcc = GetMap()->GetContext( pUpper, !m_isDisposing );
674
675 OSL_ENSURE( xAcc.is() || m_isDisposing, "no parent found" );
676
677 // Remember the parent as weak ref.
678 {
679 osl::MutexGuard aWeakParentGuard( m_Mutex );
680 m_xWeakParent = xAcc;
681 }
682
683 return xAcc;
684 }
685
getAccessibleParent()686 uno::Reference< XAccessible> SAL_CALL SwAccessibleContext::getAccessibleParent()
687 {
688 SolarMutexGuard aGuard;
689
690 ThrowIfDisposed();
691
692 return getAccessibleParentImpl();
693 }
694
getAccessibleIndexInParent()695 sal_Int32 SAL_CALL SwAccessibleContext::getAccessibleIndexInParent()
696 {
697 SolarMutexGuard aGuard;
698
699 ThrowIfDisposed();
700
701 const SwFrame *pUpper = GetParent();
702 OSL_ENSURE( pUpper != nullptr || m_isDisposing, "no upper found" );
703
704 sal_Int32 nIndex = -1;
705 if( pUpper )
706 {
707 ::rtl::Reference < SwAccessibleContext > xAccImpl(
708 GetMap()->GetContextImpl(pUpper, !m_isDisposing) );
709 OSL_ENSURE( xAccImpl.is() || m_isDisposing, "no parent found" );
710 if( xAccImpl.is() )
711 nIndex = xAccImpl->GetChildIndex( *(GetMap()), SwAccessibleChild(GetFrame()) );
712 }
713
714 return nIndex;
715 }
716
getAccessibleRole()717 sal_Int16 SAL_CALL SwAccessibleContext::getAccessibleRole()
718 {
719 return m_nRole;
720 }
721
getAccessibleName()722 OUString SAL_CALL SwAccessibleContext::getAccessibleName()
723 {
724 return m_sName;
725 }
726
727 uno::Reference< XAccessibleRelationSet> SAL_CALL
getAccessibleRelationSet()728 SwAccessibleContext::getAccessibleRelationSet()
729 {
730 // by default there are no relations
731 uno::Reference< XAccessibleRelationSet> xRet( new utl::AccessibleRelationSetHelper() );
732 return xRet;
733 }
734
735 uno::Reference<XAccessibleStateSet> SAL_CALL
getAccessibleStateSet()736 SwAccessibleContext::getAccessibleStateSet()
737 {
738 SolarMutexGuard aGuard;
739
740 ThrowIfDisposed();
741
742 rtl::Reference<::utl::AccessibleStateSetHelper> pStateSet =
743 new ::utl::AccessibleStateSetHelper;
744
745 if (m_isSelectedInDoc)
746 pStateSet->AddState( AccessibleStateType::SELECTED );
747
748 GetStates( *pStateSet );
749
750 return pStateSet;
751 }
752
getLocale()753 lang::Locale SAL_CALL SwAccessibleContext::getLocale()
754 {
755 SolarMutexGuard aGuard;
756
757 lang::Locale aLoc( Application::GetSettings().GetLanguageTag().getLocale() );
758 return aLoc;
759 }
760
addAccessibleEventListener(const uno::Reference<XAccessibleEventListener> & xListener)761 void SAL_CALL SwAccessibleContext::addAccessibleEventListener(
762 const uno::Reference< XAccessibleEventListener >& xListener )
763 {
764 if (xListener.is())
765 {
766 SolarMutexGuard aGuard;
767 if (!m_nClientId)
768 m_nClientId = comphelper::AccessibleEventNotifier::registerClient( );
769 comphelper::AccessibleEventNotifier::addEventListener( m_nClientId, xListener );
770 }
771 }
772
removeAccessibleEventListener(const uno::Reference<XAccessibleEventListener> & xListener)773 void SAL_CALL SwAccessibleContext::removeAccessibleEventListener(
774 const uno::Reference< XAccessibleEventListener >& xListener )
775 {
776 if (!(xListener.is() && m_nClientId))
777 return;
778
779 SolarMutexGuard aGuard;
780 sal_Int32 nListenerCount = comphelper::AccessibleEventNotifier::removeEventListener( m_nClientId, xListener );
781 if ( !nListenerCount )
782 {
783 // no listeners anymore
784 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
785 // and at least to us not firing any events anymore, in case somebody calls
786 // NotifyAccessibleEvent, again
787 comphelper::AccessibleEventNotifier::revokeClient( m_nClientId );
788 m_nClientId = 0;
789 }
790 }
791
lcl_PointInRectangle(const awt::Point & aPoint,const awt::Rectangle & aRect)792 static bool lcl_PointInRectangle(const awt::Point & aPoint,
793 const awt::Rectangle & aRect)
794 {
795 tools::Long nDiffX = aPoint.X - aRect.X;
796 tools::Long nDiffY = aPoint.Y - aRect.Y;
797
798 return
799 nDiffX >= 0 && nDiffX < aRect.Width && nDiffY >= 0 &&
800 nDiffY < aRect.Height;
801
802 }
803
containsPoint(const awt::Point & aPoint)804 sal_Bool SAL_CALL SwAccessibleContext::containsPoint(
805 const awt::Point& aPoint )
806 {
807 awt::Rectangle aPixBounds = getBoundsImpl(true);
808 aPixBounds.X = 0;
809 aPixBounds.Y = 0;
810
811 return lcl_PointInRectangle(aPoint, aPixBounds);
812 }
813
getAccessibleAtPoint(const awt::Point & aPoint)814 uno::Reference< XAccessible > SAL_CALL SwAccessibleContext::getAccessibleAtPoint(
815 const awt::Point& aPoint )
816 {
817 SolarMutexGuard aGuard;
818
819 ThrowIfDisposed();
820
821 uno::Reference< XAccessible > xAcc;
822
823 vcl::Window *pWin = GetWindow();
824 if (!pWin)
825 {
826 throw uno::RuntimeException("no Window", static_cast<cppu::OWeakObject*>(this));
827 }
828
829 Point aPixPoint( aPoint.X, aPoint.Y ); // px rel to parent
830 if( !GetFrame()->IsRootFrame() )
831 {
832 SwRect aLogBounds( GetBounds( *(GetMap()), GetFrame() ) ); // twip rel to doc root
833 Point aPixPos( GetMap()->CoreToPixel( aLogBounds ).TopLeft() );
834 aPixPoint.setX(aPixPoint.getX() + aPixPos.getX());
835 aPixPoint.setY(aPixPoint.getY() + aPixPos.getY());
836 }
837
838 const SwAccessibleChild aChild( GetChildAtPixel( aPixPoint, *(GetMap()) ) );
839 if( aChild.GetSwFrame() )
840 {
841 xAcc = GetMap()->GetContext( aChild.GetSwFrame() );
842 }
843 else if( aChild.GetDrawObject() )
844 {
845 xAcc = GetMap()->GetContext( aChild.GetDrawObject(), this );
846 }
847 else if ( aChild.GetWindow() )
848 {
849 xAcc = aChild.GetWindow()->GetAccessible();
850 }
851
852 return xAcc;
853 }
854
855 /**
856 Get bounding box.
857
858 There are two modes.
859
860 - relative
861
862 Return bounding box relative to parent if parent is no root
863 frame. Otherwise return the absolute bounding box.
864
865 - absolute
866
867 Return the absolute bounding box.
868
869 @param bRelative
870 true: Use relative mode.
871 false: Use absolute mode.
872 */
getBoundsImpl(bool bRelative)873 awt::Rectangle SwAccessibleContext::getBoundsImpl(bool bRelative)
874 {
875 SolarMutexGuard aGuard;
876
877 ThrowIfDisposed();
878
879 const SwFrame *pParent = GetParent();
880 OSL_ENSURE( pParent, "no Parent found" );
881 vcl::Window *pWin = GetWindow();
882
883 if (!pParent)
884 {
885 throw uno::RuntimeException("no Parent", static_cast<cppu::OWeakObject*>(this));
886 }
887 if (!pWin)
888 {
889 throw uno::RuntimeException("no Window", static_cast<cppu::OWeakObject*>(this));
890 }
891
892 SwRect aLogBounds( GetBounds( *(GetMap()), GetFrame() ) ); // twip relative to document root
893 tools::Rectangle aPixBounds( 0, 0, 0, 0 );
894 if( GetFrame()->IsPageFrame() &&
895 static_cast < const SwPageFrame * >( GetFrame() )->IsEmptyPage() )
896 {
897 OSL_ENSURE( GetShell()->IsPreview(), "empty page accessible?" );
898 if( GetShell()->IsPreview() )
899 {
900 // adjust method call <GetMap()->GetPreviewPageSize()>
901 sal_uInt16 nPageNum =
902 static_cast < const SwPageFrame * >( GetFrame() )->GetPhyPageNum();
903 aLogBounds.SSize( GetMap()->GetPreviewPageSize( nPageNum ) );
904 }
905 }
906 if( !aLogBounds.IsEmpty() )
907 {
908 aPixBounds = GetMap()->CoreToPixel( aLogBounds );
909 if( !pParent->IsRootFrame() && bRelative)
910 {
911 SwRect aParentLogBounds( GetBounds( *(GetMap()), pParent ) ); // twip rel to doc root
912 Point aParentPixPos( GetMap()->CoreToPixel( aParentLogBounds ).TopLeft() );
913 aPixBounds.Move( -aParentPixPos.getX(), -aParentPixPos.getY() );
914 }
915 }
916
917 awt::Rectangle aBox( aPixBounds.Left(), aPixBounds.Top(),
918 aPixBounds.GetWidth(), aPixBounds.GetHeight() );
919
920 return aBox;
921 }
922
getBounds()923 awt::Rectangle SAL_CALL SwAccessibleContext::getBounds()
924 {
925 return getBoundsImpl(true);
926 }
927
getLocation()928 awt::Point SAL_CALL SwAccessibleContext::getLocation()
929 {
930 awt::Rectangle aRect = getBoundsImpl(true);
931 awt::Point aPoint(aRect.X, aRect.Y);
932
933 return aPoint;
934 }
935
getLocationOnScreen()936 awt::Point SAL_CALL SwAccessibleContext::getLocationOnScreen()
937 {
938 awt::Rectangle aRect = getBoundsImpl(false);
939
940 Point aPixPos(aRect.X, aRect.Y);
941
942 vcl::Window *pWin = GetWindow();
943 if (!pWin)
944 {
945 throw uno::RuntimeException("no Window", static_cast<cppu::OWeakObject*>(this));
946 }
947
948 aPixPos = pWin->OutputToAbsoluteScreenPixel(aPixPos);
949 awt::Point aPoint(aPixPos.getX(), aPixPos.getY());
950
951 return aPoint;
952 }
953
getSize()954 awt::Size SAL_CALL SwAccessibleContext::getSize()
955 {
956 awt::Rectangle aRect = getBoundsImpl(false);
957 awt::Size aSize( aRect.Width, aRect.Height );
958
959 return aSize;
960 }
961
grabFocus()962 void SAL_CALL SwAccessibleContext::grabFocus()
963 {
964 SolarMutexGuard aGuard;
965
966 ThrowIfDisposed();
967
968 if( GetFrame()->IsFlyFrame() )
969 {
970 const SdrObject *pObj =
971 static_cast < const SwFlyFrame * >( GetFrame() )->GetVirtDrawObj();
972 if( pObj )
973 Select( const_cast < SdrObject * >( pObj ), false );
974 }
975 else
976 {
977 const SwContentFrame *pCFrame = nullptr;
978 if( GetFrame()->IsContentFrame() )
979 pCFrame = static_cast< const SwContentFrame * >( GetFrame() );
980 else if( GetFrame()->IsLayoutFrame() )
981 pCFrame = static_cast< const SwLayoutFrame * >( GetFrame() )->ContainsContent();
982
983 if( pCFrame && pCFrame->IsTextFrame() )
984 {
985 const SwTextFrame *pTextFrame = static_cast< const SwTextFrame * >( pCFrame );
986 const SwTextNode *pTextNd = pTextFrame->GetTextNodeFirst();
987 assert(pTextNd); // can it actually be null? probably not=>simplify
988 if( pTextNd )
989 {
990 // create pam for selection
991 SwPosition const aStartPos(pTextFrame->MapViewToModelPos(pTextFrame->GetOffset()));
992 SwPaM aPaM( aStartPos );
993
994 // set PaM at cursor shell
995 Select( aPaM );
996 }
997 }
998 }
999 }
1000
getForeground()1001 sal_Int32 SAL_CALL SwAccessibleContext::getForeground()
1002 {
1003 return sal_Int32(COL_BLACK);
1004 }
1005
getBackground()1006 sal_Int32 SAL_CALL SwAccessibleContext::getBackground()
1007 {
1008 return sal_Int32(COL_WHITE);
1009 }
1010
supportsService(const OUString & ServiceName)1011 sal_Bool SAL_CALL SwAccessibleContext::supportsService (const OUString& ServiceName)
1012 {
1013 return cppu::supportsService(this, ServiceName);
1014 }
1015
DisposeShape(const SdrObject * pObj,::accessibility::AccessibleShape * pAccImpl)1016 void SwAccessibleContext::DisposeShape( const SdrObject *pObj,
1017 ::accessibility::AccessibleShape *pAccImpl )
1018 {
1019 ::rtl::Reference< ::accessibility::AccessibleShape > xAccImpl( pAccImpl );
1020 if( !xAccImpl.is() )
1021 xAccImpl = GetMap()->GetContextImpl( pObj, this );
1022
1023 AccessibleEventObject aEvent;
1024 aEvent.EventId = AccessibleEventId::CHILD;
1025 uno::Reference< XAccessible > xAcc( xAccImpl );
1026 aEvent.OldValue <<= xAcc;
1027 FireAccessibleEvent( aEvent );
1028
1029 GetMap()->RemoveContext( pObj );
1030 xAccImpl->dispose();
1031 }
1032
ScrolledInShape(::accessibility::AccessibleShape * pAccImpl)1033 void SwAccessibleContext::ScrolledInShape( ::accessibility::AccessibleShape *pAccImpl )
1034 {
1035 if(nullptr == pAccImpl)
1036 {
1037 return ;
1038 }
1039 AccessibleEventObject aEvent;
1040 aEvent.EventId = AccessibleEventId::CHILD;
1041 uno::Reference< XAccessible > xAcc( pAccImpl );
1042 aEvent.NewValue <<= xAcc;
1043 FireAccessibleEvent( aEvent );
1044
1045 if( !pAccImpl->GetState( AccessibleStateType::FOCUSED ) )
1046 return;
1047
1048 vcl::Window *pWin = GetWindow();
1049 if( pWin && pWin->HasFocus() )
1050 {
1051 AccessibleEventObject aStateChangedEvent;
1052 aStateChangedEvent.EventId = AccessibleEventId::STATE_CHANGED;
1053 aStateChangedEvent.NewValue <<= AccessibleStateType::FOCUSED;
1054 aStateChangedEvent.Source = xAcc;
1055
1056 FireAccessibleEvent( aStateChangedEvent );
1057 }
1058 }
1059
Dispose(bool bRecursive,bool bCanSkipInvisible)1060 void SwAccessibleContext::Dispose(bool bRecursive, bool bCanSkipInvisible)
1061 {
1062 SolarMutexGuard aGuard;
1063
1064 OSL_ENSURE( GetFrame() && GetMap(), "already disposed" );
1065 OSL_ENSURE( GetMap()->GetVisArea() == GetVisArea(),
1066 "invalid visible area for dispose" );
1067
1068 m_isDisposing = true;
1069
1070 // dispose children
1071 if( bRecursive )
1072 DisposeChildren(GetFrame(), bRecursive, bCanSkipInvisible);
1073
1074 // get parent
1075 uno::Reference< XAccessible > xParent( GetWeakParent() );
1076 uno::Reference < XAccessibleContext > xThis( this );
1077
1078 // send child event at parent
1079 if( xParent.is() )
1080 {
1081 SwAccessibleContext *pAcc = static_cast<SwAccessibleContext *>(xParent.get());
1082
1083 AccessibleEventObject aEvent;
1084 aEvent.EventId = AccessibleEventId::CHILD;
1085 aEvent.OldValue <<= xThis;
1086 pAcc->FireAccessibleEvent( aEvent );
1087 }
1088
1089 // set defunc state (it's not required to broadcast a state changed
1090 // event if the object is disposed afterwards)
1091 {
1092 osl::MutexGuard aDefuncStateGuard( m_Mutex );
1093 m_isDefuncState = true;
1094 }
1095
1096 // broadcast dispose event
1097 if (m_nClientId)
1098 {
1099 comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( m_nClientId, *this );
1100 m_nClientId = 0;
1101 }
1102
1103 RemoveFrameFromAccessibleMap();
1104 ClearFrame();
1105 m_pMap = nullptr;
1106 m_wMap.reset();
1107
1108 m_isDisposing = false;
1109 }
1110
DisposeChild(const SwAccessibleChild & rChildFrameOrObj,bool bRecursive,bool bCanSkipInvisible)1111 void SwAccessibleContext::DisposeChild( const SwAccessibleChild& rChildFrameOrObj,
1112 bool bRecursive, bool bCanSkipInvisible )
1113 {
1114 SolarMutexGuard aGuard;
1115
1116 if ( !bCanSkipInvisible ||
1117 rChildFrameOrObj.AlwaysIncludeAsChild() ||
1118 IsShowing( *(GetMap()), rChildFrameOrObj ) ||
1119 !SwAccessibleChild( GetFrame() ).IsVisibleChildrenOnly() )
1120 {
1121 // If the object could have existed before, then there is nothing to do,
1122 // because no wrapper exists now and therefore no one is interested to
1123 // get notified of the movement.
1124 if( rChildFrameOrObj.GetSwFrame() )
1125 {
1126 ::rtl::Reference< SwAccessibleContext > xAccImpl =
1127 GetMap()->GetContextImpl( rChildFrameOrObj.GetSwFrame(), false );
1128 if (xAccImpl)
1129 xAccImpl->Dispose( bRecursive );
1130 }
1131 else if ( rChildFrameOrObj.GetDrawObject() )
1132 {
1133 ::rtl::Reference< ::accessibility::AccessibleShape > xAccImpl =
1134 GetMap()->GetContextImpl( rChildFrameOrObj.GetDrawObject(),
1135 this, false );
1136 if (xAccImpl)
1137 DisposeShape( rChildFrameOrObj.GetDrawObject(),
1138 xAccImpl.get() );
1139 }
1140 else if ( rChildFrameOrObj.GetWindow() )
1141 {
1142 AccessibleEventObject aEvent;
1143 aEvent.EventId = AccessibleEventId::CHILD;
1144 uno::Reference< XAccessible > xAcc =
1145 rChildFrameOrObj.GetWindow()->GetAccessible();
1146 aEvent.OldValue <<= xAcc;
1147 FireAccessibleEvent( aEvent );
1148 }
1149 }
1150 else if( bRecursive && rChildFrameOrObj.GetSwFrame() )
1151 DisposeChildren(rChildFrameOrObj.GetSwFrame(), bRecursive, bCanSkipInvisible);
1152 }
1153
InvalidatePosOrSize(const SwRect &)1154 void SwAccessibleContext::InvalidatePosOrSize( const SwRect& )
1155 {
1156 SolarMutexGuard aGuard;
1157
1158 OSL_ENSURE( GetFrame() && !GetFrame()->getFrameArea().IsEmpty(), "context should have a size" );
1159
1160 bool bIsOldShowingState;
1161 bool bIsNewShowingState = IsShowing( *(GetMap()) );
1162 {
1163 osl::MutexGuard aShowingStateGuard( m_Mutex );
1164 bIsOldShowingState = m_isShowingState;
1165 m_isShowingState = bIsNewShowingState;
1166 }
1167
1168 if( bIsOldShowingState != bIsNewShowingState )
1169 {
1170 FireStateChangedEvent( AccessibleStateType::SHOWING,
1171 bIsNewShowingState );
1172 }
1173 else if( bIsNewShowingState )
1174 {
1175 // The frame stays visible -> broadcast event
1176 FireVisibleDataEvent();
1177 }
1178
1179 // note: InvalidatePosOrSize must call InvalidateContent_ so that
1180 // SwAccessibleParagraph updates its portions, or dispose it
1181 // (see accmap.cxx: INVALID_CONTENT is contained in POS_CHANGED)
1182 if( !bIsNewShowingState &&
1183 SwAccessibleChild( GetParent() ).IsVisibleChildrenOnly() )
1184 {
1185 // this Dispose call was removed by IAccessibility2 implementation
1186 // without giving any reason why - without it we get stale
1187 // entries in SwAccessibleMap::mpFrameMap.
1188 Dispose(true);
1189 }
1190 else
1191 {
1192 InvalidateContent_( true );
1193 }
1194 }
1195
InvalidateChildPosOrSize(const SwAccessibleChild & rChildFrameOrObj,const SwRect & rOldFrame)1196 void SwAccessibleContext::InvalidateChildPosOrSize(
1197 const SwAccessibleChild& rChildFrameOrObj,
1198 const SwRect& rOldFrame )
1199 {
1200 SolarMutexGuard aGuard;
1201
1202 // this happens during layout, e.g. when a page is deleted and next page's
1203 // header/footer moves backward such an event is generated
1204 SAL_INFO_IF(rChildFrameOrObj.GetSwFrame() &&
1205 rChildFrameOrObj.GetSwFrame()->getFrameArea().IsEmpty(),
1206 "sw.a11y", "child context should have a size");
1207
1208 if ( rChildFrameOrObj.AlwaysIncludeAsChild() )
1209 {
1210 // nothing to do;
1211 return;
1212 }
1213
1214 const bool bVisibleChildrenOnly = SwAccessibleChild( GetFrame() ).IsVisibleChildrenOnly();
1215 const bool bNew = rOldFrame.IsEmpty() ||
1216 ( rOldFrame.Left() == 0 && rOldFrame.Top() == 0 );
1217 if( IsShowing( *(GetMap()), rChildFrameOrObj ) )
1218 {
1219 // If the object could have existed before, then there is nothing to do,
1220 // because no wrapper exists now and therefore no one is interested to
1221 // get notified of the movement.
1222 if( bNew || (bVisibleChildrenOnly && !IsShowing( rOldFrame )) )
1223 {
1224 if( rChildFrameOrObj.GetSwFrame() )
1225 {
1226 // The frame becomes visible. A child event must be send.
1227 ::rtl::Reference< SwAccessibleContext > xAccImpl =
1228 GetMap()->GetContextImpl( rChildFrameOrObj.GetSwFrame() );
1229 xAccImpl->ScrolledIn();
1230 }
1231 else if ( rChildFrameOrObj.GetDrawObject() )
1232 {
1233 ::rtl::Reference< ::accessibility::AccessibleShape > xAccImpl =
1234 GetMap()->GetContextImpl( rChildFrameOrObj.GetDrawObject(),
1235 this );
1236 // #i37790#
1237 if ( xAccImpl.is() )
1238 {
1239 ScrolledInShape( xAccImpl.get() );
1240 }
1241 else
1242 {
1243 OSL_FAIL( "<SwAccessibleContext::InvalidateChildPosOrSize(..)> - no accessible shape found." );
1244 }
1245 }
1246 else if ( rChildFrameOrObj.GetWindow() )
1247 {
1248 AccessibleEventObject aEvent;
1249 aEvent.EventId = AccessibleEventId::CHILD;
1250 aEvent.NewValue <<= rChildFrameOrObj.GetWindow()->GetAccessible();
1251 FireAccessibleEvent( aEvent );
1252 }
1253 }
1254 }
1255 else
1256 {
1257 // If the frame was visible before, then a child event for the parent
1258 // needs to be send. However, there is no wrapper existing, and so
1259 // no notifications for grandchildren are required. If the are
1260 // grandgrandchildren, they would be notified by the layout.
1261 if( bVisibleChildrenOnly &&
1262 !bNew && IsShowing( rOldFrame ) )
1263 {
1264 if( rChildFrameOrObj.GetSwFrame() )
1265 {
1266 ::rtl::Reference< SwAccessibleContext > xAccImpl =
1267 GetMap()->GetContextImpl( rChildFrameOrObj.GetSwFrame() );
1268 xAccImpl->SetParent( this );
1269 xAccImpl->Dispose( true );
1270 }
1271 else if ( rChildFrameOrObj.GetDrawObject() )
1272 {
1273 ::rtl::Reference< ::accessibility::AccessibleShape > xAccImpl =
1274 GetMap()->GetContextImpl( rChildFrameOrObj.GetDrawObject(),
1275 this );
1276 DisposeShape( rChildFrameOrObj.GetDrawObject(),
1277 xAccImpl.get() );
1278 }
1279 else if ( rChildFrameOrObj.GetWindow() )
1280 {
1281 OSL_FAIL( "<SwAccessibleContext::InvalidateChildPosOrSize(..)> - not expected to handle dispose of child of type <vcl::Window>." );
1282 }
1283 }
1284 }
1285 }
1286
InvalidateContent()1287 void SwAccessibleContext::InvalidateContent()
1288 {
1289 SolarMutexGuard aGuard;
1290
1291 InvalidateContent_( false );
1292 }
1293
InvalidateCursorPos()1294 void SwAccessibleContext::InvalidateCursorPos()
1295 {
1296 SolarMutexGuard aGuard;
1297
1298 InvalidateCursorPos_();
1299 }
1300
InvalidateFocus()1301 void SwAccessibleContext::InvalidateFocus()
1302 {
1303 SolarMutexGuard aGuard;
1304
1305 InvalidateFocus_();
1306 }
1307
1308 // #i27301# - use new type definition for <_nStates>
InvalidateStates(AccessibleStates _nStates)1309 void SwAccessibleContext::InvalidateStates( AccessibleStates _nStates )
1310 {
1311 if( !GetMap() )
1312 return;
1313
1314 SwViewShell *pVSh = GetMap()->GetShell();
1315 if( pVSh )
1316 {
1317 if( _nStates & AccessibleStates::EDITABLE )
1318 {
1319 bool bIsOldEditableState;
1320 bool bIsNewEditableState = IsEditable( pVSh );
1321 {
1322 osl::MutexGuard aGuard( m_Mutex );
1323 bIsOldEditableState = m_isEditableState;
1324 m_isEditableState = bIsNewEditableState;
1325 }
1326
1327 if( bIsOldEditableState != bIsNewEditableState )
1328 FireStateChangedEvent( AccessibleStateType::EDITABLE,
1329 bIsNewEditableState );
1330 }
1331 if( _nStates & AccessibleStates::OPAQUE )
1332 {
1333 bool bIsOldOpaqueState;
1334 bool bIsNewOpaqueState = IsOpaque( pVSh );
1335 {
1336 osl::MutexGuard aGuard( m_Mutex );
1337 bIsOldOpaqueState = m_isOpaqueState;
1338 m_isOpaqueState = bIsNewOpaqueState;
1339 }
1340
1341 if( bIsOldOpaqueState != bIsNewOpaqueState )
1342 FireStateChangedEvent( AccessibleStateType::OPAQUE,
1343 bIsNewOpaqueState );
1344 }
1345 }
1346
1347 InvalidateChildrenStates( GetFrame(), _nStates );
1348 }
1349
InvalidateRelation(sal_uInt16 nType)1350 void SwAccessibleContext::InvalidateRelation( sal_uInt16 nType )
1351 {
1352 AccessibleEventObject aEvent;
1353 aEvent.EventId = nType;
1354
1355 FireAccessibleEvent( aEvent );
1356 }
1357
1358 /** #i27301# - text selection has changed */
InvalidateTextSelection()1359 void SwAccessibleContext::InvalidateTextSelection()
1360 {
1361 AccessibleEventObject aEvent;
1362 aEvent.EventId = AccessibleEventId::TEXT_SELECTION_CHANGED;
1363
1364 FireAccessibleEvent( aEvent );
1365 }
1366
1367 /** #i88069# - attributes has changed */
InvalidateAttr()1368 void SwAccessibleContext::InvalidateAttr()
1369 {
1370 AccessibleEventObject aEvent;
1371 aEvent.EventId = AccessibleEventId::TEXT_ATTRIBUTE_CHANGED;
1372
1373 FireAccessibleEvent( aEvent );
1374 }
1375
HasCursor()1376 bool SwAccessibleContext::HasCursor()
1377 {
1378 return false;
1379 }
1380
Select(SwPaM * pPaM,SdrObject * pObj,bool bAdd)1381 bool SwAccessibleContext::Select( SwPaM *pPaM, SdrObject *pObj,
1382 bool bAdd )
1383 {
1384 SwCursorShell* pCursorShell = GetCursorShell();
1385 if( !pCursorShell )
1386 return false;
1387
1388 SwFEShell* pFEShell = dynamic_cast<SwFEShell*>(pCursorShell);
1389 // Get rid of activated OLE object
1390 if( pFEShell )
1391 pFEShell->FinishOLEObj();
1392
1393 SwWrtShell* pWrtShell = dynamic_cast<SwWrtShell*>(pCursorShell);
1394
1395 bool bRet = false;
1396 if( pObj )
1397 {
1398 if( pFEShell )
1399 {
1400 sal_uInt8 nFlags = bAdd ? SW_ADD_SELECT : 0;
1401 pFEShell->SelectObj( Point(), nFlags, pObj );
1402 bRet = true;
1403 }
1404 }
1405 else if( pPaM )
1406 {
1407 // Get rid of frame selection. If there is one, make text cursor
1408 // visible again.
1409 bool bCallShowCursor = false;
1410 if( pFEShell && (pFEShell->IsFrameSelected() ||
1411 pFEShell->IsObjSelected()) )
1412 {
1413 Point aPt( LONG_MIN, LONG_MIN );
1414 pFEShell->SelectObj( aPt );
1415 bCallShowCursor = true;
1416 }
1417 pCursorShell->KillPams();
1418 if( pWrtShell && pPaM->HasMark() )
1419 // We have to do this or SwWrtShell can't figure out that it needs
1420 // to kill the selection later, when the user moves the cursor.
1421 pWrtShell->SttSelect();
1422 pCursorShell->SetSelection( *pPaM );
1423 if( pPaM->HasMark() && *pPaM->GetPoint() == *pPaM->GetMark())
1424 // Setting a "Selection" that starts and ends at the same spot
1425 // should remove the selection rather than create an empty one, so
1426 // that we get defined behavior if accessibility sets the cursor
1427 // later.
1428 pCursorShell->ClearMark();
1429 if( bCallShowCursor )
1430 pCursorShell->ShowCursor();
1431 bRet = true;
1432 }
1433
1434 return bRet;
1435 }
1436
GetResource(const char * pResId,const OUString * pArg1,const OUString * pArg2)1437 OUString SwAccessibleContext::GetResource(const char* pResId,
1438 const OUString *pArg1,
1439 const OUString *pArg2)
1440 {
1441 OUString sStr = SwResId(pResId);
1442
1443 if( pArg1 )
1444 {
1445 sStr = sStr.replaceFirst( "$(ARG1)", *pArg1 );
1446 }
1447 if( pArg2 )
1448 {
1449 sStr = sStr.replaceFirst( "$(ARG2)", *pArg2 );
1450 }
1451
1452 return sStr;
1453 }
1454
RemoveFrameFromAccessibleMap()1455 void SwAccessibleContext::RemoveFrameFromAccessibleMap()
1456 {
1457 assert(m_refCount > 0); // must be alive to do this without using m_wMap
1458 if (m_isRegisteredAtAccessibleMap && GetFrame() && GetMap())
1459 GetMap()->RemoveContext( GetFrame() );
1460 }
1461
HasAdditionalAccessibleChildren()1462 bool SwAccessibleContext::HasAdditionalAccessibleChildren()
1463 {
1464 bool bRet( false );
1465
1466 if ( GetFrame()->IsTextFrame() )
1467 {
1468 SwPostItMgr* pPostItMgr = GetMap()->GetShell()->GetPostItMgr();
1469 if ( pPostItMgr && pPostItMgr->HasNotes() && pPostItMgr->ShowNotes() )
1470 {
1471 bRet = pPostItMgr->HasFrameConnectedSidebarWins( *(GetFrame()) );
1472 }
1473 }
1474
1475 return bRet;
1476 }
1477
1478 /** #i88070# - get additional accessible child by index */
GetAdditionalAccessibleChild(const sal_Int32 nIndex)1479 vcl::Window* SwAccessibleContext::GetAdditionalAccessibleChild( const sal_Int32 nIndex )
1480 {
1481 vcl::Window* pAdditionalAccessibleChild( nullptr );
1482
1483 if ( GetFrame()->IsTextFrame() )
1484 {
1485 SwPostItMgr* pPostItMgr = GetMap()->GetShell()->GetPostItMgr();
1486 if ( pPostItMgr && pPostItMgr->HasNotes() && pPostItMgr->ShowNotes() )
1487 {
1488 pAdditionalAccessibleChild =
1489 pPostItMgr->GetSidebarWinForFrameByIndex( *(GetFrame()), nIndex );
1490 }
1491 }
1492
1493 return pAdditionalAccessibleChild;
1494 }
1495
1496 /** #i88070# - get all additional accessible children */
GetAdditionalAccessibleChildren(std::vector<vcl::Window * > * pChildren)1497 void SwAccessibleContext::GetAdditionalAccessibleChildren( std::vector< vcl::Window* >* pChildren )
1498 {
1499 if ( GetFrame()->IsTextFrame() )
1500 {
1501 SwPostItMgr* pPostItMgr = GetMap()->GetShell()->GetPostItMgr();
1502 if ( pPostItMgr && pPostItMgr->HasNotes() && pPostItMgr->ShowNotes() )
1503 {
1504 pPostItMgr->GetAllSidebarWinForFrame( *(GetFrame()), pChildren );
1505 }
1506 }
1507 }
1508
SetSelectedState(bool const bSelected)1509 bool SwAccessibleContext::SetSelectedState(bool const bSelected)
1510 {
1511 if (m_isSelectedInDoc != bSelected)
1512 {
1513 m_isSelectedInDoc = bSelected;
1514 FireStateChangedEvent( AccessibleStateType::SELECTED, bSelected );
1515 return true;
1516 }
1517 return false;
1518 };
1519
1520 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1521