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