1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26
27
28 #include <com/sun/star/accessibility/XAccessibleSelection.hpp>
29 #include <accselectionhelper.hxx>
30
31 #include <acccontext.hxx>
32 #include <accmap.hxx>
33 #include <svx/AccessibleShape.hxx>
34 #include <viewsh.hxx>
35 #include <fesh.hxx>
36 #include <vcl/svapp.hxx> // for SolarMutex
37 #include <tools/debug.hxx>
38 #include <flyfrm.hxx>
39
40
41 #include <com/sun/star/uno/Reference.hxx>
42 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
43 #include <com/sun/star/accessibility/XAccessibleStateSet.hpp>
44 #include <fmtanchr.hxx>
45
46 using namespace ::com::sun::star::accessibility;
47 using namespace ::com::sun::star;
48 using namespace ::com::sun::star::uno;
49
50 using ::com::sun::star::accessibility::XAccessible;
51 using ::com::sun::star::accessibility::XAccessibleContext;
52 using ::com::sun::star::accessibility::XAccessibleSelection;
53
54 using namespace ::sw::access;
55
SwAccessibleSelectionHelper(SwAccessibleContext & rCtxt)56 SwAccessibleSelectionHelper::SwAccessibleSelectionHelper(
57 SwAccessibleContext& rCtxt ) :
58 rContext( rCtxt )
59 {
60 }
61
~SwAccessibleSelectionHelper()62 SwAccessibleSelectionHelper::~SwAccessibleSelectionHelper()
63 {
64 }
65
GetFEShell()66 SwFEShell* SwAccessibleSelectionHelper::GetFEShell()
67 {
68 DBG_ASSERT( rContext.GetMap() != NULL, "no map?" );
69 ViewShell* pViewShell = rContext.GetMap()->GetShell();
70 DBG_ASSERT( pViewShell != NULL,
71 "No view shell? Then what are you looking at?" );
72
73 SwFEShell* pFEShell = NULL;
74 if( pViewShell->ISA( SwFEShell ) )
75 {
76 pFEShell = static_cast<SwFEShell*>( pViewShell );
77 }
78
79 return pFEShell;
80 }
81
throwIndexOutOfBoundsException()82 void SwAccessibleSelectionHelper::throwIndexOutOfBoundsException()
83 throw ( lang::IndexOutOfBoundsException )
84 {
85 Reference < XAccessibleContext > xThis( &rContext );
86 Reference < XAccessibleSelection >xSelThis( xThis, UNO_QUERY );
87 lang::IndexOutOfBoundsException aExcept(
88 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("index out of bounds") ),
89 xSelThis ); \
90 throw aExcept;
91 }
92
93
94 //===== XAccessibleSelection ============================================
95
selectAccessibleChild(sal_Int32 nChildIndex)96 void SwAccessibleSelectionHelper::selectAccessibleChild(
97 sal_Int32 nChildIndex )
98 throw ( lang::IndexOutOfBoundsException,
99 RuntimeException )
100 {
101 vos::OGuard aGuard(Application::GetSolarMutex());
102
103 // Get the respective child as SwFrm (also do index checking), ...
104 const SwAccessibleChild aChild = rContext.GetChild( *(rContext.GetMap()),
105 nChildIndex );
106 if( !aChild.IsValid() )
107 throwIndexOutOfBoundsException();
108
109 // we can only select fly frames, so we ignore (should: return
110 // false) all other attempts at child selection
111 sal_Bool bRet = sal_False;
112 SwFEShell* pFEShell = GetFEShell();
113 if( pFEShell != NULL )
114 {
115 const SdrObject *pObj = aChild.GetDrawObject();
116 if( pObj )
117 {
118 bRet = rContext.Select( const_cast< SdrObject *>( pObj ), 0==aChild.GetSwFrm());
119 }
120 }
121 // no frame shell, or no frame, or no fly frame -> can't select
122
123 // return bRet;
124 }
125
126 //When the selected state of the SwFrmOrObj is setted, return true.
lcl_getSelectedState(const SwAccessibleChild & aChild,SwAccessibleContext * pContext,SwAccessibleMap * pMap)127 static sal_Bool lcl_getSelectedState(const SwAccessibleChild& aChild,
128 SwAccessibleContext* pContext,
129 SwAccessibleMap* pMap)
130 {
131 Reference< XAccessible > xAcc;
132 if ( aChild.GetSwFrm() )
133 {
134 xAcc = pMap->GetContext( aChild.GetSwFrm(), sal_False );
135 }
136 else if ( aChild.GetDrawObject() )
137 {
138 xAcc = pMap->GetContext( aChild.GetDrawObject(), pContext, sal_False );
139 }
140
141 if( xAcc.is() )
142 {
143 Reference< XAccessibleContext > pRContext = xAcc->getAccessibleContext();
144 if(!pRContext.is())
145 return sal_False;
146 Reference<XAccessibleStateSet> pRStateSet = pRContext->getAccessibleStateSet();
147 if( pRStateSet.is() )
148 {
149 Sequence<short> pStates = pRStateSet->getStates();
150 long count = pStates.getLength();
151 for( int i = 0; i < count; i++ )
152 {
153 if( pStates[i] == AccessibleStateType::SELECTED)
154 return sal_True;
155 }
156 }
157 }
158 return sal_False;
159 }
160
isAccessibleChildSelected(sal_Int32 nChildIndex)161 sal_Bool SwAccessibleSelectionHelper::isAccessibleChildSelected(
162 sal_Int32 nChildIndex )
163 throw ( lang::IndexOutOfBoundsException,
164 RuntimeException )
165 {
166 vos::OGuard aGuard(Application::GetSolarMutex());
167
168 // Get the respective child as SwFrm (also do index checking), ...
169 const SwAccessibleChild aChild = rContext.GetChild( *(rContext.GetMap()),
170 nChildIndex );
171 if( !aChild.IsValid() )
172 throwIndexOutOfBoundsException();
173
174 // ... and compare to the currently selected frame
175 sal_Bool bRet = sal_False;
176 SwFEShell* pFEShell = GetFEShell();
177 if( pFEShell )
178 {
179 if ( aChild.GetSwFrm() != 0 )
180 {
181 bRet = (pFEShell->GetCurrFlyFrm() == aChild.GetSwFrm());
182 }
183 else if ( aChild.GetDrawObject() )
184 {
185 bRet = pFEShell->IsObjSelected( *aChild.GetDrawObject() );
186 }
187 //If the SwFrmOrObj is not selected directly in the UI, we should check whether it is selected in the selection cursor.
188 if( !bRet )
189 {
190 if( lcl_getSelectedState( aChild, &rContext, rContext.GetMap() ) == sal_True)
191 bRet = sal_True;
192 }
193 }
194
195 return bRet;
196 }
197
clearAccessibleSelection()198 void SwAccessibleSelectionHelper::clearAccessibleSelection( )
199 throw ( RuntimeException )
200 {
201 // return sal_False // we can't deselect
202 }
203
selectAllAccessibleChildren()204 void SwAccessibleSelectionHelper::selectAllAccessibleChildren( )
205 throw ( RuntimeException )
206 {
207 vos::OGuard aGuard(Application::GetSolarMutex());
208
209 // We can select only one. So iterate over the children to find
210 // the first we can select, and select it.
211
212 SwFEShell* pFEShell = GetFEShell();
213 if( pFEShell )
214 {
215 ::std::list< SwAccessibleChild > aChildren;
216 rContext.GetChildren( *(rContext.GetMap()), aChildren );
217
218 ::std::list< SwAccessibleChild >::const_iterator aIter = aChildren.begin();
219 ::std::list< SwAccessibleChild >::const_iterator aEndIter = aChildren.end();
220 while( aIter != aEndIter )
221 {
222 const SwAccessibleChild& rChild = *aIter;
223 const SdrObject* pObj = rChild.GetDrawObject();
224 const SwFrm* pFrm = rChild.GetSwFrm();
225 if( pObj && !(pFrm != 0 && pFEShell->IsObjSelected()) )
226 {
227 rContext.Select( const_cast< SdrObject *>( pObj ), 0==pFrm );
228 if( pFrm )
229 break;
230 }
231 ++aIter;
232 }
233 }
234 }
235
getSelectedAccessibleChildCount()236 sal_Int32 SwAccessibleSelectionHelper::getSelectedAccessibleChildCount( )
237 throw ( RuntimeException )
238 {
239 vos::OGuard aGuard(Application::GetSolarMutex());
240
241 sal_Int32 nCount = 0;
242 // Only one frame can be selected at a time, and we only frames
243 // for selectable children.
244 SwFEShell* pFEShell = GetFEShell();
245 if( pFEShell != 0 )
246 {
247 const SwFlyFrm* pFlyFrm = pFEShell->GetCurrFlyFrm();
248 if( pFlyFrm )
249 {
250 //if( rContext.GetParent( SwAccessibleChild(pFlyFrm), rContext.IsInPagePreview()) ==
251 // rContext.GetFrm() )
252 nCount = 1;
253 }
254 else
255 {
256 sal_uInt16 nSelObjs = pFEShell->IsObjSelected();
257 if( nSelObjs > 0 )
258 {
259 ::std::list< SwAccessibleChild > aChildren;
260 rContext.GetChildren( *(rContext.GetMap()), aChildren );
261
262 ::std::list< SwAccessibleChild >::const_iterator aIter =
263 aChildren.begin();
264 ::std::list< SwAccessibleChild >::const_iterator aEndIter =
265 aChildren.end();
266 while( aIter != aEndIter && nCount < nSelObjs )
267 {
268 const SwAccessibleChild& rChild = *aIter;
269 if( rChild.GetDrawObject() && !rChild.GetSwFrm() &&
270 rContext.GetParent(rChild, rContext.IsInPagePreview())
271 == rContext.GetFrm() &&
272 pFEShell->IsObjSelected( *rChild.GetDrawObject() ) )
273 {
274 nCount++;
275 }
276 ++aIter;
277 }
278 }
279 }
280 //If the SwFrmOrObj is not selected directly in the UI,
281 //we should check whether it is selected in the selection cursor.
282 if( nCount == 0 )
283 {
284 ::std::list< SwAccessibleChild > aChildren;
285 rContext.GetChildren( *(rContext.GetMap()), aChildren );
286 ::std::list< SwAccessibleChild >::const_iterator aIter =
287 aChildren.begin();
288 ::std::list< SwAccessibleChild >::const_iterator aEndIter =
289 aChildren.end();
290 while( aIter != aEndIter )
291 {
292 const SwAccessibleChild& aChild = *aIter;
293 if( lcl_getSelectedState( aChild, &rContext, rContext.GetMap() ) )
294 nCount++;
295 ++aIter;
296 }
297 }
298 }
299 return nCount;
300 }
301
getSelectedAccessibleChild(sal_Int32 nSelectedChildIndex)302 Reference<XAccessible> SwAccessibleSelectionHelper::getSelectedAccessibleChild(
303 sal_Int32 nSelectedChildIndex )
304 throw ( lang::IndexOutOfBoundsException,
305 RuntimeException)
306 {
307 vos::OGuard aGuard(Application::GetSolarMutex());
308
309 // Since the index is relative to the selected children, and since
310 // there can be at most one selected frame child, the index must
311 // be 0, and a selection must exist, otherwise we have to throw an
312 // lang::IndexOutOfBoundsException
313 SwFEShell* pFEShell = GetFEShell();
314 if( 0 == pFEShell )
315 throwIndexOutOfBoundsException();
316
317 SwAccessibleChild aChild;
318 const SwFlyFrm *pFlyFrm = pFEShell->GetCurrFlyFrm();
319 if( pFlyFrm )
320 {
321 if( 0 == nSelectedChildIndex )
322 {
323 if(rContext.GetParent( SwAccessibleChild(pFlyFrm), rContext.IsInPagePreview()) == rContext.GetFrm() )
324 {
325 aChild = pFlyFrm;
326 }
327 else
328 {
329 const SwFrmFmt *pFrmFmt = pFlyFrm->GetFmt();
330 if (pFrmFmt)
331 {
332 const SwFmtAnchor& pAnchor = pFrmFmt->GetAnchor();
333 if( pAnchor.GetAnchorId() == FLY_AS_CHAR )
334 {
335 const SwFrm *pParaFrm = rContext.GetParent( SwAccessibleChild(pFlyFrm), rContext.IsInPagePreview() );
336 aChild = pParaFrm;
337 }
338 }
339 }
340 }
341 }
342 else
343 {
344 sal_uInt16 nSelObjs = pFEShell->IsObjSelected();
345 if( 0 == nSelObjs || nSelectedChildIndex >= nSelObjs )
346 throwIndexOutOfBoundsException();
347
348 ::std::list< SwAccessibleChild > aChildren;
349 rContext.GetChildren( *(rContext.GetMap()), aChildren );
350
351 ::std::list< SwAccessibleChild >::const_iterator aIter = aChildren.begin();
352 ::std::list< SwAccessibleChild >::const_iterator aEndIter = aChildren.end();
353 while( aIter != aEndIter && !aChild.IsValid() )
354 {
355 const SwAccessibleChild& rChild = *aIter;
356 if( rChild.GetDrawObject() && !rChild.GetSwFrm() &&
357 rContext.GetParent(rChild, rContext.IsInPagePreview()) ==
358 rContext.GetFrm() &&
359 pFEShell->IsObjSelected( *rChild.GetDrawObject() ) )
360 {
361 if( 0 == nSelectedChildIndex )
362 aChild = rChild;
363 else
364 --nSelectedChildIndex;
365 }
366 ++aIter;
367 }
368 }
369
370 if( !aChild.IsValid() )
371 throwIndexOutOfBoundsException();
372
373 DBG_ASSERT( rContext.GetMap() != NULL, "We need the map." );
374 Reference< XAccessible > xChild;
375 if( aChild.GetSwFrm() )
376 {
377 ::vos::ORef < SwAccessibleContext > xChildImpl(
378 rContext.GetMap()->GetContextImpl( aChild.GetSwFrm(),
379 sal_True ) );
380 if( xChildImpl.isValid() )
381 {
382 xChildImpl->SetParent( &rContext );
383 xChild = xChildImpl.getBodyPtr();
384 }
385 }
386 else if ( aChild.GetDrawObject() )
387 {
388 ::vos::ORef < ::accessibility::AccessibleShape > xChildImpl(
389 rContext.GetMap()->GetContextImpl( aChild.GetDrawObject(),
390 &rContext, sal_True ) );
391 if( xChildImpl.isValid() )
392 xChild = xChildImpl.getBodyPtr();
393 }
394 return xChild;
395 }
396
397 // --> OD 2004-11-16 #111714# - index has to be treated as global child index.
deselectAccessibleChild(sal_Int32 nChildIndex)398 void SwAccessibleSelectionHelper::deselectAccessibleChild(
399 sal_Int32 nChildIndex )
400 throw ( lang::IndexOutOfBoundsException,
401 RuntimeException )
402 {
403 // return sal_False // we can't deselect
404 if( nChildIndex < 0 ||
405 nChildIndex >= rContext.GetChildCount( *(rContext.GetMap()) ) )
406 throwIndexOutOfBoundsException();
407 }
408