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