LibreOffice Module sw (master) 1
accselectionhelper.cxx
Go to the documentation of this file.
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 <com/sun/star/accessibility/XAccessibleSelection.hpp>
22
23#include "acccontext.hxx"
24#include <accmap.hxx>
25#include <o3tl/safeint.hxx>
27#include <viewsh.hxx>
28#include <fesh.hxx>
29#include <vcl/svapp.hxx>
30#include <flyfrm.hxx>
31
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>
36
37using namespace ::com::sun::star::accessibility;
38using namespace ::com::sun::star;
39using namespace ::com::sun::star::uno;
40
41using ::com::sun::star::accessibility::XAccessible;
42using ::com::sun::star::accessibility::XAccessibleContext;
43using ::com::sun::star::accessibility::XAccessibleSelection;
44
45using namespace ::sw::access;
46
48 SwAccessibleContext& rContext ) :
49 m_rContext( rContext )
50{
51}
52
54{
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?" );
59
60 SwFEShell* pFEShell = dynamic_cast<SwFEShell*>( pViewShell );
61
62 return pFEShell;
63}
64
66{
67 Reference < XAccessibleContext > xThis( &m_rContext );
68 Reference < XAccessibleSelection >xSelThis( xThis, UNO_QUERY );
69 lang::IndexOutOfBoundsException aExcept(
70 "index out of bounds",
71 xSelThis );
72 throw aExcept;
73}
74
75// XAccessibleSelection
77 sal_Int64 nChildIndex )
78{
79 SolarMutexGuard aGuard;
80
81 if (nChildIndex < 0 || nChildIndex >= m_rContext.GetChildCount(*(m_rContext.GetMap())))
83
84 // Get the respective child as SwFrame (also do index checking), ...
85 const SwAccessibleChild aChild = m_rContext.GetChild( *(m_rContext.GetMap()),
86 nChildIndex );
87 if( !aChild.IsValid() )
89
90 // we can only select fly frames, so we ignore (should: return
91 // false) all other attempts at child selection
92 SwFEShell* pFEShell = GetFEShell();
93 if( pFEShell != nullptr )
94 {
95 const SdrObject *pObj = aChild.GetDrawObject();
96 if( pObj )
97 m_rContext.Select( const_cast< SdrObject *>( pObj ), nullptr==aChild.GetSwFrame());
98 }
99 // no frame shell, or no frame, or no fly frame -> can't select
100}
101
102//When the selected state of the SwFrameOrObj is set, return true.
103static bool lcl_getSelectedState(const SwAccessibleChild& aChild,
104 SwAccessibleContext* pContext,
105 SwAccessibleMap* pMap)
106{
107 Reference< XAccessible > xAcc;
108 if ( aChild.GetSwFrame() )
109 {
110 xAcc = pMap->GetContext( aChild.GetSwFrame(), false );
111 }
112 else if ( aChild.GetDrawObject() )
113 {
114 xAcc = pMap->GetContext( aChild.GetDrawObject(), pContext, false );
115 }
116
117 if( xAcc.is() )
118 {
119 Reference< XAccessibleContext > pRContext = xAcc->getAccessibleContext();
120 if(!pRContext.is())
121 return false;
122 sal_Int64 nRStateSet = pRContext->getAccessibleStateSet();
123 if(nRStateSet & AccessibleStateType::SELECTED)
124 return true;
125 }
126 return false;
127}
128
130 sal_Int64 nChildIndex )
131{
132 SolarMutexGuard aGuard;
133
134 if (nChildIndex < 0 || nChildIndex >= m_rContext.GetChildCount(*(m_rContext.GetMap())))
136
137 // Get the respective child as SwFrame (also do index checking), ...
138 const SwAccessibleChild aChild = m_rContext.GetChild( *(m_rContext.GetMap()),
139 nChildIndex );
140 if( !aChild.IsValid() )
142
143 // ... and compare to the currently selected frame
144 bool bRet = false;
145 const SwFEShell* pFEShell = GetFEShell();
146 if( pFEShell )
147 {
148 if ( aChild.GetSwFrame() != nullptr )
149 {
150 bRet = (pFEShell->GetSelectedFlyFrame() == aChild.GetSwFrame());
151 }
152 else if ( aChild.GetDrawObject() )
153 {
154 bRet = pFEShell->IsObjSelected( *aChild.GetDrawObject() );
155 }
156 //If the SwFrameOrObj is not selected directly in the UI, we should check whether it is selected in the selection cursor.
157 if( !bRet )
158 {
160 bRet = true;
161 }
162 }
163
164 return bRet;
165}
166
168{
169 SolarMutexGuard aGuard;
170
171 // We can select only one. So iterate over the children to find
172 // the first we can select, and select it.
173
174 SwFEShell* pFEShell = GetFEShell();
175 if( !pFEShell )
176 return;
177
178 std::list< SwAccessibleChild > aChildren;
179 m_rContext.GetChildren( *(m_rContext.GetMap()), aChildren );
180
181 for( const SwAccessibleChild& rChild : aChildren )
182 {
183 const SdrObject* pObj = rChild.GetDrawObject();
184 const SwFrame* pFrame = rChild.GetSwFrame();
185 if( pObj && !(pFrame != nullptr && pFEShell->IsObjSelected()) )
186 {
187 m_rContext.Select( const_cast< SdrObject *>( pObj ), nullptr==pFrame );
188 if( pFrame )
189 break;
190 }
191 }
192}
193
195{
196 SolarMutexGuard aGuard;
197
198 sal_Int64 nCount = 0;
199 // Only one frame can be selected at a time, and we only frames
200 // for selectable children.
201 const SwFEShell* pFEShell = GetFEShell();
202 if( pFEShell != nullptr )
203 {
204 const SwFlyFrame* pFlyFrame = pFEShell->GetSelectedFlyFrame();
205 if( pFlyFrame )
206 {
207 nCount = 1;
208 }
209 else
210 {
211 const size_t nSelObjs = pFEShell->IsObjSelected();
212 if( nSelObjs > 0 )
213 {
214 std::list< SwAccessibleChild > aChildren;
215 m_rContext.GetChildren( *(m_rContext.GetMap()), aChildren );
216
217 for( const SwAccessibleChild& rChild : aChildren )
218 {
219 if( rChild.GetDrawObject() && !rChild.GetSwFrame() &&
221 == m_rContext.GetFrame() &&
222 pFEShell->IsObjSelected( *rChild.GetDrawObject() ) )
223 {
224 nCount++;
225 }
226 if (o3tl::make_unsigned(nCount) >= nSelObjs)
227 break;
228 }
229 }
230 }
231 //If the SwFrameOrObj is not selected directly in the UI,
232 //we should check whether it is selected in the selection cursor.
233 if( nCount == 0 )
234 {
235 std::list< SwAccessibleChild > aChildren;
236 m_rContext.GetChildren( *(m_rContext.GetMap()), aChildren );
237 nCount = static_cast<sal_Int32>(std::count_if(aChildren.begin(), aChildren.end(),
238 [this](const SwAccessibleChild& aChild) { return lcl_getSelectedState(aChild, &m_rContext, m_rContext.GetMap()); }));
239 }
240 }
241 return nCount;
242}
243
245 sal_Int64 nSelectedChildIndex )
246{
247 SolarMutexGuard aGuard;
248
249 // Since the index is relative to the selected children, and since
250 // there can be at most one selected frame child, the index must
251 // be 0, and a selection must exist, otherwise we have to throw an
252 // lang::IndexOutOfBoundsException
253 SwFEShell* pFEShell = GetFEShell();
254 if( nullptr == pFEShell )
256
257 SwAccessibleChild aChild;
258 const SwFlyFrame *pFlyFrame = pFEShell->GetSelectedFlyFrame();
259 if( pFlyFrame )
260 {
261 if( 0 == nSelectedChildIndex )
262 {
263 if(SwAccessibleFrame::GetParent( SwAccessibleChild(pFlyFrame), m_rContext.IsInPagePreview()) == m_rContext.GetFrame() )
264 {
265 aChild = pFlyFrame;
266 }
267 else
268 {
269 const SwFrameFormat *pFrameFormat = pFlyFrame->GetFormat();
270 if (pFrameFormat)
271 {
272 const SwFormatAnchor& rAnchor = pFrameFormat->GetAnchor();
273 if( rAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR )
274 {
275 const SwFrame *pParaFrame = SwAccessibleFrame::GetParent( SwAccessibleChild(pFlyFrame), m_rContext.IsInPagePreview() );
276 aChild = pParaFrame;
277 }
278 }
279 }
280 }
281 }
282 else
283 {
284 const size_t nSelObjs = pFEShell->IsObjSelected();
285 if( 0 == nSelObjs || o3tl::make_unsigned(nSelectedChildIndex) >= nSelObjs )
287
288 std::list< SwAccessibleChild > aChildren;
289 m_rContext.GetChildren( *(m_rContext.GetMap()), aChildren );
290
291 for( const SwAccessibleChild& rChild : aChildren )
292 {
293 if( rChild.GetDrawObject() && !rChild.GetSwFrame() &&
296 pFEShell->IsObjSelected( *rChild.GetDrawObject() ) )
297 {
298 if( 0 == nSelectedChildIndex )
299 aChild = rChild;
300 else
301 --nSelectedChildIndex;
302 }
303 if (aChild.IsValid())
304 break;
305 }
306 }
307
308 if( !aChild.IsValid() )
310
311 OSL_ENSURE( m_rContext.GetMap() != nullptr, "We need the map." );
312 Reference< XAccessible > xChild;
313 if( aChild.GetSwFrame() )
314 {
316 m_rContext.GetMap()->GetContextImpl( aChild.GetSwFrame() ) );
317 if( xChildImpl.is() )
318 {
319 xChildImpl->SetParent( &m_rContext );
320 xChild = xChildImpl.get();
321 }
322 }
323 else if ( aChild.GetDrawObject() )
324 {
326 m_rContext.GetMap()->GetContextImpl( aChild.GetDrawObject(),
327 &m_rContext ) );
328 if( xChildImpl.is() )
329 xChild = xChildImpl.get();
330 }
331 return xChild;
332}
333
334// index has to be treated as global child index.
336 sal_Int64 nChildIndex )
337{
339
340 if( nChildIndex < 0 ||
341 nChildIndex >= m_rContext.GetChildCount( *(m_rContext.GetMap()) ) )
343}
344
345/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static bool lcl_getSelectedState(const SwAccessibleChild &aChild, SwAccessibleContext *pContext, SwAccessibleMap *pMap)
SwAccessibleMap * GetMap()
Definition: acccontext.hxx:112
bool Select(SwPaM *pPaM, SdrObject *pObj, bool bAdd)
bool IsInPagePreview() const
Definition: accframe.hxx:87
static void GetChildren(SwAccessibleMap &rAccMap, const SwRect &rVisArea, const SwFrame &rFrame, std::list< sw::access::SwAccessibleChild > &rChildren, bool bInPagePreview)
Definition: accframe.cxx:277
static sal_Int32 GetChildCount(SwAccessibleMap &rAccMap, const SwRect &rVisArea, const SwFrame *pFrame, bool bInPagePreviewr)
Definition: accframe.cxx:41
static sw::access::SwAccessibleChild GetChild(SwAccessibleMap &rAccMap, const SwRect &rVisArea, const SwFrame &rFrame, sal_Int32 &rPos, bool bInPagePreview)
Definition: accframe.cxx:71
const SwFrame * GetFrame() const
Definition: accframe.hxx:103
const SwFrame * GetParent() const
Definition: accframe.hxx:155
::rtl::Reference< SwAccessibleContext > GetContextImpl(const SwFrame *pFrame, bool bCreate=true)
Definition: accmap.cxx:1913
css::uno::Reference< css::accessibility::XAccessible > GetContext(const SwFrame *pFrame, bool bCreate=true)
Definition: accmap.cxx:1785
SwViewShell * GetShell() const
Definition: accmap.hxx:174
SwAccessibleContext & m_rContext
the context on which this helper works
SwAccessibleSelectionHelper(SwAccessibleContext &rContext)
bool isAccessibleChildSelected(sal_Int64 nChildIndex)
void selectAccessibleChild(sal_Int64 nChildIndex)
SwFEShell * GetFEShell()
get FE-Shell
css::uno::Reference< css::accessibility::XAccessible > getSelectedAccessibleChild(sal_Int64 nSelectedChildIndex)
void deselectAccessibleChild(sal_Int64 nChildIndex)
SwFlyFrame * GetSelectedFlyFrame() const
Definition: fefly1.cxx:277
size_t IsObjSelected() const
Definition: feshview.cxx:1245
general base class for all free-flowing frames
Definition: flyfrm.hxx:79
virtual const SwFlyFrameFormat * GetFormat() const override
Definition: fly.cxx:2905
FlyAnchors.
Definition: fmtanchr.hxx:37
RndStdIds GetAnchorId() const
Definition: fmtanchr.hxx:67
const SwFormatAnchor & GetAnchor(bool=true) const
Definition: fmtanchr.hxx:88
Style of a layout element.
Definition: frmfmt.hxx:62
Base class of the Writer layout elements.
Definition: frame.hxx:315
int nCount
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
const Reference< XComponentContext > & m_rContext