xref: /trunk/main/sw/source/core/access/accselectionhelper.cxx (revision ca62e2c2083b5d0995f1245bad6c2edfb455fbec)
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