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 using namespace ::com::sun::star;
42 using namespace ::com::sun::star::uno;
43 
44 using ::com::sun::star::accessibility::XAccessible;
45 using ::com::sun::star::accessibility::XAccessibleContext;
46 using ::com::sun::star::accessibility::XAccessibleSelection;
47 
48 using namespace ::sw::access;
49 
50 SwAccessibleSelectionHelper::SwAccessibleSelectionHelper(
51     SwAccessibleContext& rCtxt ) :
52         rContext( rCtxt )
53 {
54 }
55 
56 SwAccessibleSelectionHelper::~SwAccessibleSelectionHelper()
57 {
58 }
59 
60 SwFEShell* SwAccessibleSelectionHelper::GetFEShell()
61 {
62     DBG_ASSERT( rContext.GetMap() != NULL, "no map?" );
63     ViewShell* pViewShell = rContext.GetMap()->GetShell();
64     DBG_ASSERT( pViewShell != NULL,
65                 "No view shell? Then what are you looking at?" );
66 
67     SwFEShell* pFEShell = NULL;
68     if( pViewShell->ISA( SwFEShell ) )
69     {
70         pFEShell = static_cast<SwFEShell*>( pViewShell );
71     }
72 
73     return pFEShell;
74 }
75 
76 void SwAccessibleSelectionHelper::throwIndexOutOfBoundsException()
77         throw ( lang::IndexOutOfBoundsException )
78 {
79 	Reference < XAccessibleContext > xThis( &rContext );
80 	Reference < XAccessibleSelection >xSelThis( xThis, UNO_QUERY );
81     lang::IndexOutOfBoundsException aExcept(
82 				::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("index out of bounds") ),
83 				xSelThis );										\
84 	throw aExcept;
85 }
86 
87 
88 //=====  XAccessibleSelection  ============================================
89 
90 void SwAccessibleSelectionHelper::selectAccessibleChild(
91     sal_Int32 nChildIndex )
92     throw ( lang::IndexOutOfBoundsException,
93             RuntimeException )
94 {
95 	vos::OGuard aGuard(Application::GetSolarMutex());
96 
97     // Get the respective child as SwFrm (also do index checking), ...
98     const SwAccessibleChild aChild = rContext.GetChild( *(rContext.GetMap()),
99                                                         nChildIndex );
100 	if( !aChild.IsValid() )
101 		throwIndexOutOfBoundsException();
102 
103     // we can only select fly frames, so we ignore (should: return
104     // false) all other attempts at child selection
105     sal_Bool bRet = sal_False;
106     SwFEShell* pFEShell = GetFEShell();
107     if( pFEShell != NULL )
108 	{
109         const SdrObject *pObj = aChild.GetDrawObject();
110 		if( pObj )
111 		{
112 			bRet = rContext.Select( const_cast< SdrObject *>( pObj ), 0==aChild.GetSwFrm());
113 		}
114 	}
115     // no frame shell, or no frame, or no fly frame -> can't select
116 
117     // return bRet;
118 }
119 
120 sal_Bool SwAccessibleSelectionHelper::isAccessibleChildSelected(
121     sal_Int32 nChildIndex )
122     throw ( lang::IndexOutOfBoundsException,
123             RuntimeException )
124 {
125 	vos::OGuard aGuard(Application::GetSolarMutex());
126 
127     // Get the respective child as SwFrm (also do index checking), ...
128     const SwAccessibleChild aChild = rContext.GetChild( *(rContext.GetMap()),
129                                                         nChildIndex );
130 	if( !aChild.IsValid() )
131 		throwIndexOutOfBoundsException();
132 
133     // ... and compare to the currently selected frame
134 	sal_Bool bRet = sal_False;
135 	SwFEShell* pFEShell = GetFEShell();
136 	if( pFEShell )
137 	{
138         if ( aChild.GetSwFrm() != 0 )
139 		{
140 			bRet = (pFEShell->GetCurrFlyFrm() == aChild.GetSwFrm());
141 		}
142         else if ( aChild.GetDrawObject() )
143 		{
144             bRet = pFEShell->IsObjSelected( *aChild.GetDrawObject() );
145 		}
146 	}
147 
148 	return bRet;
149 }
150 
151 void SwAccessibleSelectionHelper::clearAccessibleSelection(  )
152     throw ( RuntimeException )
153 {
154     // return sal_False     // we can't deselect
155 }
156 
157 void SwAccessibleSelectionHelper::selectAllAccessibleChildren(  )
158     throw ( RuntimeException )
159 {
160 	vos::OGuard aGuard(Application::GetSolarMutex());
161 
162     // We can select only one. So iterate over the children to find
163     // the first we can select, and select it.
164 
165 	SwFEShell* pFEShell = GetFEShell();
166 	if( pFEShell )
167 	{
168         ::std::list< SwAccessibleChild > aChildren;
169         rContext.GetChildren( *(rContext.GetMap()), aChildren );
170 
171         ::std::list< SwAccessibleChild >::const_iterator aIter = aChildren.begin();
172         ::std::list< SwAccessibleChild >::const_iterator aEndIter = aChildren.end();
173 		while( aIter != aEndIter )
174 		{
175             const SwAccessibleChild& rChild = *aIter;
176             const SdrObject* pObj = rChild.GetDrawObject();
177 			const SwFrm* pFrm = rChild.GetSwFrm();
178 			if( pObj && !(pFrm != 0 && pFEShell->IsObjSelected()) )
179 			{
180 				rContext.Select( const_cast< SdrObject *>( pObj ), 0==pFrm );
181 				if( pFrm )
182 					break;
183 			}
184 			++aIter;
185 		}
186     }
187 }
188 
189 sal_Int32 SwAccessibleSelectionHelper::getSelectedAccessibleChildCount(  )
190     throw ( RuntimeException )
191 {
192 	vos::OGuard aGuard(Application::GetSolarMutex());
193 
194 	sal_Int32 nCount = 0;
195     // Only one frame can be selected at a time, and we only frames
196     // for selectable children.
197 	SwFEShell* pFEShell = GetFEShell();
198 	if( pFEShell != 0 )
199 	{
200         const SwFlyFrm* pFlyFrm = pFEShell->GetCurrFlyFrm();
201 		if( pFlyFrm )
202 		{
203             if( rContext.GetParent( SwAccessibleChild(pFlyFrm), rContext.IsInPagePreview()) ==
204                     rContext.GetFrm() )
205             {
206 				nCount = 1;
207             }
208 		}
209 		else
210 		{
211 			sal_uInt16 nSelObjs = pFEShell->IsObjSelected();
212 			if( nSelObjs > 0 )
213 			{
214                 ::std::list< SwAccessibleChild > aChildren;
215                 rContext.GetChildren( *(rContext.GetMap()), aChildren );
216 
217                 ::std::list< SwAccessibleChild >::const_iterator aIter =
218 					aChildren.begin();
219                 ::std::list< SwAccessibleChild >::const_iterator aEndIter =
220 					aChildren.end();
221 				while( aIter != aEndIter && nCount < nSelObjs )
222 				{
223                     const SwAccessibleChild& rChild = *aIter;
224                     if( rChild.GetDrawObject() && !rChild.GetSwFrm() &&
225 					    rContext.GetParent(rChild, rContext.IsInPagePreview())
226                            == rContext.GetFrm() &&
227                         pFEShell->IsObjSelected( *rChild.GetDrawObject() ) )
228 					{
229 						nCount++;
230 					}
231 					++aIter;
232 				}
233 			}
234 		}
235 	}
236     return nCount;
237 }
238 
239 Reference<XAccessible> SwAccessibleSelectionHelper::getSelectedAccessibleChild(
240     sal_Int32 nSelectedChildIndex )
241     throw ( lang::IndexOutOfBoundsException,
242             RuntimeException)
243 {
244 	vos::OGuard aGuard(Application::GetSolarMutex());
245 
246     // Since the index is relative to the selected children, and since
247     // there can be at most one selected frame child, the index must
248     // be 0, and a selection must exist, otherwise we have to throw an
249     // lang::IndexOutOfBoundsException
250 	SwFEShell* pFEShell = GetFEShell();
251 	if( 0 == pFEShell )
252 		throwIndexOutOfBoundsException();
253 
254     SwAccessibleChild aChild;
255 	const SwFlyFrm *pFlyFrm = pFEShell->GetCurrFlyFrm();
256 	if( pFlyFrm )
257 	{
258 		if( 0 == nSelectedChildIndex &&
259             rContext.GetParent( SwAccessibleChild(pFlyFrm), rContext.IsInPagePreview()) ==
260                 rContext.GetFrm() )
261         {
262         	aChild = pFlyFrm;
263         }
264 	}
265 	else
266 	{
267 		sal_uInt16 nSelObjs = pFEShell->IsObjSelected();
268 		if( 0 == nSelObjs || nSelectedChildIndex >= nSelObjs )
269 			throwIndexOutOfBoundsException();
270 
271         ::std::list< SwAccessibleChild > aChildren;
272         rContext.GetChildren( *(rContext.GetMap()), aChildren );
273 
274         ::std::list< SwAccessibleChild >::const_iterator aIter = aChildren.begin();
275         ::std::list< SwAccessibleChild >::const_iterator aEndIter = aChildren.end();
276 		while( aIter != aEndIter && !aChild.IsValid() )
277 		{
278             const SwAccessibleChild& rChild = *aIter;
279             if( rChild.GetDrawObject() && !rChild.GetSwFrm() &&
280 				rContext.GetParent(rChild, rContext.IsInPagePreview()) ==
281                     rContext.GetFrm() &&
282                 pFEShell->IsObjSelected( *rChild.GetDrawObject() ) )
283 			{
284 				if( 0 == nSelectedChildIndex )
285 					aChild = rChild;
286 				else
287 					--nSelectedChildIndex;
288 			}
289 			++aIter;
290 		}
291 	}
292 
293 	if( !aChild.IsValid() )
294 		throwIndexOutOfBoundsException();
295 
296     DBG_ASSERT( rContext.GetMap() != NULL, "We need the map." );
297 	Reference< XAccessible > xChild;
298 	if( aChild.GetSwFrm() )
299 	{
300 		::vos::ORef < SwAccessibleContext > xChildImpl(
301 				rContext.GetMap()->GetContextImpl( aChild.GetSwFrm(),
302 				sal_True ) );
303 		if( xChildImpl.isValid() )
304 		{
305 			xChildImpl->SetParent( &rContext );
306 			xChild = xChildImpl.getBodyPtr();
307 		}
308 	}
309     else if ( aChild.GetDrawObject() )
310 	{
311 		::vos::ORef < ::accessibility::AccessibleShape > xChildImpl(
312                 rContext.GetMap()->GetContextImpl( aChild.GetDrawObject(),
313 										  &rContext, sal_True )  );
314 		if( xChildImpl.isValid() )
315 			xChild = xChildImpl.getBodyPtr();
316 	}
317     return xChild;
318 }
319 
320 // --> OD 2004-11-16 #111714# - index has to be treated as global child index.
321 void SwAccessibleSelectionHelper::deselectAccessibleChild(
322     sal_Int32 nChildIndex )
323     throw ( lang::IndexOutOfBoundsException,
324             RuntimeException )
325 {
326     // return sal_False     // we can't deselect
327     if( nChildIndex < 0 ||
328         nChildIndex >= rContext.GetChildCount( *(rContext.GetMap()) ) )
329 		throwIndexOutOfBoundsException();
330 }
331