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 using namespace ::com::sun::star; 46 using namespace ::com::sun::star::accessibility; 47 using ::rtl::OUString; 48 49 sal_Bool SwAccessibleFrameBase::IsSelected() 50 { 51 sal_Bool bRet = sal_False; 52 53 DBG_ASSERT( GetMap(), "no map?" ); 54 const ViewShell *pVSh = GetMap()->GetShell(); 55 DBG_ASSERT( pVSh, "no shell?" ); 56 if( pVSh->ISA( SwFEShell ) ) 57 { 58 const SwFEShell *pFESh = static_cast< const SwFEShell * >( pVSh ); 59 const SwFrm *pFlyFrm = pFESh->GetCurrFlyFrm(); 60 if( pFlyFrm == GetFrm() ) 61 bRet = sal_True; 62 } 63 64 return bRet; 65 } 66 67 void SwAccessibleFrameBase::GetStates( 68 ::utl::AccessibleStateSetHelper& rStateSet ) 69 { 70 SwAccessibleContext::GetStates( rStateSet ); 71 72 const ViewShell *pVSh = GetMap()->GetShell(); 73 DBG_ASSERT( pVSh, "no shell?" ); 74 sal_Bool bSelectable = pVSh->ISA( SwFEShell ); 75 76 // SELECTABLE 77 if( bSelectable ) 78 rStateSet.AddState( AccessibleStateType::SELECTABLE ); 79 80 // FOCUSABLE 81 if( bSelectable ) 82 rStateSet.AddState( AccessibleStateType::FOCUSABLE ); 83 84 // SELECTED and FOCUSED 85 if( IsSelected() ) 86 { 87 rStateSet.AddState( AccessibleStateType::SELECTED ); 88 ASSERT( bIsSelected, "bSelected out of sync" ); 89 ::vos::ORef < SwAccessibleContext > xThis( this ); 90 GetMap()->SetCursorContext( xThis ); 91 92 Window *pWin = GetWindow(); 93 if( pWin && pWin->HasFocus() ) 94 rStateSet.AddState( AccessibleStateType::FOCUSED ); 95 } 96 } 97 98 99 sal_uInt8 SwAccessibleFrameBase::GetNodeType( const SwFlyFrm *pFlyFrm ) 100 { 101 sal_uInt8 nType = ND_TEXTNODE; 102 if( pFlyFrm->Lower() ) 103 { 104 if( pFlyFrm->Lower()->IsNoTxtFrm() ) 105 { 106 const SwCntntFrm *pCntFrm = 107 static_cast<const SwCntntFrm *>( pFlyFrm->Lower() ); 108 nType = pCntFrm->GetNode()->GetNodeType(); 109 } 110 } 111 else 112 { 113 const SwFrmFmt *pFrmFmt = pFlyFrm->GetFmt(); 114 const SwFmtCntnt& rCntnt = pFrmFmt->GetCntnt(); 115 const SwNodeIndex *pNdIdx = rCntnt.GetCntntIdx(); 116 if( pNdIdx ) 117 { 118 const SwCntntNode *pCNd = 119 (pNdIdx->GetNodes())[pNdIdx->GetIndex()+1]->GetCntntNode(); 120 if( pCNd ) 121 nType = pCNd->GetNodeType(); 122 } 123 } 124 125 return nType; 126 } 127 128 SwAccessibleFrameBase::SwAccessibleFrameBase( 129 SwAccessibleMap* pInitMap, 130 sal_Int16 nInitRole, 131 const SwFlyFrm* pFlyFrm ) : 132 SwAccessibleContext( pInitMap, nInitRole, pFlyFrm ), 133 bIsSelected( sal_False ) 134 { 135 vos::OGuard aGuard(Application::GetSolarMutex()); 136 137 const SwFrmFmt *pFrmFmt = pFlyFrm->GetFmt(); 138 const_cast< SwFrmFmt * >( pFrmFmt )->Add( this ); 139 140 SetName( pFrmFmt->GetName() ); 141 142 bIsSelected = IsSelected(); 143 } 144 145 void SwAccessibleFrameBase::_InvalidateCursorPos() 146 { 147 sal_Bool bNewSelected = IsSelected(); 148 sal_Bool bOldSelected; 149 150 { 151 vos::OGuard aGuard( aMutex ); 152 bOldSelected = bIsSelected; 153 bIsSelected = bNewSelected; 154 } 155 156 if( bNewSelected ) 157 { 158 // remember that object as the one that has the caret. This is 159 // neccessary to notify that object if the cursor leaves it. 160 ::vos::ORef < SwAccessibleContext > xThis( this ); 161 GetMap()->SetCursorContext( xThis ); 162 } 163 164 if( bOldSelected != bNewSelected ) 165 { 166 Window *pWin = GetWindow(); 167 if( pWin && pWin->HasFocus() && bNewSelected ) 168 FireStateChangedEvent( AccessibleStateType::FOCUSED, bNewSelected ); 169 FireStateChangedEvent( AccessibleStateType::SELECTED, bNewSelected ); 170 if( pWin && pWin->HasFocus() && !bNewSelected ) 171 FireStateChangedEvent( AccessibleStateType::FOCUSED, bNewSelected ); 172 173 uno::Reference< XAccessible > xParent( GetWeakParent() ); 174 if( xParent.is() ) 175 { 176 SwAccessibleContext *pAcc = 177 static_cast <SwAccessibleContext *>( xParent.get() ); 178 179 AccessibleEventObject aEvent; 180 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED; 181 pAcc->FireAccessibleEvent( aEvent ); 182 } 183 } 184 } 185 186 void SwAccessibleFrameBase::_InvalidateFocus() 187 { 188 Window *pWin = GetWindow(); 189 if( pWin ) 190 { 191 sal_Bool bSelected; 192 193 { 194 vos::OGuard aGuard( aMutex ); 195 bSelected = bIsSelected; 196 } 197 ASSERT( bSelected, "focus object should be selected" ); 198 199 FireStateChangedEvent( AccessibleStateType::FOCUSED, 200 pWin->HasFocus() && bSelected ); 201 } 202 } 203 204 sal_Bool SwAccessibleFrameBase::HasCursor() 205 { 206 vos::OGuard aGuard( aMutex ); 207 return bIsSelected; 208 } 209 210 211 SwAccessibleFrameBase::~SwAccessibleFrameBase() 212 { 213 } 214 215 void SwAccessibleFrameBase::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew) 216 { 217 sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0 ; 218 const SwFlyFrm *pFlyFrm = static_cast< const SwFlyFrm * >( GetFrm() ); 219 switch( nWhich ) 220 { 221 case RES_NAME_CHANGED: 222 if( pFlyFrm ) 223 { 224 const SwFrmFmt *pFrmFmt = pFlyFrm->GetFmt(); 225 ASSERT( pFrmFmt == GetRegisteredIn(), "invalid frame" ); 226 227 OUString sOldName( GetName() ); 228 ASSERT( !pOld || 229 static_cast < const SwStringMsgPoolItem * >( pOld )->GetString() == String( sOldName ), 230 "invalid old name" ); 231 232 const String& rNewName = pFrmFmt->GetName(); 233 SetName( rNewName ); 234 ASSERT( !pNew || 235 static_cast < const SwStringMsgPoolItem * >( pNew )->GetString() == rNewName, 236 "invalid new name" ); 237 238 if( sOldName != GetName() ) 239 { 240 AccessibleEventObject aEvent; 241 aEvent.EventId = AccessibleEventId::NAME_CHANGED; 242 aEvent.OldValue <<= sOldName; 243 aEvent.NewValue <<= GetName(); 244 FireAccessibleEvent( aEvent ); 245 } 246 } 247 break; 248 case RES_OBJECTDYING: 249 // mba: it seems that this class intentionally does not call code in base class SwClient 250 if( GetRegisteredIn() == 251 static_cast< SwModify *>( static_cast< const SwPtrMsgPoolItem * >( pOld )->pObject ) ) 252 GetRegisteredInNonConst()->Remove( this ); 253 break; 254 255 case RES_FMT_CHG: 256 if( static_cast< const SwFmtChg * >(pNew)->pChangedFmt == GetRegisteredIn() && 257 static_cast< const SwFmtChg * >(pOld)->pChangedFmt->IsFmtInDTOR() ) 258 GetRegisteredInNonConst()->Remove( this ); 259 break; 260 261 default: 262 // mba: former call to base class method removed as it is meant to handle only RES_OBJECTDYING 263 break; 264 } 265 } 266 267 void SwAccessibleFrameBase::Dispose( sal_Bool bRecursive ) 268 { 269 vos::OGuard aGuard(Application::GetSolarMutex()); 270 271 if( GetRegisteredIn() ) 272 GetRegisteredInNonConst()->Remove( this ); 273 274 SwAccessibleContext::Dispose( bRecursive ); 275 } 276