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/XAccessibleSelection.hpp>
21 #include "accselectionhelper.hxx"
23 #include "acccontext.hxx"
25 #include <o3tl/safeint.hxx>
26 #include <svx/AccessibleShape.hxx>
29 #include <vcl/svapp.hxx>
32 #include <com/sun/star/uno/Reference.hxx>
33 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
34 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
35 #include <fmtanchr.hxx>
37 using namespace ::com::sun::star::accessibility
;
38 using namespace ::com::sun::star
;
39 using namespace ::com::sun::star::uno
;
41 using ::com::sun::star::accessibility::XAccessible
;
42 using ::com::sun::star::accessibility::XAccessibleContext
;
43 using ::com::sun::star::accessibility::XAccessibleSelection
;
45 using namespace ::sw::access
;
47 SwAccessibleSelectionHelper::SwAccessibleSelectionHelper(
48 SwAccessibleContext
& rContext
) :
49 m_rContext( rContext
)
53 SwFEShell
* SwAccessibleSelectionHelper::GetFEShell()
55 OSL_ENSURE( m_rContext
.GetMap() != nullptr, "no map?" );
56 SwViewShell
* pViewShell
= m_rContext
.GetMap()->GetShell();
57 OSL_ENSURE( pViewShell
!= nullptr,
58 "No view shell? Then what are you looking at?" );
60 SwFEShell
* pFEShell
= dynamic_cast<SwFEShell
*>( pViewShell
);
65 void SwAccessibleSelectionHelper::throwIndexOutOfBoundsException()
67 Reference
< XAccessibleContext
> xThis( &m_rContext
);
68 Reference
< XAccessibleSelection
>xSelThis( xThis
, UNO_QUERY
);
69 lang::IndexOutOfBoundsException
aExcept(
70 "index out of bounds",
75 // XAccessibleSelection
76 void SwAccessibleSelectionHelper::selectAccessibleChild(
77 sal_Int64 nChildIndex
)
79 SolarMutexGuard aGuard
;
81 if (nChildIndex
< 0 || nChildIndex
>= m_rContext
.GetChildCount(*(m_rContext
.GetMap())))
82 throwIndexOutOfBoundsException();
84 // Get the respective child as SwFrame (also do index checking), ...
85 const SwAccessibleChild aChild
= m_rContext
.GetChild( *(m_rContext
.GetMap()),
87 if( !aChild
.IsValid() )
88 throwIndexOutOfBoundsException();
90 // we can only select fly frames, so we ignore (should: return
91 // false) all other attempts at child selection
94 const SdrObject
*pObj
= aChild
.GetDrawObject();
96 m_rContext
.Select( const_cast< SdrObject
*>( pObj
), nullptr==aChild
.GetSwFrame());
98 // no frame shell, or no frame, or no fly frame -> can't select
101 //When the selected state of the SwFrameOrObj is set, return true.
102 static bool lcl_getSelectedState(const SwAccessibleChild
& aChild
,
103 SwAccessibleContext
* pContext
,
104 SwAccessibleMap
* pMap
)
106 Reference
< XAccessible
> xAcc
;
107 if ( aChild
.GetSwFrame() )
109 xAcc
= pMap
->GetContext( aChild
.GetSwFrame(), false );
111 else if ( aChild
.GetDrawObject() )
113 xAcc
= pMap
->GetContext( aChild
.GetDrawObject(), pContext
, false );
118 Reference
< XAccessibleContext
> pRContext
= xAcc
->getAccessibleContext();
121 sal_Int64 nRStateSet
= pRContext
->getAccessibleStateSet();
122 if(nRStateSet
& AccessibleStateType::SELECTED
)
128 bool SwAccessibleSelectionHelper::isAccessibleChildSelected(
129 sal_Int64 nChildIndex
)
131 SolarMutexGuard aGuard
;
133 if (nChildIndex
< 0 || nChildIndex
>= m_rContext
.GetChildCount(*(m_rContext
.GetMap())))
134 throwIndexOutOfBoundsException();
136 // Get the respective child as SwFrame (also do index checking), ...
137 const SwAccessibleChild aChild
= m_rContext
.GetChild( *(m_rContext
.GetMap()),
139 if( !aChild
.IsValid() )
140 throwIndexOutOfBoundsException();
142 // ... and compare to the currently selected frame
144 if (const SwFEShell
* pFEShell
= GetFEShell())
146 if ( aChild
.GetSwFrame() != nullptr )
148 bRet
= (pFEShell
->GetSelectedFlyFrame() == aChild
.GetSwFrame());
150 else if ( aChild
.GetDrawObject() )
152 bRet
= pFEShell
->IsObjSelected( *aChild
.GetDrawObject() );
154 //If the SwFrameOrObj is not selected directly in the UI, we should check whether it is selected in the selection cursor.
157 if( lcl_getSelectedState( aChild
, &m_rContext
, m_rContext
.GetMap() ) )
165 void SwAccessibleSelectionHelper::selectAllAccessibleChildren( )
167 SolarMutexGuard aGuard
;
169 // We can select only one. So iterate over the children to find
170 // the first we can select, and select it.
172 SwFEShell
* pFEShell
= GetFEShell();
176 std::list
< SwAccessibleChild
> aChildren
;
177 m_rContext
.GetChildren( *(m_rContext
.GetMap()), aChildren
);
179 for( const SwAccessibleChild
& rChild
: aChildren
)
181 const SdrObject
* pObj
= rChild
.GetDrawObject();
182 const SwFrame
* pFrame
= rChild
.GetSwFrame();
183 if( pObj
&& !(pFrame
!= nullptr && pFEShell
->IsObjSelected()) )
185 m_rContext
.Select( const_cast< SdrObject
*>( pObj
), nullptr==pFrame
);
192 sal_Int64
SwAccessibleSelectionHelper::getSelectedAccessibleChildCount( )
194 SolarMutexGuard aGuard
;
196 sal_Int64 nCount
= 0;
197 // Only one frame can be selected at a time, and we only frames
198 // for selectable children.
199 if (const SwFEShell
* pFEShell
= GetFEShell())
201 const SwFlyFrame
* pFlyFrame
= pFEShell
->GetSelectedFlyFrame();
208 const size_t nSelObjs
= pFEShell
->IsObjSelected();
211 std::list
< SwAccessibleChild
> aChildren
;
212 m_rContext
.GetChildren( *(m_rContext
.GetMap()), aChildren
);
214 for( const SwAccessibleChild
& rChild
: aChildren
)
216 if( rChild
.GetDrawObject() && !rChild
.GetSwFrame() &&
217 SwAccessibleFrame::GetParent(rChild
, m_rContext
.IsInPagePreview())
218 == m_rContext
.GetFrame() &&
219 pFEShell
->IsObjSelected( *rChild
.GetDrawObject() ) )
223 if (o3tl::make_unsigned(nCount
) >= nSelObjs
)
228 //If the SwFrameOrObj is not selected directly in the UI,
229 //we should check whether it is selected in the selection cursor.
232 std::list
< SwAccessibleChild
> aChildren
;
233 m_rContext
.GetChildren( *(m_rContext
.GetMap()), aChildren
);
234 nCount
= static_cast<sal_Int32
>(std::count_if(aChildren
.begin(), aChildren
.end(),
235 [this](const SwAccessibleChild
& aChild
) { return lcl_getSelectedState(aChild
, &m_rContext
, m_rContext
.GetMap()); }));
241 Reference
<XAccessible
> SwAccessibleSelectionHelper::getSelectedAccessibleChild(
242 sal_Int64 nSelectedChildIndex
)
244 SolarMutexGuard aGuard
;
246 // Since the index is relative to the selected children, and since
247 // there can be at most one selected frame child, the index must
248 // be 0, and a selection must exist, otherwise we have to throw an
249 // lang::IndexOutOfBoundsException
250 SwFEShell
* pFEShell
= GetFEShell();
252 throwIndexOutOfBoundsException();
254 SwAccessibleChild aChild
;
255 const SwFlyFrame
*pFlyFrame
= pFEShell
->GetSelectedFlyFrame();
258 if( 0 == nSelectedChildIndex
)
260 if(SwAccessibleFrame::GetParent( SwAccessibleChild(pFlyFrame
), m_rContext
.IsInPagePreview()) == m_rContext
.GetFrame() )
266 const SwFrameFormat
*pFrameFormat
= pFlyFrame
->GetFormat();
269 const SwFormatAnchor
& rAnchor
= pFrameFormat
->GetAnchor();
270 if( rAnchor
.GetAnchorId() == RndStdIds::FLY_AS_CHAR
)
272 const SwFrame
*pParaFrame
= SwAccessibleFrame::GetParent( SwAccessibleChild(pFlyFrame
), m_rContext
.IsInPagePreview() );
281 const size_t nSelObjs
= pFEShell
->IsObjSelected();
282 if( 0 == nSelObjs
|| o3tl::make_unsigned(nSelectedChildIndex
) >= nSelObjs
)
283 throwIndexOutOfBoundsException();
285 std::list
< SwAccessibleChild
> aChildren
;
286 m_rContext
.GetChildren( *(m_rContext
.GetMap()), aChildren
);
288 for( const SwAccessibleChild
& rChild
: aChildren
)
290 if( rChild
.GetDrawObject() && !rChild
.GetSwFrame() &&
291 SwAccessibleFrame::GetParent(rChild
, m_rContext
.IsInPagePreview()) ==
292 m_rContext
.GetFrame() &&
293 pFEShell
->IsObjSelected( *rChild
.GetDrawObject() ) )
295 if( 0 == nSelectedChildIndex
)
298 --nSelectedChildIndex
;
300 if (aChild
.IsValid())
305 if( !aChild
.IsValid() )
306 throwIndexOutOfBoundsException();
308 OSL_ENSURE( m_rContext
.GetMap() != nullptr, "We need the map." );
309 Reference
< XAccessible
> xChild
;
310 if( aChild
.GetSwFrame() )
312 ::rtl::Reference
< SwAccessibleContext
> xChildImpl(
313 m_rContext
.GetMap()->GetContextImpl( aChild
.GetSwFrame() ) );
314 if( xChildImpl
.is() )
316 xChildImpl
->SetParent( &m_rContext
);
317 xChild
= xChildImpl
.get();
320 else if ( aChild
.GetDrawObject() )
322 ::rtl::Reference
< ::accessibility::AccessibleShape
> xChildImpl(
323 m_rContext
.GetMap()->GetContextImpl( aChild
.GetDrawObject(),
325 if( xChildImpl
.is() )
326 xChild
= xChildImpl
.get();
331 // index has to be treated as global child index.
332 void SwAccessibleSelectionHelper::deselectAccessibleChild(
333 sal_Int64 nChildIndex
)
337 if( nChildIndex
< 0 ||
338 nChildIndex
>= m_rContext
.GetChildCount( *(m_rContext
.GetMap()) ) )
339 throwIndexOutOfBoundsException();
342 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */