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/AccessibleStateType.hpp> 29 #include <com/sun/star/accessibility/AccessibleEventId.hpp> 30 #include <unotools/accessiblestatesethelper.hxx> 31 #include <vos/mutex.hxx> 32 #include <vcl/svapp.hxx> 33 #include <vcl/window.hxx> 34 #include <frmfmt.hxx> 35 #include <ndnotxt.hxx> 36 #include <flyfrm.hxx> 37 #include <cntfrm.hxx> 38 #include <fmtcntnt.hxx> 39 #include <ndindex.hxx> 40 #include "fesh.hxx" 41 #include <hints.hxx> 42 #include "accmap.hxx" 43 #include "accframebase.hxx" 44 45 //IAccessibility2 Implementation 2009----- 46 #ifndef _CRSRSH_HXX 47 #include <crsrsh.hxx> 48 #endif 49 #ifndef _FESH_HXX 50 #include "fesh.hxx" 51 #endif 52 #ifndef _TXTFRM_HXX 53 #include <txtfrm.hxx> 54 #endif 55 #ifndef _NDTXT_HXX 56 #include <ndtxt.hxx> 57 #endif 58 #ifndef _DCONTACT_HXX 59 #include <dcontact.hxx> 60 #endif 61 #ifndef _FMTANCHR_HXX 62 #include <fmtanchr.hxx> 63 #endif 64 //-----IAccessibility2 Implementation 2009 65 using namespace ::com::sun::star; 66 using namespace ::com::sun::star::accessibility; 67 using ::rtl::OUString; 68 69 sal_Bool SwAccessibleFrameBase::IsSelected() 70 { 71 sal_Bool bRet = sal_False; 72 73 DBG_ASSERT( GetMap(), "no map?" ); 74 const ViewShell *pVSh = GetMap()->GetShell(); 75 DBG_ASSERT( pVSh, "no shell?" ); 76 if( pVSh->ISA( SwFEShell ) ) 77 { 78 const SwFEShell *pFESh = static_cast< const SwFEShell * >( pVSh ); 79 const SwFrm *pFlyFrm = pFESh->GetCurrFlyFrm(); 80 if( pFlyFrm == GetFrm() ) 81 bRet = sal_True; 82 } 83 84 return bRet; 85 } 86 87 void SwAccessibleFrameBase::GetStates( 88 ::utl::AccessibleStateSetHelper& rStateSet ) 89 { 90 SwAccessibleContext::GetStates( rStateSet ); 91 92 const ViewShell *pVSh = GetMap()->GetShell(); 93 DBG_ASSERT( pVSh, "no shell?" ); 94 sal_Bool bSelectable = pVSh->ISA( SwFEShell ); 95 96 // SELECTABLE 97 if( bSelectable ) 98 rStateSet.AddState( AccessibleStateType::SELECTABLE ); 99 100 // FOCUSABLE 101 if( bSelectable ) 102 rStateSet.AddState( AccessibleStateType::FOCUSABLE ); 103 104 // SELECTED and FOCUSED 105 if( IsSelected() ) 106 { 107 rStateSet.AddState( AccessibleStateType::SELECTED ); 108 ASSERT( bIsSelected, "bSelected out of sync" ); 109 ::vos::ORef < SwAccessibleContext > xThis( this ); 110 GetMap()->SetCursorContext( xThis ); 111 112 Window *pWin = GetWindow(); 113 if( pWin && pWin->HasFocus() ) 114 rStateSet.AddState( AccessibleStateType::FOCUSED ); 115 } 116 //IAccessibility2 Implementation 2009----- 117 if( GetSelectedState() ) 118 rStateSet.AddState( AccessibleStateType::SELECTED ); 119 //-----IAccessibility2 Implementation 2009 120 } 121 122 123 sal_uInt8 SwAccessibleFrameBase::GetNodeType( const SwFlyFrm *pFlyFrm ) 124 { 125 sal_uInt8 nType = ND_TEXTNODE; 126 if( pFlyFrm->Lower() ) 127 { 128 if( pFlyFrm->Lower()->IsNoTxtFrm() ) 129 { 130 const SwCntntFrm *pCntFrm = 131 static_cast<const SwCntntFrm *>( pFlyFrm->Lower() ); 132 nType = pCntFrm->GetNode()->GetNodeType(); 133 } 134 } 135 else 136 { 137 const SwFrmFmt *pFrmFmt = pFlyFrm->GetFmt(); 138 const SwFmtCntnt& rCntnt = pFrmFmt->GetCntnt(); 139 const SwNodeIndex *pNdIdx = rCntnt.GetCntntIdx(); 140 if( pNdIdx ) 141 { 142 const SwCntntNode *pCNd = 143 (pNdIdx->GetNodes())[pNdIdx->GetIndex()+1]->GetCntntNode(); 144 if( pCNd ) 145 nType = pCNd->GetNodeType(); 146 } 147 } 148 149 return nType; 150 } 151 152 SwAccessibleFrameBase::SwAccessibleFrameBase( 153 SwAccessibleMap* pInitMap, 154 sal_Int16 nInitRole, 155 const SwFlyFrm* pFlyFrm ) : 156 SwAccessibleContext( pInitMap, nInitRole, pFlyFrm ), 157 bIsSelected( sal_False ) 158 { 159 vos::OGuard aGuard(Application::GetSolarMutex()); 160 161 const SwFrmFmt *pFrmFmt = pFlyFrm->GetFmt(); 162 const_cast< SwFrmFmt * >( pFrmFmt )->Add( this ); 163 164 SetName( pFrmFmt->GetName() ); 165 166 bIsSelected = IsSelected(); 167 } 168 169 void SwAccessibleFrameBase::_InvalidateCursorPos() 170 { 171 sal_Bool bNewSelected = IsSelected(); 172 sal_Bool bOldSelected; 173 174 { 175 vos::OGuard aGuard( aMutex ); 176 bOldSelected = bIsSelected; 177 bIsSelected = bNewSelected; 178 } 179 180 if( bNewSelected ) 181 { 182 // remember that object as the one that has the caret. This is 183 // neccessary to notify that object if the cursor leaves it. 184 ::vos::ORef < SwAccessibleContext > xThis( this ); 185 GetMap()->SetCursorContext( xThis ); 186 } 187 188 if( bOldSelected != bNewSelected ) 189 { 190 Window *pWin = GetWindow(); 191 if( pWin && pWin->HasFocus() && bNewSelected ) 192 FireStateChangedEvent( AccessibleStateType::FOCUSED, bNewSelected ); 193 //IAccessibility2 Implementation 2009----- 194 //FireStateChangedEvent( AccessibleStateType::SELECTED, bNewSelected ); 195 if( pWin && pWin->HasFocus() && !bNewSelected ) 196 FireStateChangedEvent( AccessibleStateType::FOCUSED, bNewSelected ); 197 if(bNewSelected) 198 { 199 uno::Reference< XAccessible > xParent( GetWeakParent() ); 200 if( xParent.is() ) 201 { 202 SwAccessibleContext *pAcc = 203 static_cast <SwAccessibleContext *>( xParent.get() ); 204 205 AccessibleEventObject aEvent; 206 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED; 207 uno::Reference< XAccessible > xChild(this); 208 aEvent.NewValue <<= xChild; 209 pAcc->FireAccessibleEvent( aEvent ); 210 } 211 } 212 //-----IAccessibility2 Implementation 2009 213 } 214 } 215 216 void SwAccessibleFrameBase::_InvalidateFocus() 217 { 218 Window *pWin = GetWindow(); 219 if( pWin ) 220 { 221 sal_Bool bSelected; 222 223 { 224 vos::OGuard aGuard( aMutex ); 225 bSelected = bIsSelected; 226 } 227 ASSERT( bSelected, "focus object should be selected" ); 228 229 FireStateChangedEvent( AccessibleStateType::FOCUSED, 230 pWin->HasFocus() && bSelected ); 231 } 232 } 233 234 sal_Bool SwAccessibleFrameBase::HasCursor() 235 { 236 vos::OGuard aGuard( aMutex ); 237 return bIsSelected; 238 } 239 240 241 SwAccessibleFrameBase::~SwAccessibleFrameBase() 242 { 243 } 244 245 void SwAccessibleFrameBase::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew) 246 { 247 sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0 ; 248 const SwFlyFrm *pFlyFrm = static_cast< const SwFlyFrm * >( GetFrm() ); 249 switch( nWhich ) 250 { 251 case RES_NAME_CHANGED: 252 if( pFlyFrm ) 253 { 254 const SwFrmFmt *pFrmFmt = pFlyFrm->GetFmt(); 255 ASSERT( pFrmFmt == GetRegisteredIn(), "invalid frame" ); 256 257 OUString sOldName( GetName() ); 258 ASSERT( !pOld || 259 static_cast < const SwStringMsgPoolItem * >( pOld )->GetString() == String( sOldName ), 260 "invalid old name" ); 261 262 const String& rNewName = pFrmFmt->GetName(); 263 SetName( rNewName ); 264 ASSERT( !pNew || 265 static_cast < const SwStringMsgPoolItem * >( pNew )->GetString() == rNewName, 266 "invalid new name" ); 267 268 if( sOldName != GetName() ) 269 { 270 AccessibleEventObject aEvent; 271 aEvent.EventId = AccessibleEventId::NAME_CHANGED; 272 aEvent.OldValue <<= sOldName; 273 aEvent.NewValue <<= GetName(); 274 FireAccessibleEvent( aEvent ); 275 } 276 } 277 break; 278 case RES_OBJECTDYING: 279 // mba: it seems that this class intentionally does not call code in base class SwClient 280 if( pOld && ( GetRegisteredIn() == static_cast< SwModify *>( static_cast< const SwPtrMsgPoolItem * >( pOld )->pObject ) ) ) 281 GetRegisteredInNonConst()->Remove( this ); 282 break; 283 284 case RES_FMT_CHG: 285 if( pOld && 286 static_cast< const SwFmtChg * >(pNew)->pChangedFmt == GetRegisteredIn() && 287 static_cast< const SwFmtChg * >(pOld)->pChangedFmt->IsFmtInDTOR() ) 288 GetRegisteredInNonConst()->Remove( this ); 289 break; 290 291 default: 292 // mba: former call to base class method removed as it is meant to handle only RES_OBJECTDYING 293 break; 294 } 295 } 296 297 void SwAccessibleFrameBase::Dispose( sal_Bool bRecursive ) 298 { 299 vos::OGuard aGuard(Application::GetSolarMutex()); 300 301 if( GetRegisteredIn() ) 302 GetRegisteredInNonConst()->Remove( this ); 303 304 SwAccessibleContext::Dispose( bRecursive ); 305 } 306 //IAccessibility2 Implementation 2009----- 307 //Get the selection cursor of the document. 308 SwPaM* SwAccessibleFrameBase::GetCrsr() 309 { 310 // get the cursor shell; if we don't have any, we don't have a 311 // cursor/selection either 312 SwPaM* pCrsr = NULL; 313 SwCrsrShell* pCrsrShell = GetCrsrShell(); 314 if( pCrsrShell != NULL && !pCrsrShell->IsTableMode() ) 315 { 316 SwFEShell *pFESh = pCrsrShell->ISA( SwFEShell ) 317 ? static_cast< SwFEShell * >( pCrsrShell ) : 0; 318 if( !pFESh || 319 !(pFESh->IsFrmSelected() || pFESh->IsObjSelected() > 0) ) 320 { 321 // get the selection, and test whether it affects our text node 322 pCrsr = pCrsrShell->GetCrsr( sal_False /* ??? */ ); 323 } 324 } 325 326 return pCrsr; 327 } 328 //Return the selected state of the object. 329 //when the object's anchor are in the selection cursor, we should return true. 330 sal_Bool SwAccessibleFrameBase::GetSelectedState( ) 331 { 332 vos::OGuard aGuard(Application::GetSolarMutex()); 333 334 //IAccessibility2 Implementation 2009----- 335 if(GetMap()->IsDocumentSelAll()) 336 { 337 return sal_True; 338 } 339 //-----IAccessibility2 Implementation 2009 340 341 // SELETED. 342 SwFlyFrm* pFlyFrm = getFlyFrm(); 343 const SwFrmFmt *pFrmFmt = pFlyFrm->GetFmt(); 344 const SwFmtAnchor& pAnchor = pFrmFmt->GetAnchor(); 345 const SwPosition *pPos = pAnchor.GetCntntAnchor(); 346 if( !pPos ) 347 return sal_False; 348 int pIndex = pPos->nContent.GetIndex(); 349 if( pPos->nNode.GetNode().GetTxtNode() ) 350 { 351 SwPaM* pCrsr = GetCrsr(); 352 if( pCrsr != NULL ) 353 { 354 const SwTxtNode* pNode = pPos->nNode.GetNode().GetTxtNode(); 355 sal_uLong nHere = pNode->GetIndex(); 356 357 // iterate over ring 358 SwPaM* pRingStart = pCrsr; 359 do 360 { 361 // ignore, if no mark 362 if( pCrsr->HasMark() ) 363 { 364 // check whether nHere is 'inside' pCrsr 365 SwPosition* pStart = pCrsr->Start(); 366 sal_uLong nStartIndex = pStart->nNode.GetIndex(); 367 SwPosition* pEnd = pCrsr->End(); 368 sal_uLong nEndIndex = pEnd->nNode.GetIndex(); 369 if( ( nHere >= nStartIndex ) && (nHere <= nEndIndex) ) 370 { 371 if( pAnchor.GetAnchorId() == FLY_AS_CHAR ) 372 { 373 //IAccessibility2 Implementation 2009----- 374 if( (nHere == nStartIndex) && (pIndex >= pStart->nContent.GetIndex()) || (nHere > nStartIndex) ) 375 if( (nHere == nEndIndex) && (pIndex < pEnd->nContent.GetIndex()) || (nHere < nEndIndex) ) 376 return sal_True; 377 //-----IAccessibility2 Implementation 2009 378 } 379 else if( pAnchor.GetAnchorId() == FLY_AT_PARA ) 380 { 381 if( ((nHere > nStartIndex) || pStart->nContent.GetIndex() ==0 ) 382 && (nHere < nEndIndex ) ) 383 return sal_True; 384 } 385 break; 386 } 387 // else: this PaM doesn't point to this paragraph 388 } 389 // else: this PaM is collapsed and doesn't select anything 390 391 // next PaM in ring 392 pCrsr = static_cast<SwPaM*>( pCrsr->GetNext() ); 393 } 394 while( pCrsr != pRingStart ); 395 } 396 } 397 return sal_False; 398 } 399 400 SwFlyFrm* SwAccessibleFrameBase::getFlyFrm() const 401 { 402 SwFlyFrm* pFlyFrm = NULL; 403 404 const SwFrm* pFrm = GetFrm(); 405 DBG_ASSERT( pFrm != NULL, "frame expected" ); 406 if( pFrm->IsFlyFrm() ) 407 { 408 pFlyFrm = static_cast<SwFlyFrm*>( const_cast<SwFrm*>( pFrm ) ); 409 } 410 411 return pFlyFrm; 412 } 413 414 sal_Bool SwAccessibleFrameBase::SetSelectedState( sal_Bool ) 415 { 416 sal_Bool bParaSeleted = GetSelectedState() || IsSelected(); 417 418 if(bIsSeletedInDoc != bParaSeleted) 419 { 420 bIsSeletedInDoc = bParaSeleted; 421 FireStateChangedEvent( AccessibleStateType::SELECTED, bParaSeleted ); 422 return sal_True; 423 } 424 return sal_False; 425 } 426 //-----IAccessibility2 Implementation 2009 427