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 56 SwAccessibleSelectionHelper::SwAccessibleSelectionHelper( 57 SwAccessibleContext& rCtxt ) : 58 rContext( rCtxt ) 59 { 60 } 61 62 SwAccessibleSelectionHelper::~SwAccessibleSelectionHelper() 63 { 64 } 65 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 82 void SwAccessibleSelectionHelper::throwIndexOutOfBoundsException() 83 throw ( lang::IndexOutOfBoundsException ) 84 { 85 Reference < XAccessibleContext > xThis( &rContext ); 86 Reference < XAccessibleSelection >xSelThis( xThis, UNO_QUERY ); 87 lang::IndexOutOfBoundsException aExcept( 88 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("index out of bounds") ), 89 xSelThis ); \ 90 throw aExcept; 91 } 92 93 94 //===== XAccessibleSelection ============================================ 95 96 void SwAccessibleSelectionHelper::selectAccessibleChild( 97 sal_Int32 nChildIndex ) 98 throw ( lang::IndexOutOfBoundsException, 99 RuntimeException ) 100 { 101 vos::OGuard aGuard(Application::GetSolarMutex()); 102 103 // Get the respective child as SwFrm (also do index checking), ... 104 const SwAccessibleChild aChild = rContext.GetChild( *(rContext.GetMap()), 105 nChildIndex ); 106 if( !aChild.IsValid() ) 107 throwIndexOutOfBoundsException(); 108 109 // we can only select fly frames, so we ignore (should: return 110 // false) all other attempts at child selection 111 sal_Bool bRet = sal_False; 112 SwFEShell* pFEShell = GetFEShell(); 113 if( pFEShell != NULL ) 114 { 115 const SdrObject *pObj = aChild.GetDrawObject(); 116 if( pObj ) 117 { 118 bRet = rContext.Select( const_cast< SdrObject *>( pObj ), 0==aChild.GetSwFrm()); 119 } 120 } 121 // no frame shell, or no frame, or no fly frame -> can't select 122 123 // return bRet; 124 } 125 126 //When the selected state of the SwFrmOrObj is setted, return true. 127 static sal_Bool lcl_getSelectedState(const SwAccessibleChild& aChild, 128 SwAccessibleContext* pContext, 129 SwAccessibleMap* pMap) 130 { 131 Reference< XAccessible > xAcc; 132 if ( aChild.GetSwFrm() ) 133 { 134 xAcc = pMap->GetContext( aChild.GetSwFrm(), sal_False ); 135 } 136 else if ( aChild.GetDrawObject() ) 137 { 138 xAcc = pMap->GetContext( aChild.GetDrawObject(), pContext, sal_False ); 139 } 140 141 if( xAcc.is() ) 142 { 143 Reference< XAccessibleContext > pRContext = xAcc->getAccessibleContext(); 144 if(!pRContext.is()) 145 return sal_False; 146 Reference<XAccessibleStateSet> pRStateSet = pRContext->getAccessibleStateSet(); 147 if( pRStateSet.is() ) 148 { 149 Sequence<short> pStates = pRStateSet->getStates(); 150 long count = pStates.getLength(); 151 for( int i = 0; i < count; i++ ) 152 { 153 if( pStates[i] == AccessibleStateType::SELECTED) 154 return sal_True; 155 } 156 } 157 } 158 return sal_False; 159 } 160 161 sal_Bool SwAccessibleSelectionHelper::isAccessibleChildSelected( 162 sal_Int32 nChildIndex ) 163 throw ( lang::IndexOutOfBoundsException, 164 RuntimeException ) 165 { 166 vos::OGuard aGuard(Application::GetSolarMutex()); 167 168 // Get the respective child as SwFrm (also do index checking), ... 169 const SwAccessibleChild aChild = rContext.GetChild( *(rContext.GetMap()), 170 nChildIndex ); 171 if( !aChild.IsValid() ) 172 throwIndexOutOfBoundsException(); 173 174 // ... and compare to the currently selected frame 175 sal_Bool bRet = sal_False; 176 SwFEShell* pFEShell = GetFEShell(); 177 if( pFEShell ) 178 { 179 if ( aChild.GetSwFrm() != 0 ) 180 { 181 bRet = (pFEShell->GetCurrFlyFrm() == aChild.GetSwFrm()); 182 } 183 else if ( aChild.GetDrawObject() ) 184 { 185 bRet = pFEShell->IsObjSelected( *aChild.GetDrawObject() ); 186 } 187 //If the SwFrmOrObj is not selected directly in the UI, we should check whether it is selected in the selection cursor. 188 if( !bRet ) 189 { 190 if( lcl_getSelectedState( aChild, &rContext, rContext.GetMap() ) == sal_True) 191 bRet = sal_True; 192 } 193 } 194 195 return bRet; 196 } 197 198 void SwAccessibleSelectionHelper::clearAccessibleSelection( ) 199 throw ( RuntimeException ) 200 { 201 // return sal_False // we can't deselect 202 } 203 204 void SwAccessibleSelectionHelper::selectAllAccessibleChildren( ) 205 throw ( RuntimeException ) 206 { 207 vos::OGuard aGuard(Application::GetSolarMutex()); 208 209 // We can select only one. So iterate over the children to find 210 // the first we can select, and select it. 211 212 SwFEShell* pFEShell = GetFEShell(); 213 if( pFEShell ) 214 { 215 ::std::list< SwAccessibleChild > aChildren; 216 rContext.GetChildren( *(rContext.GetMap()), aChildren ); 217 218 ::std::list< SwAccessibleChild >::const_iterator aIter = aChildren.begin(); 219 ::std::list< SwAccessibleChild >::const_iterator aEndIter = aChildren.end(); 220 while( aIter != aEndIter ) 221 { 222 const SwAccessibleChild& rChild = *aIter; 223 const SdrObject* pObj = rChild.GetDrawObject(); 224 const SwFrm* pFrm = rChild.GetSwFrm(); 225 if( pObj && !(pFrm != 0 && pFEShell->IsObjSelected()) ) 226 { 227 rContext.Select( const_cast< SdrObject *>( pObj ), 0==pFrm ); 228 if( pFrm ) 229 break; 230 } 231 ++aIter; 232 } 233 } 234 } 235 236 sal_Int32 SwAccessibleSelectionHelper::getSelectedAccessibleChildCount( ) 237 throw ( RuntimeException ) 238 { 239 vos::OGuard aGuard(Application::GetSolarMutex()); 240 241 sal_Int32 nCount = 0; 242 // Only one frame can be selected at a time, and we only frames 243 // for selectable children. 244 SwFEShell* pFEShell = GetFEShell(); 245 if( pFEShell != 0 ) 246 { 247 const SwFlyFrm* pFlyFrm = pFEShell->GetCurrFlyFrm(); 248 if( pFlyFrm ) 249 { 250 //if( rContext.GetParent( SwAccessibleChild(pFlyFrm), rContext.IsInPagePreview()) == 251 // rContext.GetFrm() ) 252 nCount = 1; 253 } 254 else 255 { 256 sal_uInt16 nSelObjs = pFEShell->IsObjSelected(); 257 if( nSelObjs > 0 ) 258 { 259 ::std::list< SwAccessibleChild > aChildren; 260 rContext.GetChildren( *(rContext.GetMap()), aChildren ); 261 262 ::std::list< SwAccessibleChild >::const_iterator aIter = 263 aChildren.begin(); 264 ::std::list< SwAccessibleChild >::const_iterator aEndIter = 265 aChildren.end(); 266 while( aIter != aEndIter && nCount < nSelObjs ) 267 { 268 const SwAccessibleChild& rChild = *aIter; 269 if( rChild.GetDrawObject() && !rChild.GetSwFrm() && 270 rContext.GetParent(rChild, rContext.IsInPagePreview()) 271 == rContext.GetFrm() && 272 pFEShell->IsObjSelected( *rChild.GetDrawObject() ) ) 273 { 274 nCount++; 275 } 276 ++aIter; 277 } 278 } 279 } 280 //If the SwFrmOrObj is not selected directly in the UI, 281 //we should check whether it is selected in the selection cursor. 282 if( nCount == 0 ) 283 { 284 ::std::list< SwAccessibleChild > aChildren; 285 rContext.GetChildren( *(rContext.GetMap()), aChildren ); 286 ::std::list< SwAccessibleChild >::const_iterator aIter = 287 aChildren.begin(); 288 ::std::list< SwAccessibleChild >::const_iterator aEndIter = 289 aChildren.end(); 290 while( aIter != aEndIter ) 291 { 292 const SwAccessibleChild& aChild = *aIter; 293 if( lcl_getSelectedState( aChild, &rContext, rContext.GetMap() ) ) 294 nCount++; 295 ++aIter; 296 } 297 } 298 } 299 return nCount; 300 } 301 302 Reference<XAccessible> SwAccessibleSelectionHelper::getSelectedAccessibleChild( 303 sal_Int32 nSelectedChildIndex ) 304 throw ( lang::IndexOutOfBoundsException, 305 RuntimeException) 306 { 307 vos::OGuard aGuard(Application::GetSolarMutex()); 308 309 // Since the index is relative to the selected children, and since 310 // there can be at most one selected frame child, the index must 311 // be 0, and a selection must exist, otherwise we have to throw an 312 // lang::IndexOutOfBoundsException 313 SwFEShell* pFEShell = GetFEShell(); 314 if( 0 == pFEShell ) 315 throwIndexOutOfBoundsException(); 316 317 SwAccessibleChild aChild; 318 const SwFlyFrm *pFlyFrm = pFEShell->GetCurrFlyFrm(); 319 if( pFlyFrm ) 320 { 321 if( 0 == nSelectedChildIndex ) 322 { 323 if(rContext.GetParent( SwAccessibleChild(pFlyFrm), rContext.IsInPagePreview()) == rContext.GetFrm() ) 324 { 325 aChild = pFlyFrm; 326 } 327 else 328 { 329 const SwFrmFmt *pFrmFmt = pFlyFrm->GetFmt(); 330 if (pFrmFmt) 331 { 332 const SwFmtAnchor& pAnchor = pFrmFmt->GetAnchor(); 333 if( pAnchor.GetAnchorId() == FLY_AS_CHAR ) 334 { 335 const SwFrm *pParaFrm = rContext.GetParent( SwAccessibleChild(pFlyFrm), rContext.IsInPagePreview() ); 336 aChild = pParaFrm; 337 } 338 } 339 } 340 } 341 } 342 else 343 { 344 sal_uInt16 nSelObjs = pFEShell->IsObjSelected(); 345 if( 0 == nSelObjs || nSelectedChildIndex >= nSelObjs ) 346 throwIndexOutOfBoundsException(); 347 348 ::std::list< SwAccessibleChild > aChildren; 349 rContext.GetChildren( *(rContext.GetMap()), aChildren ); 350 351 ::std::list< SwAccessibleChild >::const_iterator aIter = aChildren.begin(); 352 ::std::list< SwAccessibleChild >::const_iterator aEndIter = aChildren.end(); 353 while( aIter != aEndIter && !aChild.IsValid() ) 354 { 355 const SwAccessibleChild& rChild = *aIter; 356 if( rChild.GetDrawObject() && !rChild.GetSwFrm() && 357 rContext.GetParent(rChild, rContext.IsInPagePreview()) == 358 rContext.GetFrm() && 359 pFEShell->IsObjSelected( *rChild.GetDrawObject() ) ) 360 { 361 if( 0 == nSelectedChildIndex ) 362 aChild = rChild; 363 else 364 --nSelectedChildIndex; 365 } 366 ++aIter; 367 } 368 } 369 370 if( !aChild.IsValid() ) 371 throwIndexOutOfBoundsException(); 372 373 DBG_ASSERT( rContext.GetMap() != NULL, "We need the map." ); 374 Reference< XAccessible > xChild; 375 if( aChild.GetSwFrm() ) 376 { 377 ::vos::ORef < SwAccessibleContext > xChildImpl( 378 rContext.GetMap()->GetContextImpl( aChild.GetSwFrm(), 379 sal_True ) ); 380 if( xChildImpl.isValid() ) 381 { 382 xChildImpl->SetParent( &rContext ); 383 xChild = xChildImpl.getBodyPtr(); 384 } 385 } 386 else if ( aChild.GetDrawObject() ) 387 { 388 ::vos::ORef < ::accessibility::AccessibleShape > xChildImpl( 389 rContext.GetMap()->GetContextImpl( aChild.GetDrawObject(), 390 &rContext, sal_True ) ); 391 if( xChildImpl.isValid() ) 392 xChild = xChildImpl.getBodyPtr(); 393 } 394 return xChild; 395 } 396 397 // --> OD 2004-11-16 #111714# - index has to be treated as global child index. 398 void SwAccessibleSelectionHelper::deselectAccessibleChild( 399 sal_Int32 nChildIndex ) 400 throw ( lang::IndexOutOfBoundsException, 401 RuntimeException ) 402 { 403 // return sal_False // we can't deselect 404 if( nChildIndex < 0 || 405 nChildIndex >= rContext.GetChildCount( *(rContext.GetMap()) ) ) 406 throwIndexOutOfBoundsException(); 407 } 408