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