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