xref: /trunk/main/sw/source/core/access/accselectionhelper.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1  /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 
32 #include <com/sun/star/accessibility/XAccessibleSelection.hpp>
33 #include <accselectionhelper.hxx>
34 
35 #include <acccontext.hxx>
36 #include <accmap.hxx>
37 #include <svx/AccessibleShape.hxx>
38 #include <viewsh.hxx>
39 #include <fesh.hxx>
40 #include <vcl/svapp.hxx>        // for SolarMutex
41 #include <tools/debug.hxx>
42 #include <flyfrm.hxx>
43 
44 
45 using namespace ::com::sun::star;
46 using namespace ::com::sun::star::uno;
47 
48 using ::com::sun::star::accessibility::XAccessible;
49 using ::com::sun::star::accessibility::XAccessibleContext;
50 using ::com::sun::star::accessibility::XAccessibleSelection;
51 
52 using namespace ::sw::access;
53 
54 SwAccessibleSelectionHelper::SwAccessibleSelectionHelper(
55     SwAccessibleContext& rCtxt ) :
56         rContext( rCtxt )
57 {
58 }
59 
60 SwAccessibleSelectionHelper::~SwAccessibleSelectionHelper()
61 {
62 }
63 
64 SwFEShell* SwAccessibleSelectionHelper::GetFEShell()
65 {
66     DBG_ASSERT( rContext.GetMap() != NULL, "no map?" );
67     ViewShell* pViewShell = rContext.GetMap()->GetShell();
68     DBG_ASSERT( pViewShell != NULL,
69                 "No view shell? Then what are you looking at?" );
70 
71     SwFEShell* pFEShell = NULL;
72     if( pViewShell->ISA( SwFEShell ) )
73     {
74         pFEShell = static_cast<SwFEShell*>( pViewShell );
75     }
76 
77     return pFEShell;
78 }
79 
80 void SwAccessibleSelectionHelper::throwIndexOutOfBoundsException()
81         throw ( lang::IndexOutOfBoundsException )
82 {
83     Reference < XAccessibleContext > xThis( &rContext );
84     Reference < XAccessibleSelection >xSelThis( xThis, UNO_QUERY );
85     lang::IndexOutOfBoundsException aExcept(
86                 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("index out of bounds") ),
87                 xSelThis );                                     \
88     throw aExcept;
89 }
90 
91 
92 //=====  XAccessibleSelection  ============================================
93 
94 void SwAccessibleSelectionHelper::selectAccessibleChild(
95     sal_Int32 nChildIndex )
96     throw ( lang::IndexOutOfBoundsException,
97             RuntimeException )
98 {
99     vos::OGuard aGuard(Application::GetSolarMutex());
100 
101     // Get the respective child as SwFrm (also do index checking), ...
102     const SwAccessibleChild aChild = rContext.GetChild( *(rContext.GetMap()),
103                                                         nChildIndex );
104     if( !aChild.IsValid() )
105         throwIndexOutOfBoundsException();
106 
107     // we can only select fly frames, so we ignore (should: return
108     // false) all other attempts at child selection
109     sal_Bool bRet = sal_False;
110     SwFEShell* pFEShell = GetFEShell();
111     if( pFEShell != NULL )
112     {
113         const SdrObject *pObj = aChild.GetDrawObject();
114         if( pObj )
115         {
116             bRet = rContext.Select( const_cast< SdrObject *>( pObj ), 0==aChild.GetSwFrm());
117         }
118     }
119     // no frame shell, or no frame, or no fly frame -> can't select
120 
121     // return bRet;
122 }
123 
124 sal_Bool SwAccessibleSelectionHelper::isAccessibleChildSelected(
125     sal_Int32 nChildIndex )
126     throw ( lang::IndexOutOfBoundsException,
127             RuntimeException )
128 {
129     vos::OGuard aGuard(Application::GetSolarMutex());
130 
131     // Get the respective child as SwFrm (also do index checking), ...
132     const SwAccessibleChild aChild = rContext.GetChild( *(rContext.GetMap()),
133                                                         nChildIndex );
134     if( !aChild.IsValid() )
135         throwIndexOutOfBoundsException();
136 
137     // ... and compare to the currently selected frame
138     sal_Bool bRet = sal_False;
139     SwFEShell* pFEShell = GetFEShell();
140     if( pFEShell )
141     {
142         if ( aChild.GetSwFrm() != 0 )
143         {
144             bRet = (pFEShell->GetCurrFlyFrm() == aChild.GetSwFrm());
145         }
146         else if ( aChild.GetDrawObject() )
147         {
148             bRet = pFEShell->IsObjSelected( *aChild.GetDrawObject() );
149         }
150     }
151 
152     return bRet;
153 }
154 
155 void SwAccessibleSelectionHelper::clearAccessibleSelection(  )
156     throw ( RuntimeException )
157 {
158     // return sal_False     // we can't deselect
159 }
160 
161 void SwAccessibleSelectionHelper::selectAllAccessibleChildren(  )
162     throw ( RuntimeException )
163 {
164     vos::OGuard aGuard(Application::GetSolarMutex());
165 
166     // We can select only one. So iterate over the children to find
167     // the first we can select, and select it.
168 
169     SwFEShell* pFEShell = GetFEShell();
170     if( pFEShell )
171     {
172         ::std::list< SwAccessibleChild > aChildren;
173         rContext.GetChildren( *(rContext.GetMap()), aChildren );
174 
175         ::std::list< SwAccessibleChild >::const_iterator aIter = aChildren.begin();
176         ::std::list< SwAccessibleChild >::const_iterator aEndIter = aChildren.end();
177         while( aIter != aEndIter )
178         {
179             const SwAccessibleChild& rChild = *aIter;
180             const SdrObject* pObj = rChild.GetDrawObject();
181             const SwFrm* pFrm = rChild.GetSwFrm();
182             if( pObj && !(pFrm != 0 && pFEShell->IsObjSelected()) )
183             {
184                 rContext.Select( const_cast< SdrObject *>( pObj ), 0==pFrm );
185                 if( pFrm )
186                     break;
187             }
188             ++aIter;
189         }
190     }
191 }
192 
193 sal_Int32 SwAccessibleSelectionHelper::getSelectedAccessibleChildCount(  )
194     throw ( RuntimeException )
195 {
196     vos::OGuard aGuard(Application::GetSolarMutex());
197 
198     sal_Int32 nCount = 0;
199     // Only one frame can be selected at a time, and we only frames
200     // for selectable children.
201     SwFEShell* pFEShell = GetFEShell();
202     if( pFEShell != 0 )
203     {
204         const SwFlyFrm* pFlyFrm = pFEShell->GetCurrFlyFrm();
205         if( pFlyFrm )
206         {
207             if( rContext.GetParent( SwAccessibleChild(pFlyFrm), rContext.IsInPagePreview()) ==
208                     rContext.GetFrm() )
209             {
210                 nCount = 1;
211             }
212         }
213         else
214         {
215             sal_uInt16 nSelObjs = pFEShell->IsObjSelected();
216             if( nSelObjs > 0 )
217             {
218                 ::std::list< SwAccessibleChild > aChildren;
219                 rContext.GetChildren( *(rContext.GetMap()), aChildren );
220 
221                 ::std::list< SwAccessibleChild >::const_iterator aIter =
222                     aChildren.begin();
223                 ::std::list< SwAccessibleChild >::const_iterator aEndIter =
224                     aChildren.end();
225                 while( aIter != aEndIter && nCount < nSelObjs )
226                 {
227                     const SwAccessibleChild& rChild = *aIter;
228                     if( rChild.GetDrawObject() && !rChild.GetSwFrm() &&
229                         rContext.GetParent(rChild, rContext.IsInPagePreview())
230                            == rContext.GetFrm() &&
231                         pFEShell->IsObjSelected( *rChild.GetDrawObject() ) )
232                     {
233                         nCount++;
234                     }
235                     ++aIter;
236                 }
237             }
238         }
239     }
240     return nCount;
241 }
242 
243 Reference<XAccessible> SwAccessibleSelectionHelper::getSelectedAccessibleChild(
244     sal_Int32 nSelectedChildIndex )
245     throw ( lang::IndexOutOfBoundsException,
246             RuntimeException)
247 {
248     vos::OGuard aGuard(Application::GetSolarMutex());
249 
250     // Since the index is relative to the selected children, and since
251     // there can be at most one selected frame child, the index must
252     // be 0, and a selection must exist, otherwise we have to throw an
253     // lang::IndexOutOfBoundsException
254     SwFEShell* pFEShell = GetFEShell();
255     if( 0 == pFEShell )
256         throwIndexOutOfBoundsException();
257 
258     SwAccessibleChild aChild;
259     const SwFlyFrm *pFlyFrm = pFEShell->GetCurrFlyFrm();
260     if( pFlyFrm )
261     {
262         if( 0 == nSelectedChildIndex &&
263             rContext.GetParent( SwAccessibleChild(pFlyFrm), rContext.IsInPagePreview()) ==
264                 rContext.GetFrm() )
265         {
266             aChild = pFlyFrm;
267         }
268     }
269     else
270     {
271         sal_uInt16 nSelObjs = pFEShell->IsObjSelected();
272         if( 0 == nSelObjs || nSelectedChildIndex >= nSelObjs )
273             throwIndexOutOfBoundsException();
274 
275         ::std::list< SwAccessibleChild > aChildren;
276         rContext.GetChildren( *(rContext.GetMap()), aChildren );
277 
278         ::std::list< SwAccessibleChild >::const_iterator aIter = aChildren.begin();
279         ::std::list< SwAccessibleChild >::const_iterator aEndIter = aChildren.end();
280         while( aIter != aEndIter && !aChild.IsValid() )
281         {
282             const SwAccessibleChild& rChild = *aIter;
283             if( rChild.GetDrawObject() && !rChild.GetSwFrm() &&
284                 rContext.GetParent(rChild, rContext.IsInPagePreview()) ==
285                     rContext.GetFrm() &&
286                 pFEShell->IsObjSelected( *rChild.GetDrawObject() ) )
287             {
288                 if( 0 == nSelectedChildIndex )
289                     aChild = rChild;
290                 else
291                     --nSelectedChildIndex;
292             }
293             ++aIter;
294         }
295     }
296 
297     if( !aChild.IsValid() )
298         throwIndexOutOfBoundsException();
299 
300     DBG_ASSERT( rContext.GetMap() != NULL, "We need the map." );
301     Reference< XAccessible > xChild;
302     if( aChild.GetSwFrm() )
303     {
304         ::vos::ORef < SwAccessibleContext > xChildImpl(
305                 rContext.GetMap()->GetContextImpl( aChild.GetSwFrm(),
306                 sal_True ) );
307         if( xChildImpl.isValid() )
308         {
309             xChildImpl->SetParent( &rContext );
310             xChild = xChildImpl.getBodyPtr();
311         }
312     }
313     else if ( aChild.GetDrawObject() )
314     {
315         ::vos::ORef < ::accessibility::AccessibleShape > xChildImpl(
316                 rContext.GetMap()->GetContextImpl( aChild.GetDrawObject(),
317                                           &rContext, sal_True )  );
318         if( xChildImpl.isValid() )
319             xChild = xChildImpl.getBodyPtr();
320     }
321     return xChild;
322 }
323 
324 // --> OD 2004-11-16 #111714# - index has to be treated as global child index.
325 void SwAccessibleSelectionHelper::deselectAccessibleChild(
326     sal_Int32 nChildIndex )
327     throw ( lang::IndexOutOfBoundsException,
328             RuntimeException )
329 {
330     // return sal_False     // we can't deselect
331     if( nChildIndex < 0 ||
332         nChildIndex >= rContext.GetChildCount( *(rContext.GetMap()) ) )
333         throwIndexOutOfBoundsException();
334 }
335