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 {
84 Reference < XAccessibleContext > xThis( &rContext );
85 Reference < XAccessibleSelection >xSelThis( xThis, UNO_QUERY );
86 lang::IndexOutOfBoundsException aExcept(
87 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("index out of bounds") ),
88 xSelThis ); \
89 throw aExcept;
90 }
91
92
93 //===== XAccessibleSelection ============================================
94
selectAccessibleChild(sal_Int32 nChildIndex)95 void SwAccessibleSelectionHelper::selectAccessibleChild(
96 sal_Int32 nChildIndex )
97 {
98 vos::OGuard aGuard(Application::GetSolarMutex());
99
100 // Get the respective child as SwFrm (also do index checking), ...
101 const SwAccessibleChild aChild = rContext.GetChild( *(rContext.GetMap()),
102 nChildIndex );
103 if( !aChild.IsValid() )
104 throwIndexOutOfBoundsException();
105
106 // we can only select fly frames, so we ignore (should: return
107 // false) all other attempts at child selection
108 sal_Bool bRet = sal_False;
109 SwFEShell* pFEShell = GetFEShell();
110 if( pFEShell != NULL )
111 {
112 const SdrObject *pObj = aChild.GetDrawObject();
113 if( pObj )
114 {
115 bRet = rContext.Select( const_cast< SdrObject *>( pObj ), 0==aChild.GetSwFrm());
116 }
117 }
118 // no frame shell, or no frame, or no fly frame -> can't select
119
120 // return bRet;
121 }
122
123 //When the selected state of the SwFrmOrObj is setted, return true.
lcl_getSelectedState(const SwAccessibleChild & aChild,SwAccessibleContext * pContext,SwAccessibleMap * pMap)124 static sal_Bool lcl_getSelectedState(const SwAccessibleChild& aChild,
125 SwAccessibleContext* pContext,
126 SwAccessibleMap* pMap)
127 {
128 Reference< XAccessible > xAcc;
129 if ( aChild.GetSwFrm() )
130 {
131 xAcc = pMap->GetContext( aChild.GetSwFrm(), sal_False );
132 }
133 else if ( aChild.GetDrawObject() )
134 {
135 xAcc = pMap->GetContext( aChild.GetDrawObject(), pContext, sal_False );
136 }
137
138 if( xAcc.is() )
139 {
140 Reference< XAccessibleContext > pRContext = xAcc->getAccessibleContext();
141 if(!pRContext.is())
142 return sal_False;
143 Reference<XAccessibleStateSet> pRStateSet = pRContext->getAccessibleStateSet();
144 if( pRStateSet.is() )
145 {
146 Sequence<short> pStates = pRStateSet->getStates();
147 long count = pStates.getLength();
148 for( int i = 0; i < count; i++ )
149 {
150 if( pStates[i] == AccessibleStateType::SELECTED)
151 return sal_True;
152 }
153 }
154 }
155 return sal_False;
156 }
157
isAccessibleChildSelected(sal_Int32 nChildIndex)158 sal_Bool SwAccessibleSelectionHelper::isAccessibleChildSelected(
159 sal_Int32 nChildIndex )
160 {
161 vos::OGuard aGuard(Application::GetSolarMutex());
162
163 // Get the respective child as SwFrm (also do index checking), ...
164 const SwAccessibleChild aChild = rContext.GetChild( *(rContext.GetMap()),
165 nChildIndex );
166 if( !aChild.IsValid() )
167 throwIndexOutOfBoundsException();
168
169 // ... and compare to the currently selected frame
170 sal_Bool bRet = sal_False;
171 SwFEShell* pFEShell = GetFEShell();
172 if( pFEShell )
173 {
174 if ( aChild.GetSwFrm() != 0 )
175 {
176 bRet = (pFEShell->GetCurrFlyFrm() == aChild.GetSwFrm());
177 }
178 else if ( aChild.GetDrawObject() )
179 {
180 bRet = pFEShell->IsObjSelected( *aChild.GetDrawObject() );
181 }
182 //If the SwFrmOrObj is not selected directly in the UI, we should check whether it is selected in the selection cursor.
183 if( !bRet )
184 {
185 if( lcl_getSelectedState( aChild, &rContext, rContext.GetMap() ) == sal_True)
186 bRet = sal_True;
187 }
188 }
189
190 return bRet;
191 }
192
clearAccessibleSelection()193 void SwAccessibleSelectionHelper::clearAccessibleSelection( )
194 {
195 // return sal_False // we can't deselect
196 }
197
selectAllAccessibleChildren()198 void SwAccessibleSelectionHelper::selectAllAccessibleChildren( )
199 {
200 vos::OGuard aGuard(Application::GetSolarMutex());
201
202 // We can select only one. So iterate over the children to find
203 // the first we can select, and select it.
204
205 SwFEShell* pFEShell = GetFEShell();
206 if( pFEShell )
207 {
208 ::std::list< SwAccessibleChild > aChildren;
209 rContext.GetChildren( *(rContext.GetMap()), aChildren );
210
211 ::std::list< SwAccessibleChild >::const_iterator aIter = aChildren.begin();
212 ::std::list< SwAccessibleChild >::const_iterator aEndIter = aChildren.end();
213 while( aIter != aEndIter )
214 {
215 const SwAccessibleChild& rChild = *aIter;
216 const SdrObject* pObj = rChild.GetDrawObject();
217 const SwFrm* pFrm = rChild.GetSwFrm();
218 if( pObj && !(pFrm != 0 && pFEShell->IsObjSelected()) )
219 {
220 rContext.Select( const_cast< SdrObject *>( pObj ), 0==pFrm );
221 if( pFrm )
222 break;
223 }
224 ++aIter;
225 }
226 }
227 }
228
getSelectedAccessibleChildCount()229 sal_Int32 SwAccessibleSelectionHelper::getSelectedAccessibleChildCount( )
230 {
231 vos::OGuard aGuard(Application::GetSolarMutex());
232
233 sal_Int32 nCount = 0;
234 // Only one frame can be selected at a time, and we only frames
235 // for selectable children.
236 SwFEShell* pFEShell = GetFEShell();
237 if( pFEShell != 0 )
238 {
239 const SwFlyFrm* pFlyFrm = pFEShell->GetCurrFlyFrm();
240 if( pFlyFrm )
241 {
242 //if( rContext.GetParent( SwAccessibleChild(pFlyFrm), rContext.IsInPagePreview()) ==
243 // rContext.GetFrm() )
244 nCount = 1;
245 }
246 else
247 {
248 sal_uInt16 nSelObjs = pFEShell->IsObjSelected();
249 if( nSelObjs > 0 )
250 {
251 ::std::list< SwAccessibleChild > aChildren;
252 rContext.GetChildren( *(rContext.GetMap()), aChildren );
253
254 ::std::list< SwAccessibleChild >::const_iterator aIter =
255 aChildren.begin();
256 ::std::list< SwAccessibleChild >::const_iterator aEndIter =
257 aChildren.end();
258 while( aIter != aEndIter && nCount < nSelObjs )
259 {
260 const SwAccessibleChild& rChild = *aIter;
261 if( rChild.GetDrawObject() && !rChild.GetSwFrm() &&
262 rContext.GetParent(rChild, rContext.IsInPagePreview())
263 == rContext.GetFrm() &&
264 pFEShell->IsObjSelected( *rChild.GetDrawObject() ) )
265 {
266 nCount++;
267 }
268 ++aIter;
269 }
270 }
271 }
272 //If the SwFrmOrObj is not selected directly in the UI,
273 //we should check whether it is selected in the selection cursor.
274 if( nCount == 0 )
275 {
276 ::std::list< SwAccessibleChild > aChildren;
277 rContext.GetChildren( *(rContext.GetMap()), aChildren );
278 ::std::list< SwAccessibleChild >::const_iterator aIter =
279 aChildren.begin();
280 ::std::list< SwAccessibleChild >::const_iterator aEndIter =
281 aChildren.end();
282 while( aIter != aEndIter )
283 {
284 const SwAccessibleChild& aChild = *aIter;
285 if( lcl_getSelectedState( aChild, &rContext, rContext.GetMap() ) )
286 nCount++;
287 ++aIter;
288 }
289 }
290 }
291 return nCount;
292 }
293
getSelectedAccessibleChild(sal_Int32 nSelectedChildIndex)294 Reference<XAccessible> SwAccessibleSelectionHelper::getSelectedAccessibleChild(
295 sal_Int32 nSelectedChildIndex )
296 {
297 vos::OGuard aGuard(Application::GetSolarMutex());
298
299 // Since the index is relative to the selected children, and since
300 // there can be at most one selected frame child, the index must
301 // be 0, and a selection must exist, otherwise we have to throw an
302 // lang::IndexOutOfBoundsException
303 SwFEShell* pFEShell = GetFEShell();
304 if( 0 == pFEShell )
305 throwIndexOutOfBoundsException();
306
307 SwAccessibleChild aChild;
308 const SwFlyFrm *pFlyFrm = pFEShell->GetCurrFlyFrm();
309 if( pFlyFrm )
310 {
311 if( 0 == nSelectedChildIndex )
312 {
313 if(rContext.GetParent( SwAccessibleChild(pFlyFrm), rContext.IsInPagePreview()) == rContext.GetFrm() )
314 {
315 aChild = pFlyFrm;
316 }
317 else
318 {
319 const SwFrmFmt *pFrmFmt = pFlyFrm->GetFmt();
320 if (pFrmFmt)
321 {
322 const SwFmtAnchor& pAnchor = pFrmFmt->GetAnchor();
323 if( pAnchor.GetAnchorId() == FLY_AS_CHAR )
324 {
325 const SwFrm *pParaFrm = rContext.GetParent( SwAccessibleChild(pFlyFrm), rContext.IsInPagePreview() );
326 aChild = pParaFrm;
327 }
328 }
329 }
330 }
331 }
332 else
333 {
334 sal_uInt16 nSelObjs = pFEShell->IsObjSelected();
335 if( 0 == nSelObjs || nSelectedChildIndex >= nSelObjs )
336 throwIndexOutOfBoundsException();
337
338 ::std::list< SwAccessibleChild > aChildren;
339 rContext.GetChildren( *(rContext.GetMap()), aChildren );
340
341 ::std::list< SwAccessibleChild >::const_iterator aIter = aChildren.begin();
342 ::std::list< SwAccessibleChild >::const_iterator aEndIter = aChildren.end();
343 while( aIter != aEndIter && !aChild.IsValid() )
344 {
345 const SwAccessibleChild& rChild = *aIter;
346 if( rChild.GetDrawObject() && !rChild.GetSwFrm() &&
347 rContext.GetParent(rChild, rContext.IsInPagePreview()) ==
348 rContext.GetFrm() &&
349 pFEShell->IsObjSelected( *rChild.GetDrawObject() ) )
350 {
351 if( 0 == nSelectedChildIndex )
352 aChild = rChild;
353 else
354 --nSelectedChildIndex;
355 }
356 ++aIter;
357 }
358 }
359
360 if( !aChild.IsValid() )
361 throwIndexOutOfBoundsException();
362
363 DBG_ASSERT( rContext.GetMap() != NULL, "We need the map." );
364 Reference< XAccessible > xChild;
365 if( aChild.GetSwFrm() )
366 {
367 ::vos::ORef < SwAccessibleContext > xChildImpl(
368 rContext.GetMap()->GetContextImpl( aChild.GetSwFrm(),
369 sal_True ) );
370 if( xChildImpl.isValid() )
371 {
372 xChildImpl->SetParent( &rContext );
373 xChild = xChildImpl.getBodyPtr();
374 }
375 }
376 else if ( aChild.GetDrawObject() )
377 {
378 ::vos::ORef < ::accessibility::AccessibleShape > xChildImpl(
379 rContext.GetMap()->GetContextImpl( aChild.GetDrawObject(),
380 &rContext, sal_True ) );
381 if( xChildImpl.isValid() )
382 xChild = xChildImpl.getBodyPtr();
383 }
384 return xChild;
385 }
386
387 // --> OD 2004-11-16 #111714# - index has to be treated as global child index.
deselectAccessibleChild(sal_Int32 nChildIndex)388 void SwAccessibleSelectionHelper::deselectAccessibleChild(
389 sal_Int32 nChildIndex )
390 {
391 // return sal_False // we can't deselect
392 if( nChildIndex < 0 ||
393 nChildIndex >= rContext.GetChildCount( *(rContext.GetMap()) ) )
394 throwIndexOutOfBoundsException();
395 }
396