1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <com/sun/star/accessibility/AccessibleStateType.hpp>
21 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
22 #include <vcl/svapp.hxx>
23 #include <vcl/window.hxx>
26 #include <fmtcntnt.hxx>
27 #include <ndindex.hxx>
31 #include "accframebase.hxx"
34 #include <notxtfrm.hxx>
37 #include <fmtanchr.hxx>
39 using namespace ::com::sun::star
;
40 using namespace ::com::sun::star::accessibility
;
42 bool SwAccessibleFrameBase::IsSelected()
47 const SwViewShell
*pVSh
= GetMap()->GetShell();
49 if( auto pFESh
= dynamic_cast<const SwFEShell
*>(pVSh
) )
51 const SwFrame
*pFlyFrame
= pFESh
->GetSelectedFlyFrame();
52 if( pFlyFrame
== GetFrame() )
59 void SwAccessibleFrameBase::GetStates( sal_Int64
& rStateSet
)
61 SwAccessibleContext::GetStates( rStateSet
);
63 const SwViewShell
*pVSh
= GetMap()->GetShell();
66 if (dynamic_cast<const SwFEShell
*>(pVSh
))
69 rStateSet
|= AccessibleStateType::SELECTABLE
;
71 rStateSet
|= AccessibleStateType::FOCUSABLE
;
74 // SELECTED and FOCUSED
77 rStateSet
|= AccessibleStateType::SELECTED
;
78 SAL_WARN_IF(!m_bIsSelected
, "sw.a11y", "bSelected out of sync");
79 ::rtl::Reference
< SwAccessibleContext
> xThis( this );
80 GetMap()->SetCursorContext( xThis
);
82 vcl::Window
*pWin
= GetWindow();
83 if( pWin
&& pWin
->HasFocus() )
84 rStateSet
|= AccessibleStateType::FOCUSED
;
86 if( GetSelectedState() )
87 rStateSet
|= AccessibleStateType::SELECTED
;
90 SwNodeType
SwAccessibleFrameBase::GetNodeType( const SwFlyFrame
*pFlyFrame
)
92 SwNodeType nType
= SwNodeType::Text
;
93 if( pFlyFrame
->Lower() )
95 if( pFlyFrame
->Lower()->IsNoTextFrame() )
97 const SwNoTextFrame
*const pContentFrame
=
98 static_cast<const SwNoTextFrame
*>(pFlyFrame
->Lower());
99 nType
= pContentFrame
->GetNode()->GetNodeType();
104 const SwFrameFormat
*pFrameFormat
= pFlyFrame
->GetFormat();
105 const SwFormatContent
& rContent
= pFrameFormat
->GetContent();
106 const SwNodeIndex
*pNdIdx
= rContent
.GetContentIdx();
109 const SwContentNode
*pCNd
=
110 (pNdIdx
->GetNodes())[pNdIdx
->GetIndex()+1]->GetContentNode();
112 nType
= pCNd
->GetNodeType();
119 SwAccessibleFrameBase::SwAccessibleFrameBase(
120 std::shared_ptr
<SwAccessibleMap
> const& pInitMap
,
122 const SwFlyFrame
* pFlyFrame
) :
123 SwAccessibleContext( pInitMap
, nInitRole
, pFlyFrame
),
124 m_bIsSelected( false )
126 const SwFrameFormat
* pFrameFormat
= pFlyFrame
->GetFormat();
128 StartListening(const_cast<SwFrameFormat
*>(pFrameFormat
)->GetNotifier());
130 SetName( pFrameFormat
->GetName() );
132 m_bIsSelected
= IsSelected();
135 void SwAccessibleFrameBase::InvalidateCursorPos_()
137 bool bNewSelected
= IsSelected();
141 std::scoped_lock
aGuard( m_Mutex
);
142 bOldSelected
= m_bIsSelected
;
143 m_bIsSelected
= bNewSelected
;
148 // remember that object as the one that has the caret. This is
149 // necessary to notify that object if the cursor leaves it.
150 ::rtl::Reference
< SwAccessibleContext
> xThis( this );
151 GetMap()->SetCursorContext( xThis
);
154 if( bOldSelected
== bNewSelected
)
157 vcl::Window
*pWin
= GetWindow();
158 if( pWin
&& pWin
->HasFocus() && bNewSelected
)
159 FireStateChangedEvent( AccessibleStateType::FOCUSED
, bNewSelected
);
160 if( pWin
&& pWin
->HasFocus() && !bNewSelected
)
161 FireStateChangedEvent( AccessibleStateType::FOCUSED
, bNewSelected
);
165 uno::Reference
< XAccessible
> xParent( GetWeakParent() );
168 SwAccessibleContext
*pAcc
=
169 static_cast <SwAccessibleContext
*>( xParent
.get() );
171 AccessibleEventObject aEvent
;
172 aEvent
.EventId
= AccessibleEventId::SELECTION_CHANGED
;
173 uno::Reference
< XAccessible
> xChild(this);
174 aEvent
.NewValue
<<= xChild
;
175 pAcc
->FireAccessibleEvent( aEvent
);
179 void SwAccessibleFrameBase::InvalidateFocus_()
181 vcl::Window
*pWin
= GetWindow();
188 std::scoped_lock
aGuard( m_Mutex
);
189 bSelected
= m_bIsSelected
;
191 assert(bSelected
&& "focus object should be selected");
193 FireStateChangedEvent( AccessibleStateType::FOCUSED
,
194 pWin
->HasFocus() && bSelected
);
197 bool SwAccessibleFrameBase::HasCursor()
199 std::scoped_lock
aGuard( m_Mutex
);
200 return m_bIsSelected
;
203 SwAccessibleFrameBase::~SwAccessibleFrameBase()
207 void SwAccessibleFrameBase::Notify(const SfxHint
& rHint
)
209 const SwFlyFrame
* pFlyFrame
= static_cast<const SwFlyFrame
*>(GetFrame());
210 if(rHint
.GetId() == SfxHintId::Dying
)
214 else if (rHint
.GetId() == SfxHintId::SwNameChanged
&& pFlyFrame
)
216 auto rNameChanged
= static_cast<const sw::NameChanged
&>(rHint
);
217 const SwFrameFormat
* pFrameFormat
= pFlyFrame
->GetFormat();
219 const OUString
sOldName( GetName() );
220 assert( rNameChanged
.m_sOld
== sOldName
);
222 SetName( pFrameFormat
->GetName() );
223 assert( rNameChanged
.m_sNew
== GetName());
225 if( sOldName
!= GetName() )
227 AccessibleEventObject aEvent
;
228 aEvent
.EventId
= AccessibleEventId::NAME_CHANGED
;
229 aEvent
.OldValue
<<= sOldName
;
230 aEvent
.NewValue
<<= GetName();
231 FireAccessibleEvent( aEvent
);
236 void SwAccessibleFrameBase::Dispose(bool bRecursive
, bool bCanSkipInvisible
)
238 SolarMutexGuard aGuard
;
240 SwAccessibleContext::Dispose(bRecursive
, bCanSkipInvisible
);
243 //Get the selection cursor of the document.
244 SwPaM
* SwAccessibleFrameBase::GetCursor()
246 // get the cursor shell; if we don't have any, we don't have a
247 // cursor/selection either
248 SwPaM
* pCursor
= nullptr;
249 SwCursorShell
* pCursorShell
= GetCursorShell();
250 if( pCursorShell
!= nullptr && !pCursorShell
->IsTableMode() )
252 SwFEShell
*pFESh
= dynamic_cast<SwFEShell
*>( pCursorShell
);
254 !(pFESh
->IsFrameSelected() || pFESh
->IsObjSelected() > 0) )
256 // get the selection, and test whether it affects our text node
257 pCursor
= pCursorShell
->GetCursor( false /* ??? */ );
264 //Return the selected state of the object.
265 //when the object's anchor are in the selection cursor, we should return true.
266 bool SwAccessibleFrameBase::GetSelectedState( )
268 SolarMutexGuard aGuard
;
270 if(GetMap()->IsDocumentSelAll())
276 SwFlyFrame
* pFlyFrame
= getFlyFrame();
277 const SwFrameFormat
*pFrameFormat
= pFlyFrame
->GetFormat();
278 const SwFormatAnchor
& rAnchor
= pFrameFormat
->GetAnchor();
279 const SwPosition
*pPos
= rAnchor
.GetContentAnchor();
282 int nIndex
= pPos
->GetContentIndex();
283 if( pPos
->GetNode().GetTextNode() )
285 SwPaM
* pCursor
= GetCursor();
286 if( pCursor
!= nullptr )
288 const SwTextNode
* pNode
= pPos
->GetNode().GetTextNode();
289 SwNodeOffset nHere
= pNode
->GetIndex();
292 SwPaM
* pRingStart
= pCursor
;
295 // ignore, if no mark
296 if( pCursor
->HasMark() )
298 // check whether nHere is 'inside' pCursor
299 SwPosition
* pStart
= pCursor
->Start();
300 SwNodeOffset nStartIndex
= pStart
->GetNodeIndex();
301 SwPosition
* pEnd
= pCursor
->End();
302 SwNodeOffset nEndIndex
= pEnd
->GetNodeIndex();
303 if( ( nHere
>= nStartIndex
) && (nHere
<= nEndIndex
) )
305 if( rAnchor
.GetAnchorId() == RndStdIds::FLY_AS_CHAR
)
307 if( ((nHere
== nStartIndex
) && (nIndex
>= pStart
->GetContentIndex())) || (nHere
> nStartIndex
) )
308 if( ((nHere
== nEndIndex
) && (nIndex
< pEnd
->GetContentIndex())) || (nHere
< nEndIndex
) )
311 else if( rAnchor
.GetAnchorId() == RndStdIds::FLY_AT_PARA
)
313 if (IsSelectFrameAnchoredAtPara(*pPos
, *pStart
, *pEnd
))
316 else if (rAnchor
.GetAnchorId() == RndStdIds::FLY_AT_CHAR
)
318 if (IsDestroyFrameAnchoredAtChar(*pPos
, *pStart
, *pEnd
))
325 // else: this PaM doesn't point to this paragraph
327 // else: this PaM is collapsed and doesn't select anything
330 pCursor
= pCursor
->GetNext();
332 while( pCursor
!= pRingStart
);
338 SwFlyFrame
* SwAccessibleFrameBase::getFlyFrame() const
340 SwFlyFrame
* pFlyFrame
= nullptr;
342 const SwFrame
* pFrame
= GetFrame();
344 if( pFrame
->IsFlyFrame() )
346 pFlyFrame
= static_cast<SwFlyFrame
*>( const_cast<SwFrame
*>( pFrame
) );
352 bool SwAccessibleFrameBase::SetSelectedState( bool )
354 bool bParaSelected
= GetSelectedState() || IsSelected();
356 if (m_isSelectedInDoc
!= bParaSelected
)
358 m_isSelectedInDoc
= bParaSelected
;
359 FireStateChangedEvent( AccessibleStateType::SELECTED
, bParaSelected
);
365 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */