1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sw.hxx" 30 31 32 #include <com/sun/star/accessibility/AccessibleStateType.hpp> 33 #include <com/sun/star/accessibility/AccessibleEventId.hpp> 34 #include <unotools/accessiblestatesethelper.hxx> 35 #include <vos/mutex.hxx> 36 #include <vcl/svapp.hxx> 37 #include <vcl/window.hxx> 38 #include <frmfmt.hxx> 39 #include <ndnotxt.hxx> 40 #include <flyfrm.hxx> 41 #include <cntfrm.hxx> 42 #include <fmtcntnt.hxx> 43 #include <ndindex.hxx> 44 #include "fesh.hxx" 45 #include <hints.hxx> 46 #include "accmap.hxx" 47 #include "accframebase.hxx" 48 49 using namespace ::com::sun::star; 50 using namespace ::com::sun::star::accessibility; 51 using ::rtl::OUString; 52 53 sal_Bool SwAccessibleFrameBase::IsSelected() 54 { 55 sal_Bool bRet = sal_False; 56 57 DBG_ASSERT( GetMap(), "no map?" ); 58 const ViewShell *pVSh = GetMap()->GetShell(); 59 DBG_ASSERT( pVSh, "no shell?" ); 60 if( pVSh->ISA( SwFEShell ) ) 61 { 62 const SwFEShell *pFESh = static_cast< const SwFEShell * >( pVSh ); 63 const SwFrm *pFlyFrm = pFESh->GetCurrFlyFrm(); 64 if( pFlyFrm == GetFrm() ) 65 bRet = sal_True; 66 } 67 68 return bRet; 69 } 70 71 void SwAccessibleFrameBase::GetStates( 72 ::utl::AccessibleStateSetHelper& rStateSet ) 73 { 74 SwAccessibleContext::GetStates( rStateSet ); 75 76 const ViewShell *pVSh = GetMap()->GetShell(); 77 DBG_ASSERT( pVSh, "no shell?" ); 78 sal_Bool bSelectable = pVSh->ISA( SwFEShell ); 79 80 // SELECTABLE 81 if( bSelectable ) 82 rStateSet.AddState( AccessibleStateType::SELECTABLE ); 83 84 // FOCUSABLE 85 if( bSelectable ) 86 rStateSet.AddState( AccessibleStateType::FOCUSABLE ); 87 88 // SELECTED and FOCUSED 89 if( IsSelected() ) 90 { 91 rStateSet.AddState( AccessibleStateType::SELECTED ); 92 ASSERT( bIsSelected, "bSelected out of sync" ); 93 ::vos::ORef < SwAccessibleContext > xThis( this ); 94 GetMap()->SetCursorContext( xThis ); 95 96 Window *pWin = GetWindow(); 97 if( pWin && pWin->HasFocus() ) 98 rStateSet.AddState( AccessibleStateType::FOCUSED ); 99 } 100 } 101 102 103 sal_uInt8 SwAccessibleFrameBase::GetNodeType( const SwFlyFrm *pFlyFrm ) 104 { 105 sal_uInt8 nType = ND_TEXTNODE; 106 if( pFlyFrm->Lower() ) 107 { 108 if( pFlyFrm->Lower()->IsNoTxtFrm() ) 109 { 110 const SwCntntFrm *pCntFrm = 111 static_cast<const SwCntntFrm *>( pFlyFrm->Lower() ); 112 nType = pCntFrm->GetNode()->GetNodeType(); 113 } 114 } 115 else 116 { 117 const SwFrmFmt *pFrmFmt = pFlyFrm->GetFmt(); 118 const SwFmtCntnt& rCntnt = pFrmFmt->GetCntnt(); 119 const SwNodeIndex *pNdIdx = rCntnt.GetCntntIdx(); 120 if( pNdIdx ) 121 { 122 const SwCntntNode *pCNd = 123 (pNdIdx->GetNodes())[pNdIdx->GetIndex()+1]->GetCntntNode(); 124 if( pCNd ) 125 nType = pCNd->GetNodeType(); 126 } 127 } 128 129 return nType; 130 } 131 132 SwAccessibleFrameBase::SwAccessibleFrameBase( 133 SwAccessibleMap* pInitMap, 134 sal_Int16 nInitRole, 135 const SwFlyFrm* pFlyFrm ) : 136 SwAccessibleContext( pInitMap, nInitRole, pFlyFrm ), 137 bIsSelected( sal_False ) 138 { 139 vos::OGuard aGuard(Application::GetSolarMutex()); 140 141 const SwFrmFmt *pFrmFmt = pFlyFrm->GetFmt(); 142 const_cast< SwFrmFmt * >( pFrmFmt )->Add( this ); 143 144 SetName( pFrmFmt->GetName() ); 145 146 bIsSelected = IsSelected(); 147 } 148 149 void SwAccessibleFrameBase::_InvalidateCursorPos() 150 { 151 sal_Bool bNewSelected = IsSelected(); 152 sal_Bool bOldSelected; 153 154 { 155 vos::OGuard aGuard( aMutex ); 156 bOldSelected = bIsSelected; 157 bIsSelected = bNewSelected; 158 } 159 160 if( bNewSelected ) 161 { 162 // remember that object as the one that has the caret. This is 163 // neccessary to notify that object if the cursor leaves it. 164 ::vos::ORef < SwAccessibleContext > xThis( this ); 165 GetMap()->SetCursorContext( xThis ); 166 } 167 168 if( bOldSelected != bNewSelected ) 169 { 170 Window *pWin = GetWindow(); 171 if( pWin && pWin->HasFocus() && bNewSelected ) 172 FireStateChangedEvent( AccessibleStateType::FOCUSED, bNewSelected ); 173 FireStateChangedEvent( AccessibleStateType::SELECTED, bNewSelected ); 174 if( pWin && pWin->HasFocus() && !bNewSelected ) 175 FireStateChangedEvent( AccessibleStateType::FOCUSED, bNewSelected ); 176 177 uno::Reference< XAccessible > xParent( GetWeakParent() ); 178 if( xParent.is() ) 179 { 180 SwAccessibleContext *pAcc = 181 static_cast <SwAccessibleContext *>( xParent.get() ); 182 183 AccessibleEventObject aEvent; 184 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED; 185 pAcc->FireAccessibleEvent( aEvent ); 186 } 187 } 188 } 189 190 void SwAccessibleFrameBase::_InvalidateFocus() 191 { 192 Window *pWin = GetWindow(); 193 if( pWin ) 194 { 195 sal_Bool bSelected; 196 197 { 198 vos::OGuard aGuard( aMutex ); 199 bSelected = bIsSelected; 200 } 201 ASSERT( bSelected, "focus object should be selected" ); 202 203 FireStateChangedEvent( AccessibleStateType::FOCUSED, 204 pWin->HasFocus() && bSelected ); 205 } 206 } 207 208 sal_Bool SwAccessibleFrameBase::HasCursor() 209 { 210 vos::OGuard aGuard( aMutex ); 211 return bIsSelected; 212 } 213 214 215 SwAccessibleFrameBase::~SwAccessibleFrameBase() 216 { 217 } 218 219 void SwAccessibleFrameBase::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew) 220 { 221 sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0 ; 222 const SwFlyFrm *pFlyFrm = static_cast< const SwFlyFrm * >( GetFrm() ); 223 switch( nWhich ) 224 { 225 case RES_NAME_CHANGED: 226 if( pFlyFrm ) 227 { 228 const SwFrmFmt *pFrmFmt = pFlyFrm->GetFmt(); 229 ASSERT( pFrmFmt == GetRegisteredIn(), "invalid frame" ); 230 231 OUString sOldName( GetName() ); 232 ASSERT( !pOld || 233 static_cast < const SwStringMsgPoolItem * >( pOld )->GetString() == String( sOldName ), 234 "invalid old name" ); 235 236 const String& rNewName = pFrmFmt->GetName(); 237 SetName( rNewName ); 238 ASSERT( !pNew || 239 static_cast < const SwStringMsgPoolItem * >( pNew )->GetString() == rNewName, 240 "invalid new name" ); 241 242 if( sOldName != GetName() ) 243 { 244 AccessibleEventObject aEvent; 245 aEvent.EventId = AccessibleEventId::NAME_CHANGED; 246 aEvent.OldValue <<= sOldName; 247 aEvent.NewValue <<= GetName(); 248 FireAccessibleEvent( aEvent ); 249 } 250 } 251 break; 252 case RES_OBJECTDYING: 253 // mba: it seems that this class intentionally does not call code in base class SwClient 254 if( GetRegisteredIn() == 255 static_cast< SwModify *>( static_cast< const SwPtrMsgPoolItem * >( pOld )->pObject ) ) 256 GetRegisteredInNonConst()->Remove( this ); 257 break; 258 259 case RES_FMT_CHG: 260 if( static_cast< const SwFmtChg * >(pNew)->pChangedFmt == GetRegisteredIn() && 261 static_cast< const SwFmtChg * >(pOld)->pChangedFmt->IsFmtInDTOR() ) 262 GetRegisteredInNonConst()->Remove( this ); 263 break; 264 265 default: 266 // mba: former call to base class method removed as it is meant to handle only RES_OBJECTDYING 267 break; 268 } 269 } 270 271 void SwAccessibleFrameBase::Dispose( sal_Bool bRecursive ) 272 { 273 vos::OGuard aGuard(Application::GetSolarMutex()); 274 275 if( GetRegisteredIn() ) 276 GetRegisteredInNonConst()->Remove( this ); 277 278 SwAccessibleContext::Dispose( bRecursive ); 279 } 280