Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <com/sun/star/accessibility/XAccessibleSelection.hpp>
21 : #include <accselectionhelper.hxx>
22 :
23 : #include <acccontext.hxx>
24 : #include <accmap.hxx>
25 : #include <svx/AccessibleShape.hxx>
26 : #include <viewsh.hxx>
27 : #include <fesh.hxx>
28 : #include <vcl/svapp.hxx>
29 : #include <flyfrm.hxx>
30 :
31 : #include <com/sun/star/uno/Reference.hxx>
32 : #include <com/sun/star/accessibility/AccessibleStateType.hpp>
33 : #include <com/sun/star/accessibility/XAccessibleStateSet.hpp>
34 : #include <fmtanchr.hxx>
35 :
36 : using namespace ::com::sun::star::accessibility;
37 : using namespace ::com::sun::star;
38 : using namespace ::com::sun::star::uno;
39 :
40 : using ::com::sun::star::accessibility::XAccessible;
41 : using ::com::sun::star::accessibility::XAccessibleContext;
42 : using ::com::sun::star::accessibility::XAccessibleSelection;
43 :
44 : using namespace ::sw::access;
45 :
46 93 : SwAccessibleSelectionHelper::SwAccessibleSelectionHelper(
47 : SwAccessibleContext& rContext ) :
48 93 : m_rContext( rContext )
49 : {
50 93 : }
51 :
52 93 : SwAccessibleSelectionHelper::~SwAccessibleSelectionHelper()
53 : {
54 93 : }
55 :
56 21 : SwFEShell* SwAccessibleSelectionHelper::GetFEShell()
57 : {
58 : OSL_ENSURE( m_rContext.GetMap() != NULL, "no map?" );
59 21 : SwViewShell* pViewShell = m_rContext.GetMap()->GetShell();
60 : OSL_ENSURE( pViewShell != NULL,
61 : "No view shell? Then what are you looking at?" );
62 :
63 21 : SwFEShell* pFEShell = NULL;
64 21 : if( pViewShell->ISA( SwFEShell ) )
65 : {
66 21 : pFEShell = static_cast<SwFEShell*>( pViewShell );
67 : }
68 :
69 21 : return pFEShell;
70 : }
71 :
72 16 : void SwAccessibleSelectionHelper::throwIndexOutOfBoundsException()
73 : throw ( lang::IndexOutOfBoundsException )
74 : {
75 16 : Reference < XAccessibleContext > xThis( &m_rContext );
76 32 : Reference < XAccessibleSelection >xSelThis( xThis, UNO_QUERY );
77 : lang::IndexOutOfBoundsException aExcept(
78 : OUString( "index out of bounds" ),
79 32 : xSelThis ); \
80 32 : throw aExcept;
81 : }
82 :
83 : // XAccessibleSelection
84 4 : void SwAccessibleSelectionHelper::selectAccessibleChild(
85 : sal_Int32 nChildIndex )
86 : throw ( lang::IndexOutOfBoundsException,
87 : RuntimeException )
88 : {
89 4 : SolarMutexGuard aGuard;
90 :
91 : // Get the respective child as SwFrm (also do index checking), ...
92 4 : const SwAccessibleChild aChild = m_rContext.GetChild( *(m_rContext.GetMap()),
93 8 : nChildIndex );
94 4 : if( !aChild.IsValid() )
95 4 : throwIndexOutOfBoundsException();
96 :
97 : // we can only select fly frames, so we ignore (should: return
98 : // false) all other attempts at child selection
99 0 : SwFEShell* pFEShell = GetFEShell();
100 0 : if( pFEShell != NULL )
101 : {
102 0 : const SdrObject *pObj = aChild.GetDrawObject();
103 0 : if( pObj )
104 0 : m_rContext.Select( const_cast< SdrObject *>( pObj ), 0==aChild.GetSwFrm());
105 4 : }
106 : // no frame shell, or no frame, or no fly frame -> can't select
107 0 : }
108 :
109 : //When the selected state of the SwFrmOrObj is setted, return true.
110 6 : static bool lcl_getSelectedState(const SwAccessibleChild& aChild,
111 : SwAccessibleContext* pContext,
112 : SwAccessibleMap* pMap)
113 : {
114 6 : Reference< XAccessible > xAcc;
115 6 : if ( aChild.GetSwFrm() )
116 : {
117 6 : xAcc = pMap->GetContext( aChild.GetSwFrm(), false );
118 : }
119 0 : else if ( aChild.GetDrawObject() )
120 : {
121 0 : xAcc = pMap->GetContext( aChild.GetDrawObject(), pContext, false );
122 : }
123 :
124 6 : if( xAcc.is() )
125 : {
126 6 : Reference< XAccessibleContext > pRContext = xAcc->getAccessibleContext();
127 6 : if(!pRContext.is())
128 0 : return false;
129 12 : Reference<XAccessibleStateSet> pRStateSet = pRContext->getAccessibleStateSet();
130 6 : if( pRStateSet.is() )
131 : {
132 6 : Sequence<short> pStates = pRStateSet->getStates();
133 6 : sal_Int32 count = pStates.getLength();
134 66 : for( sal_Int32 i = 0; i < count; i++ )
135 : {
136 60 : if( pStates[i] == AccessibleStateType::SELECTED)
137 0 : return true;
138 6 : }
139 6 : }
140 : }
141 6 : return false;
142 : }
143 :
144 5 : bool SwAccessibleSelectionHelper::isAccessibleChildSelected(
145 : sal_Int32 nChildIndex )
146 : throw ( lang::IndexOutOfBoundsException,
147 : RuntimeException )
148 : {
149 5 : SolarMutexGuard aGuard;
150 :
151 : // Get the respective child as SwFrm (also do index checking), ...
152 5 : const SwAccessibleChild aChild = m_rContext.GetChild( *(m_rContext.GetMap()),
153 10 : nChildIndex );
154 5 : if( !aChild.IsValid() )
155 4 : throwIndexOutOfBoundsException();
156 :
157 : // ... and compare to the currently selected frame
158 1 : bool bRet = false;
159 1 : SwFEShell* pFEShell = GetFEShell();
160 1 : if( pFEShell )
161 : {
162 1 : if ( aChild.GetSwFrm() != 0 )
163 : {
164 1 : bRet = (pFEShell->GetCurrFlyFrm() == aChild.GetSwFrm());
165 : }
166 0 : else if ( aChild.GetDrawObject() )
167 : {
168 0 : bRet = pFEShell->IsObjSelected( *aChild.GetDrawObject() );
169 : }
170 : //If the SwFrmOrObj is not selected directly in the UI, we should check whether it is selected in the selection cursor.
171 1 : if( !bRet )
172 : {
173 1 : if( lcl_getSelectedState( aChild, &m_rContext, m_rContext.GetMap() ) )
174 0 : bRet = true;
175 : }
176 : }
177 :
178 6 : return bRet;
179 : }
180 :
181 6 : void SwAccessibleSelectionHelper::selectAllAccessibleChildren( )
182 : throw ( RuntimeException )
183 : {
184 6 : SolarMutexGuard aGuard;
185 :
186 : // We can select only one. So iterate over the children to find
187 : // the first we can select, and select it.
188 :
189 6 : SwFEShell* pFEShell = GetFEShell();
190 6 : if( pFEShell )
191 : {
192 6 : ::std::list< SwAccessibleChild > aChildren;
193 6 : m_rContext.GetChildren( *(m_rContext.GetMap()), aChildren );
194 :
195 6 : ::std::list< SwAccessibleChild >::const_iterator aIter = aChildren.begin();
196 6 : ::std::list< SwAccessibleChild >::const_iterator aEndIter = aChildren.end();
197 15 : while( aIter != aEndIter )
198 : {
199 3 : const SwAccessibleChild& rChild = *aIter;
200 3 : const SdrObject* pObj = rChild.GetDrawObject();
201 3 : const SwFrm* pFrm = rChild.GetSwFrm();
202 3 : if( pObj && !(pFrm != 0 && pFEShell->IsObjSelected()) )
203 : {
204 0 : m_rContext.Select( const_cast< SdrObject *>( pObj ), 0==pFrm );
205 0 : if( pFrm )
206 0 : break;
207 : }
208 3 : ++aIter;
209 6 : }
210 6 : }
211 6 : }
212 :
213 10 : sal_Int32 SwAccessibleSelectionHelper::getSelectedAccessibleChildCount( )
214 : throw ( RuntimeException )
215 : {
216 10 : SolarMutexGuard aGuard;
217 :
218 10 : sal_Int32 nCount = 0;
219 : // Only one frame can be selected at a time, and we only frames
220 : // for selectable children.
221 10 : SwFEShell* pFEShell = GetFEShell();
222 10 : if( pFEShell != 0 )
223 : {
224 10 : const SwFlyFrm* pFlyFrm = pFEShell->GetCurrFlyFrm();
225 10 : if( pFlyFrm )
226 : {
227 0 : nCount = 1;
228 : }
229 : else
230 : {
231 10 : const size_t nSelObjs = pFEShell->IsObjSelected();
232 10 : if( nSelObjs > 0 )
233 : {
234 0 : ::std::list< SwAccessibleChild > aChildren;
235 0 : m_rContext.GetChildren( *(m_rContext.GetMap()), aChildren );
236 :
237 : ::std::list< SwAccessibleChild >::const_iterator aIter =
238 0 : aChildren.begin();
239 : ::std::list< SwAccessibleChild >::const_iterator aEndIter =
240 0 : aChildren.end();
241 0 : while( aIter != aEndIter && static_cast<size_t>(nCount) < nSelObjs )
242 : {
243 0 : const SwAccessibleChild& rChild = *aIter;
244 0 : if( rChild.GetDrawObject() && !rChild.GetSwFrm() &&
245 0 : SwAccessibleFrame::GetParent(rChild, m_rContext.IsInPagePreview())
246 0 : == m_rContext.GetFrm() &&
247 0 : pFEShell->IsObjSelected( *rChild.GetDrawObject() ) )
248 : {
249 0 : nCount++;
250 : }
251 0 : ++aIter;
252 0 : }
253 : }
254 : }
255 : //If the SwFrmOrObj is not selected directly in the UI,
256 : //we should check whether it is selected in the selection cursor.
257 10 : if( nCount == 0 )
258 : {
259 10 : ::std::list< SwAccessibleChild > aChildren;
260 10 : m_rContext.GetChildren( *(m_rContext.GetMap()), aChildren );
261 : ::std::list< SwAccessibleChild >::const_iterator aIter =
262 10 : aChildren.begin();
263 : ::std::list< SwAccessibleChild >::const_iterator aEndIter =
264 10 : aChildren.end();
265 25 : while( aIter != aEndIter )
266 : {
267 5 : const SwAccessibleChild& aChild = *aIter;
268 5 : if( lcl_getSelectedState( aChild, &m_rContext, m_rContext.GetMap() ) )
269 0 : nCount++;
270 5 : ++aIter;
271 10 : }
272 : }
273 : }
274 10 : return nCount;
275 : }
276 :
277 4 : Reference<XAccessible> SwAccessibleSelectionHelper::getSelectedAccessibleChild(
278 : sal_Int32 nSelectedChildIndex )
279 : throw ( lang::IndexOutOfBoundsException,
280 : RuntimeException)
281 : {
282 4 : SolarMutexGuard aGuard;
283 :
284 : // Since the index is relative to the selected children, and since
285 : // there can be at most one selected frame child, the index must
286 : // be 0, and a selection must exist, otherwise we have to throw an
287 : // lang::IndexOutOfBoundsException
288 4 : SwFEShell* pFEShell = GetFEShell();
289 4 : if( 0 == pFEShell )
290 0 : throwIndexOutOfBoundsException();
291 :
292 8 : SwAccessibleChild aChild;
293 4 : const SwFlyFrm *pFlyFrm = pFEShell->GetCurrFlyFrm();
294 4 : if( pFlyFrm )
295 : {
296 0 : if( 0 == nSelectedChildIndex )
297 : {
298 0 : if(SwAccessibleFrame::GetParent( SwAccessibleChild(pFlyFrm), m_rContext.IsInPagePreview()) == m_rContext.GetFrm() )
299 : {
300 0 : aChild = pFlyFrm;
301 : }
302 : else
303 : {
304 0 : const SwFrameFormat *pFrameFormat = pFlyFrm->GetFormat();
305 0 : if (pFrameFormat)
306 : {
307 0 : const SwFormatAnchor& pAnchor = pFrameFormat->GetAnchor();
308 0 : if( pAnchor.GetAnchorId() == FLY_AS_CHAR )
309 : {
310 0 : const SwFrm *pParaFrm = SwAccessibleFrame::GetParent( SwAccessibleChild(pFlyFrm), m_rContext.IsInPagePreview() );
311 0 : aChild = pParaFrm;
312 : }
313 : }
314 : }
315 : }
316 : }
317 : else
318 : {
319 4 : const size_t nSelObjs = pFEShell->IsObjSelected();
320 4 : if( 0 == nSelObjs || static_cast<size_t>(nSelectedChildIndex) >= nSelObjs )
321 4 : throwIndexOutOfBoundsException();
322 :
323 0 : ::std::list< SwAccessibleChild > aChildren;
324 0 : m_rContext.GetChildren( *(m_rContext.GetMap()), aChildren );
325 :
326 0 : ::std::list< SwAccessibleChild >::const_iterator aIter = aChildren.begin();
327 0 : ::std::list< SwAccessibleChild >::const_iterator aEndIter = aChildren.end();
328 0 : while( aIter != aEndIter && !aChild.IsValid() )
329 : {
330 0 : const SwAccessibleChild& rChild = *aIter;
331 0 : if( rChild.GetDrawObject() && !rChild.GetSwFrm() &&
332 0 : SwAccessibleFrame::GetParent(rChild, m_rContext.IsInPagePreview()) ==
333 0 : m_rContext.GetFrm() &&
334 0 : pFEShell->IsObjSelected( *rChild.GetDrawObject() ) )
335 : {
336 0 : if( 0 == nSelectedChildIndex )
337 0 : aChild = rChild;
338 : else
339 0 : --nSelectedChildIndex;
340 : }
341 0 : ++aIter;
342 0 : }
343 : }
344 :
345 0 : if( !aChild.IsValid() )
346 0 : throwIndexOutOfBoundsException();
347 :
348 : OSL_ENSURE( m_rContext.GetMap() != NULL, "We need the map." );
349 0 : Reference< XAccessible > xChild;
350 0 : if( aChild.GetSwFrm() )
351 : {
352 : ::rtl::Reference < SwAccessibleContext > xChildImpl(
353 : m_rContext.GetMap()->GetContextImpl( aChild.GetSwFrm(),
354 0 : true ) );
355 0 : if( xChildImpl.is() )
356 : {
357 0 : xChildImpl->SetParent( &m_rContext );
358 0 : xChild = xChildImpl.get();
359 0 : }
360 : }
361 0 : else if ( aChild.GetDrawObject() )
362 : {
363 : ::rtl::Reference < ::accessibility::AccessibleShape > xChildImpl(
364 : m_rContext.GetMap()->GetContextImpl( aChild.GetDrawObject(),
365 0 : &m_rContext, true ) );
366 0 : if( xChildImpl.is() )
367 0 : xChild = xChildImpl.get();
368 : }
369 4 : return xChild;
370 : }
371 :
372 : // index has to be treated as global child index.
373 4 : void SwAccessibleSelectionHelper::deselectAccessibleChild(
374 : sal_Int32 nChildIndex )
375 : throw ( lang::IndexOutOfBoundsException,
376 : RuntimeException )
377 : {
378 4 : SolarMutexGuard g;
379 :
380 6 : if( nChildIndex < 0 ||
381 2 : nChildIndex >= m_rContext.GetChildCount( *(m_rContext.GetMap()) ) )
382 8 : throwIndexOutOfBoundsException();
383 177 : }
384 :
385 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|