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