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_toolkit.hxx" 26 27 28 #include <com/sun/star/accessibility/AccessibleRole.hpp> 29 #include <com/sun/star/accessibility/AccessibleStateType.hpp> 30 #include <com/sun/star/accessibility/AccessibleEventId.hpp> 31 #include <com/sun/star/accessibility/XAccessibleEventListener.hpp> 32 #include <com/sun/star/accessibility/AccessibleRelationType.hpp> 33 #include <toolkit/awt/vclxaccessiblecomponent.hxx> 34 #include <toolkit/helper/externallock.hxx> 35 #include <toolkit/awt/vclxwindow.hxx> 36 #include <toolkit/helper/convert.hxx> 37 #include <toolkit/awt/vclxfont.hxx> 38 #include <vcl/dialog.hxx> 39 #include <vcl/window.hxx> 40 //Solution:Need methods in Edit. 41 #include <vcl/edit.hxx> 42 #include <tools/debug.hxx> 43 #include <unotools/accessiblestatesethelper.hxx> 44 #include <unotools/accessiblerelationsethelper.hxx> 45 #include <vcl/svapp.hxx> 46 #include <vcl/menu.hxx> 47 48 #ifndef VCLEVENT_WINDOW_FRAMETITLECHANGED 49 #define VCLEVENT_WINDOW_FRAMETITLECHANGED 1018 // pData = XubString* = oldTitle 50 #endif 51 52 using namespace ::com::sun::star; 53 using namespace ::comphelper; 54 55 56 DBG_NAME(VCLXAccessibleComponent) 57 58 59 // ---------------------------------------------------- 60 // class VCLXAccessibleComponent 61 // ---------------------------------------------------- 62 VCLXAccessibleComponent::VCLXAccessibleComponent( VCLXWindow* pVCLXindow ) 63 : AccessibleExtendedComponentHelper_BASE( new VCLExternalSolarLock() ) 64 , OAccessibleImplementationAccess( ) 65 { 66 DBG_CTOR( VCLXAccessibleComponent, 0 ); 67 mpVCLXindow = pVCLXindow; 68 mxWindow = pVCLXindow; 69 70 m_pSolarLock = static_cast< VCLExternalSolarLock* >( getExternalLock( ) ); 71 72 DBG_ASSERT( pVCLXindow->GetWindow(), "VCLXAccessibleComponent - no window!" ); 73 if ( pVCLXindow->GetWindow() ) 74 { 75 pVCLXindow->GetWindow()->AddEventListener( LINK( this, VCLXAccessibleComponent, WindowEventListener ) ); 76 pVCLXindow->GetWindow()->AddChildEventListener( LINK( this, VCLXAccessibleComponent, WindowChildEventListener ) ); 77 } 78 79 // announce the XAccessible of our creator to the base class 80 lateInit( pVCLXindow ); 81 } 82 83 VCLXAccessibleComponent::~VCLXAccessibleComponent() 84 { 85 DBG_DTOR( VCLXAccessibleComponent, 0 ); 86 87 ensureDisposed(); 88 89 if ( mpVCLXindow && mpVCLXindow->GetWindow() ) 90 { 91 mpVCLXindow->GetWindow()->RemoveEventListener( LINK( this, VCLXAccessibleComponent, WindowEventListener ) ); 92 mpVCLXindow->GetWindow()->RemoveChildEventListener( LINK( this, VCLXAccessibleComponent, WindowChildEventListener ) ); 93 } 94 95 delete m_pSolarLock; 96 m_pSolarLock = NULL; 97 // This is not completely safe. If we assume that the base class dtor calls some method which 98 // uses this lock, the we crash. However, as the base class' dtor does not have a chance to call _out_ 99 // virtual methods, this is no problem as long as the base class is safe, i.e. does not use the external 100 // lock from within it's dtor. At the moment, we _know_ the base class is safe in this respect, so 101 // let's assume it keeps this way. 102 // @see OAccessibleContextHelper::OAccessibleContextHelper( IMutex* ) 103 } 104 105 IMPLEMENT_FORWARD_XINTERFACE3( VCLXAccessibleComponent, AccessibleExtendedComponentHelper_BASE, OAccessibleImplementationAccess, VCLXAccessibleComponent_BASE ) 106 IMPLEMENT_FORWARD_XTYPEPROVIDER3( VCLXAccessibleComponent, AccessibleExtendedComponentHelper_BASE, OAccessibleImplementationAccess, VCLXAccessibleComponent_BASE ) 107 108 ::rtl::OUString VCLXAccessibleComponent::getImplementationName() throw (uno::RuntimeException) 109 { 110 return ::rtl::OUString::createFromAscii( "com.sun.star.comp.toolkit.AccessibleWindow" ); 111 } 112 113 sal_Bool VCLXAccessibleComponent::supportsService( const ::rtl::OUString& rServiceName ) throw (uno::RuntimeException) 114 { 115 uno::Sequence< ::rtl::OUString > aNames( getSupportedServiceNames() ); 116 const ::rtl::OUString* pNames = aNames.getConstArray(); 117 const ::rtl::OUString* pEnd = pNames + aNames.getLength(); 118 for ( ; pNames != pEnd && !pNames->equals( rServiceName ); ++pNames ) 119 ; 120 121 return pNames != pEnd; 122 } 123 124 uno::Sequence< ::rtl::OUString > VCLXAccessibleComponent::getSupportedServiceNames() throw (uno::RuntimeException) 125 { 126 uno::Sequence< ::rtl::OUString > aNames(1); 127 aNames[0] = ::rtl::OUString::createFromAscii( "com.sun.star.awt.AccessibleWindow" ); 128 return aNames; 129 } 130 131 IMPL_LINK( VCLXAccessibleComponent, WindowEventListener, VclSimpleEvent*, pEvent ) 132 { 133 DBG_CHKTHIS(VCLXAccessibleComponent,0); 134 135 DBG_ASSERT( pEvent && pEvent->ISA( VclWindowEvent ), "Unknown WindowEvent!" ); 136 137 /* Ignore VCLEVENT_WINDOW_ENDPOPUPMODE, because the UNO accessibility wrapper 138 * might have been destroyed by the previous VCLEventListener (if no AT tool 139 * is running), e.g. sub-toolbars in impress. 140 */ 141 if ( pEvent && pEvent->ISA( VclWindowEvent ) && mxWindow.is() /* #122218# */ && (pEvent->GetId() != VCLEVENT_WINDOW_ENDPOPUPMODE) ) 142 { 143 DBG_ASSERT( ((VclWindowEvent*)pEvent)->GetWindow(), "Window???" ); 144 if( !((VclWindowEvent*)pEvent)->GetWindow()->IsAccessibilityEventsSuppressed() || ( pEvent->GetId() == VCLEVENT_OBJECT_DYING ) ) 145 { 146 ProcessWindowEvent( *(VclWindowEvent*)pEvent ); 147 } 148 } 149 return 0; 150 } 151 152 IMPL_LINK( VCLXAccessibleComponent, WindowChildEventListener, VclSimpleEvent*, pEvent ) 153 { 154 DBG_CHKTHIS(VCLXAccessibleComponent,0); 155 156 DBG_ASSERT( pEvent && pEvent->ISA( VclWindowEvent ), "Unknown WindowEvent!" ); 157 if ( pEvent && pEvent->ISA( VclWindowEvent ) && mxWindow.is() /* #i68079# */ ) 158 { 159 DBG_ASSERT( ((VclWindowEvent*)pEvent)->GetWindow(), "Window???" ); 160 if( !((VclWindowEvent*)pEvent)->GetWindow()->IsAccessibilityEventsSuppressed() ) 161 { 162 // #103087# to prevent an early release of the component 163 uno::Reference< accessibility::XAccessibleContext > xTmp = this; 164 165 ProcessWindowChildEvent( *(VclWindowEvent*)pEvent ); 166 } 167 } 168 return 0; 169 } 170 171 uno::Reference< accessibility::XAccessible > VCLXAccessibleComponent::GetChildAccessible( const VclWindowEvent& rVclWindowEvent ) 172 { 173 // checks if the data in the window event is our direct child 174 // and returns its accessible 175 176 // MT: Change this later, normaly a show/hide event shouldn't have the Window* in pData. 177 Window* pChildWindow = (Window *) rVclWindowEvent.GetData(); 178 if( pChildWindow && GetWindow() == pChildWindow->GetAccessibleParentWindow() ) 179 return pChildWindow->GetAccessible( rVclWindowEvent.GetId() == VCLEVENT_WINDOW_SHOW ); 180 else 181 return uno::Reference< accessibility::XAccessible > (); 182 } 183 184 void VCLXAccessibleComponent::ProcessWindowChildEvent( const VclWindowEvent& rVclWindowEvent ) 185 { 186 uno::Any aOldValue, aNewValue; 187 uno::Reference< accessibility::XAccessible > xAcc; 188 189 switch ( rVclWindowEvent.GetId() ) 190 { 191 case VCLEVENT_WINDOW_SHOW: // send create on show for direct accessible children 192 { 193 xAcc = GetChildAccessible( rVclWindowEvent ); 194 if( xAcc.is() ) 195 { 196 aNewValue <<= xAcc; 197 NotifyAccessibleEvent( accessibility::AccessibleEventId::CHILD, aOldValue, aNewValue ); 198 } 199 } 200 break; 201 case VCLEVENT_WINDOW_HIDE: // send destroy on hide for direct accessible children 202 { 203 xAcc = GetChildAccessible( rVclWindowEvent ); 204 if( xAcc.is() ) 205 { 206 aOldValue <<= xAcc; 207 NotifyAccessibleEvent( accessibility::AccessibleEventId::CHILD, aOldValue, aNewValue ); 208 } 209 } 210 break; 211 } 212 } 213 214 void VCLXAccessibleComponent::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent ) 215 { 216 uno::Any aOldValue, aNewValue; 217 218 Window* pAccWindow = rVclWindowEvent.GetWindow(); 219 DBG_ASSERT( pAccWindow, "VCLXAccessibleComponent::ProcessWindowEvent - Window?" ); 220 221 switch ( rVclWindowEvent.GetId() ) 222 { 223 case VCLEVENT_OBJECT_DYING: 224 { 225 pAccWindow->RemoveEventListener( LINK( this, VCLXAccessibleComponent, WindowEventListener ) ); 226 pAccWindow->RemoveChildEventListener( LINK( this, VCLXAccessibleComponent, WindowChildEventListener ) ); 227 mxWindow.clear(); 228 mpVCLXindow = NULL; 229 } 230 break; 231 // 232 // dont handle CHILDCREATED events here 233 // they are handled separately as child events, see ProcessWindowChildEvent above 234 // 235 /* 236 case VCLEVENT_WINDOW_CHILDCREATED: 237 { 238 Window* pWindow = (Window*) rVclWindowEvent.GetData(); 239 DBG_ASSERT( pWindow, "VCLEVENT_WINDOW_CHILDCREATED - Window=?" ); 240 aNewValue <<= pWindow->GetAccessible(); 241 NotifyAccessibleEvent( accessibility::AccessibleEventId::CHILD, aOldValue, aNewValue ); 242 } 243 break; 244 */ 245 case VCLEVENT_WINDOW_CHILDDESTROYED: 246 { 247 Window* pWindow = (Window*) rVclWindowEvent.GetData(); 248 DBG_ASSERT( pWindow, "VCLEVENT_WINDOW_CHILDDESTROYED - Window=?" ); 249 if ( pWindow->GetAccessible( sal_False ).is() ) 250 { 251 aOldValue <<= pWindow->GetAccessible( sal_False ); 252 NotifyAccessibleEvent( accessibility::AccessibleEventId::CHILD, aOldValue, aNewValue ); 253 } 254 } 255 break; 256 257 // 258 // show and hide will be handled as child events only and are 259 // responsible for sending create/destroy events, see ProcessWindowChildEvent above 260 // 261 /* 262 case VCLEVENT_WINDOW_SHOW: 263 { 264 aNewValue <<= accessibility::AccessibleStateType::VISIBLE; 265 NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue ); 266 267 aNewValue <<= accessibility::AccessibleStateType::SHOWING; 268 NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue ); 269 270 aNewValue.clear(); 271 aOldValue <<= accessibility::AccessibleStateType::INVALID; 272 NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue ); 273 } 274 break; 275 case VCLEVENT_WINDOW_HIDE: 276 { 277 aOldValue <<= accessibility::AccessibleStateType::VISIBLE; 278 NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue ); 279 280 aOldValue <<= accessibility::AccessibleStateType::SHOWING; 281 NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue ); 282 283 aOldValue.clear(); 284 aNewValue <<= accessibility::AccessibleStateType::INVALID; 285 NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue ); 286 } 287 break; 288 */ 289 case VCLEVENT_WINDOW_ACTIVATE: 290 { 291 // avoid notification if a child frame is already active 292 // only one frame may be active at a given time 293 if ( !pAccWindow->HasActiveChildFrame() && 294 ( getAccessibleRole() == accessibility::AccessibleRole::FRAME || 295 getAccessibleRole() == accessibility::AccessibleRole::ALERT || 296 getAccessibleRole() == accessibility::AccessibleRole::DIALOG ) ) // #i18891# 297 { 298 aNewValue <<= accessibility::AccessibleStateType::ACTIVE; 299 NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue ); 300 } 301 } 302 break; 303 case VCLEVENT_WINDOW_DEACTIVATE: 304 { 305 if ( getAccessibleRole() == accessibility::AccessibleRole::FRAME || 306 getAccessibleRole() == accessibility::AccessibleRole::ALERT || 307 getAccessibleRole() == accessibility::AccessibleRole::DIALOG ) // #i18891# 308 { 309 aOldValue <<= accessibility::AccessibleStateType::ACTIVE; 310 NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue ); 311 } 312 } 313 break; 314 case VCLEVENT_WINDOW_GETFOCUS: 315 case VCLEVENT_CONTROL_GETFOCUS: 316 { 317 if( (pAccWindow->IsCompoundControl() && rVclWindowEvent.GetId() == VCLEVENT_CONTROL_GETFOCUS) || 318 (!pAccWindow->IsCompoundControl() && rVclWindowEvent.GetId() == VCLEVENT_WINDOW_GETFOCUS) ) 319 { 320 // if multiple listeners were registered it is possible that the 321 // focus was changed during event processing (eg SfxTopWindow ) 322 // #106082# allow ChildPathFocus only for CompoundControls, for windows the focus must be in the window itself 323 if( (pAccWindow->IsCompoundControl() && pAccWindow->HasChildPathFocus()) || 324 (!pAccWindow->IsCompoundControl() && pAccWindow->HasFocus()) ) 325 { 326 aNewValue <<= accessibility::AccessibleStateType::FOCUSED; 327 NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue ); 328 } 329 } 330 } 331 break; 332 case VCLEVENT_WINDOW_LOSEFOCUS: 333 case VCLEVENT_CONTROL_LOSEFOCUS: 334 { 335 if( (pAccWindow->IsCompoundControl() && rVclWindowEvent.GetId() == VCLEVENT_CONTROL_LOSEFOCUS) || 336 (!pAccWindow->IsCompoundControl() && rVclWindowEvent.GetId() == VCLEVENT_WINDOW_LOSEFOCUS) ) 337 { 338 aOldValue <<= accessibility::AccessibleStateType::FOCUSED; 339 NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue ); 340 } 341 } 342 break; 343 case VCLEVENT_WINDOW_FRAMETITLECHANGED: 344 { 345 ::rtl::OUString aOldName( *((::rtl::OUString*) rVclWindowEvent.GetData()) ); 346 ::rtl::OUString aNewName( getAccessibleName() ); 347 aOldValue <<= aOldName; 348 aNewValue <<= aNewName; 349 NotifyAccessibleEvent( accessibility::AccessibleEventId::NAME_CHANGED, aOldValue, aNewValue ); 350 } 351 break; 352 case VCLEVENT_WINDOW_ENABLED: 353 { 354 aNewValue <<= accessibility::AccessibleStateType::ENABLED; 355 NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue ); 356 aNewValue <<= accessibility::AccessibleStateType::SENSITIVE; 357 NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue ); 358 } 359 break; 360 case VCLEVENT_WINDOW_DISABLED: 361 { 362 aOldValue <<= accessibility::AccessibleStateType::SENSITIVE; 363 NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue ); 364 365 aOldValue <<= accessibility::AccessibleStateType::ENABLED; 366 NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue ); 367 } 368 break; 369 case VCLEVENT_WINDOW_MOVE: 370 case VCLEVENT_WINDOW_RESIZE: 371 { 372 NotifyAccessibleEvent( accessibility::AccessibleEventId::BOUNDRECT_CHANGED, aOldValue, aNewValue ); 373 } 374 break; 375 case VCLEVENT_WINDOW_MENUBARADDED: 376 { 377 MenuBar* pMenuBar = (MenuBar*) rVclWindowEvent.GetData(); 378 if ( pMenuBar ) 379 { 380 uno::Reference< accessibility::XAccessible > xChild( pMenuBar->GetAccessible() ); 381 if ( xChild.is() ) 382 { 383 aNewValue <<= xChild; 384 NotifyAccessibleEvent( accessibility::AccessibleEventId::CHILD, aOldValue, aNewValue ); 385 } 386 } 387 } 388 break; 389 case VCLEVENT_WINDOW_MENUBARREMOVED: 390 { 391 MenuBar* pMenuBar = (MenuBar*) rVclWindowEvent.GetData(); 392 if ( pMenuBar ) 393 { 394 uno::Reference< accessibility::XAccessible > xChild( pMenuBar->GetAccessible() ); 395 if ( xChild.is() ) 396 { 397 aOldValue <<= xChild; 398 NotifyAccessibleEvent( accessibility::AccessibleEventId::CHILD, aOldValue, aNewValue ); 399 } 400 } 401 } 402 break; 403 case VCLEVENT_WINDOW_MINIMIZE: 404 { 405 aNewValue <<= accessibility::AccessibleStateType::ICONIFIED; 406 NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue ); 407 } 408 break; 409 case VCLEVENT_WINDOW_NORMALIZE: 410 { 411 aOldValue <<= accessibility::AccessibleStateType::ICONIFIED; 412 NotifyAccessibleEvent( accessibility::AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue ); 413 } 414 break; 415 default: 416 { 417 } 418 break; 419 } 420 } 421 422 void VCLXAccessibleComponent::disposing() 423 { 424 if ( mpVCLXindow && mpVCLXindow->GetWindow() ) 425 { 426 mpVCLXindow->GetWindow()->RemoveEventListener( LINK( this, VCLXAccessibleComponent, WindowEventListener ) ); 427 mpVCLXindow->GetWindow()->RemoveChildEventListener( LINK( this, VCLXAccessibleComponent, WindowChildEventListener ) ); 428 } 429 430 AccessibleExtendedComponentHelper_BASE::disposing(); 431 432 mxWindow.clear(); 433 mpVCLXindow = NULL; 434 } 435 436 Window* VCLXAccessibleComponent::GetWindow() const 437 { 438 return GetVCLXWindow() ? GetVCLXWindow()->GetWindow() : NULL; 439 } 440 441 void VCLXAccessibleComponent::FillAccessibleRelationSet( utl::AccessibleRelationSetHelper& rRelationSet ) 442 { 443 Window* pWindow = GetWindow(); 444 if ( pWindow ) 445 { 446 Window *pLabeledBy = pWindow->GetAccessibleRelationLabeledBy(); 447 if ( pLabeledBy && pLabeledBy != pWindow ) 448 { 449 uno::Sequence< uno::Reference< uno::XInterface > > aSequence(1); 450 aSequence[0] = pLabeledBy->GetAccessible(); 451 rRelationSet.AddRelation( accessibility::AccessibleRelation( accessibility::AccessibleRelationType::LABELED_BY, aSequence ) ); 452 } 453 454 Window* pLabelFor = pWindow->GetAccessibleRelationLabelFor(); 455 if ( pLabelFor && pLabelFor != pWindow ) 456 { 457 uno::Sequence< uno::Reference< uno::XInterface > > aSequence(1); 458 aSequence[0] = pLabelFor->GetAccessible(); 459 rRelationSet.AddRelation( accessibility::AccessibleRelation( accessibility::AccessibleRelationType::LABEL_FOR, aSequence ) ); 460 } 461 Window* pMemberOf = pWindow->GetAccessibleRelationMemberOf(); 462 if ( pMemberOf && pMemberOf != pWindow ) 463 { 464 uno::Sequence< uno::Reference< uno::XInterface > > aSequence(1); 465 aSequence[0] = pMemberOf->GetAccessible(); 466 rRelationSet.AddRelation( accessibility::AccessibleRelation( accessibility::AccessibleRelationType::MEMBER_OF, aSequence ) ); 467 } 468 uno::Sequence< uno::Reference< uno::XInterface > > aFlowToSequence = pWindow->GetAccFlowToSequence(); 469 if( aFlowToSequence.getLength() > 0 ) 470 { 471 rRelationSet.AddRelation( accessibility::AccessibleRelation( accessibility::AccessibleRelationType::CONTENT_FLOWS_TO, aFlowToSequence ) ); 472 } 473 } 474 } 475 476 void VCLXAccessibleComponent::FillAccessibleStateSet( utl::AccessibleStateSetHelper& rStateSet ) 477 { 478 Window* pWindow = GetWindow(); 479 if ( pWindow ) 480 { 481 if ( pWindow->IsVisible() ) 482 { 483 rStateSet.AddState( accessibility::AccessibleStateType::VISIBLE ); 484 rStateSet.AddState( accessibility::AccessibleStateType::SHOWING ); 485 } 486 else 487 { 488 rStateSet.AddState( accessibility::AccessibleStateType::INVALID ); 489 } 490 491 if ( pWindow->IsEnabled() ) 492 { 493 rStateSet.AddState( accessibility::AccessibleStateType::ENABLED ); 494 rStateSet.AddState( accessibility::AccessibleStateType::SENSITIVE ); 495 } 496 497 if ( pWindow->HasChildPathFocus() && 498 ( getAccessibleRole() == accessibility::AccessibleRole::FRAME || 499 getAccessibleRole() == accessibility::AccessibleRole::ALERT || 500 getAccessibleRole() == accessibility::AccessibleRole::DIALOG ) ) // #i18891# 501 rStateSet.AddState( accessibility::AccessibleStateType::ACTIVE ); 502 503 // #104290# MT: This way, a ComboBox doesn't get state FOCUSED. 504 // I also don't understand 505 // a) why WINDOW_FIRSTCHILD is used here (which btw is a border window in the case of a combo box) 506 // b) why HasFocus() is nout "enough" for a compound control 507 /* 508 Window* pChild = pWindow->GetWindow( WINDOW_FIRSTCHILD ); 509 if ( ( !pWindow->IsCompoundControl() && pWindow->HasFocus() ) || 510 ( pWindow->IsCompoundControl() && pChild && pChild->HasFocus() ) ) 511 rStateSet.AddState( accessibility::AccessibleStateType::FOCUSED ); 512 */ 513 if ( pWindow->HasFocus() || ( pWindow->IsCompoundControl() && pWindow->HasChildPathFocus() ) ) 514 rStateSet.AddState( accessibility::AccessibleStateType::FOCUSED ); 515 516 if ( pWindow->IsWait() ) 517 rStateSet.AddState( accessibility::AccessibleStateType::BUSY ); 518 519 if ( pWindow->GetStyle() & WB_SIZEABLE ) 520 rStateSet.AddState( accessibility::AccessibleStateType::RESIZABLE ); 521 // 6. frame doesn't have MOVABLE state 522 // 10. for password text, where is the sensitive state? 523 if( ( getAccessibleRole() == accessibility::AccessibleRole::FRAME ||getAccessibleRole() == accessibility::AccessibleRole::DIALOG )&& pWindow->GetStyle() & WB_MOVEABLE ) 524 rStateSet.AddState( accessibility::AccessibleStateType::MOVEABLE ); 525 if( pWindow->IsDialog() ) 526 { 527 Dialog *pDlg = static_cast< Dialog* >( pWindow ); 528 if( pDlg->IsInExecute() ) 529 rStateSet.AddState( accessibility::AccessibleStateType::MODAL ); 530 } 531 //Solution:If a combobox or list's edit child isn't read-only,EDITABLE state 532 // should be set. 533 if( pWindow && pWindow->GetType() == WINDOW_COMBOBOX ) 534 { 535 if( !( pWindow->GetStyle() & WB_READONLY) || 536 !((Edit*)pWindow)->IsReadOnly() ) 537 rStateSet.AddState( accessibility::AccessibleStateType::EDITABLE ); 538 } 539 540 Window* pChild = pWindow->GetWindow( WINDOW_FIRSTCHILD ); 541 542 while( pWindow && pChild ) 543 { 544 Window* pWinTemp = pChild->GetWindow( WINDOW_FIRSTCHILD ); 545 if( pWinTemp && pWinTemp->GetType() == WINDOW_EDIT ) 546 { 547 if( !( pWinTemp->GetStyle() & WB_READONLY) || 548 !((Edit*)pWinTemp)->IsReadOnly() ) 549 rStateSet.AddState( accessibility::AccessibleStateType::EDITABLE ); 550 break; 551 } 552 if( pChild->GetType() == WINDOW_EDIT ) 553 { 554 if( !( pChild->GetStyle() & WB_READONLY) || 555 !((Edit*)pChild)->IsReadOnly()) 556 rStateSet.AddState( accessibility::AccessibleStateType::EDITABLE ); 557 break; 558 } 559 pChild = pChild->GetWindow( WINDOW_NEXT ); 560 } 561 } 562 else 563 { 564 rStateSet.AddState( accessibility::AccessibleStateType::DEFUNC ); 565 } 566 567 /* 568 569 MUST BE SET FROM DERIVED CLASSES: 570 571 CHECKED 572 COLLAPSED 573 EXPANDED 574 EXPANDABLE 575 EDITABLE 576 FOCUSABLE 577 HORIZONTAL 578 VERTICAL 579 ICONIFIED 580 MULTILINE 581 MULTI_SELECTABLE 582 PRESSED 583 SELECTABLE 584 SELECTED 585 SINGLE_LINE 586 TRANSIENT 587 588 */ 589 } 590 591 592 // accessibility::XAccessibleContext 593 sal_Int32 VCLXAccessibleComponent::getAccessibleChildCount() throw (uno::RuntimeException) 594 { 595 OExternalLockGuard aGuard( this ); 596 597 sal_Int32 nChildren = 0; 598 if ( GetWindow() ) 599 nChildren = GetWindow()->GetAccessibleChildWindowCount(); 600 601 return nChildren; 602 } 603 604 uno::Reference< accessibility::XAccessible > VCLXAccessibleComponent::getAccessibleChild( sal_Int32 i ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 605 { 606 OExternalLockGuard aGuard( this ); 607 608 if ( i >= getAccessibleChildCount() ) 609 throw lang::IndexOutOfBoundsException(); 610 611 uno::Reference< accessibility::XAccessible > xAcc; 612 if ( GetWindow() ) 613 { 614 Window* pChild = GetWindow()->GetAccessibleChildWindow( (sal_uInt16)i ); 615 if ( pChild ) 616 xAcc = pChild->GetAccessible(); 617 } 618 619 return xAcc; 620 } 621 622 uno::Reference< accessibility::XAccessible > VCLXAccessibleComponent::getVclParent() const 623 { 624 uno::Reference< accessibility::XAccessible > xAcc; 625 if ( GetWindow() ) 626 { 627 Window* pParent = GetWindow()->GetAccessibleParentWindow(); 628 if ( pParent ) 629 xAcc = pParent->GetAccessible(); 630 } 631 return xAcc; 632 } 633 634 uno::Reference< accessibility::XAccessible > VCLXAccessibleComponent::getAccessibleParent( ) throw (uno::RuntimeException) 635 { 636 OExternalLockGuard aGuard( this ); 637 638 uno::Reference< accessibility::XAccessible > xAcc( implGetForeignControlledParent() ); 639 if ( !xAcc.is() ) 640 // we do _not_ have a foreign-controlled parent -> default to our VCL parent 641 xAcc = getVclParent(); 642 643 return xAcc; 644 } 645 646 sal_Int32 VCLXAccessibleComponent::getAccessibleIndexInParent( ) throw (uno::RuntimeException) 647 { 648 OExternalLockGuard aGuard( this ); 649 650 sal_Int32 nIndex = -1; 651 652 uno::Reference< accessibility::XAccessible > xAcc( implGetForeignControlledParent() ); 653 if ( xAcc.is() ) 654 { // we _do_ have a foreign-controlled parent -> use the base class' implementation, 655 // which goes the UNO way 656 nIndex = AccessibleExtendedComponentHelper_BASE::getAccessibleIndexInParent( ); 657 } 658 else 659 { 660 if ( GetWindow() ) 661 { 662 Window* pParent = GetWindow()->GetAccessibleParentWindow(); 663 if ( pParent ) 664 { 665 /* 666 for ( sal_uInt16 n = pParent->GetAccessibleChildWindowCount(); n; ) 667 { 668 Window* pChild = pParent->GetAccessibleChildWindow( --n ); 669 if ( pChild == GetWindow() ) 670 { 671 nIndex = n; 672 break; 673 } 674 } 675 */ 676 // Iterate over all the parent's children and search for this object. 677 // this should be compatible with the code in SVX 678 uno::Reference< accessibility::XAccessible > xParentAcc( pParent->GetAccessible() ); 679 if ( xParentAcc.is() ) 680 { 681 uno::Reference< accessibility::XAccessibleContext > xParentContext ( xParentAcc->getAccessibleContext() ); 682 if ( xParentContext.is() ) 683 { 684 sal_Int32 nChildCount = xParentContext->getAccessibleChildCount(); 685 for ( sal_Int32 i=0; i<nChildCount; i++ ) 686 { 687 uno::Reference< accessibility::XAccessible > xChild( xParentContext->getAccessibleChild(i) ); 688 if ( xChild.is() ) 689 { 690 uno::Reference< accessibility::XAccessibleContext > xChildContext = xChild->getAccessibleContext(); 691 if ( xChildContext == (accessibility::XAccessibleContext*) this ) 692 { 693 nIndex = i; 694 break; 695 } 696 } 697 } 698 } 699 } 700 } 701 } 702 } 703 return nIndex; 704 } 705 706 sal_Int16 VCLXAccessibleComponent::getAccessibleRole( ) throw (uno::RuntimeException) 707 { 708 OExternalLockGuard aGuard( this ); 709 710 sal_Int16 nRole = 0; 711 712 if ( GetWindow() ) 713 nRole = GetWindow()->GetAccessibleRole(); 714 715 return nRole; 716 } 717 718 ::rtl::OUString VCLXAccessibleComponent::getAccessibleDescription( ) throw (uno::RuntimeException) 719 { 720 OExternalLockGuard aGuard( this ); 721 722 ::rtl::OUString aDescription; 723 724 if ( GetWindow() ) 725 aDescription = GetWindow()->GetAccessibleDescription(); 726 727 return aDescription; 728 } 729 730 ::rtl::OUString VCLXAccessibleComponent::getAccessibleName( ) throw (uno::RuntimeException) 731 { 732 OExternalLockGuard aGuard( this ); 733 734 ::rtl::OUString aName; 735 if ( GetWindow() ) 736 { 737 aName = GetWindow()->GetAccessibleName(); 738 #if OSL_DEBUG_LEVEL > 1 739 aName += String( RTL_CONSTASCII_USTRINGPARAM( " (Type = " ) ); 740 aName += String::CreateFromInt32( GetWindow()->GetType() ); 741 aName += String( RTL_CONSTASCII_USTRINGPARAM( ")" ) ); 742 #endif 743 } 744 return aName; 745 } 746 747 uno::Reference< accessibility::XAccessibleRelationSet > VCLXAccessibleComponent::getAccessibleRelationSet( ) throw (uno::RuntimeException) 748 { 749 OExternalLockGuard aGuard( this ); 750 751 utl::AccessibleRelationSetHelper* pRelationSetHelper = new utl::AccessibleRelationSetHelper; 752 uno::Reference< accessibility::XAccessibleRelationSet > xSet = pRelationSetHelper; 753 FillAccessibleRelationSet( *pRelationSetHelper ); 754 return xSet; 755 } 756 757 uno::Reference< accessibility::XAccessibleStateSet > VCLXAccessibleComponent::getAccessibleStateSet( ) throw (uno::RuntimeException) 758 { 759 OExternalLockGuard aGuard( this ); 760 761 utl::AccessibleStateSetHelper* pStateSetHelper = new utl::AccessibleStateSetHelper; 762 uno::Reference< accessibility::XAccessibleStateSet > xSet = pStateSetHelper; 763 FillAccessibleStateSet( *pStateSetHelper ); 764 return xSet; 765 } 766 767 lang::Locale VCLXAccessibleComponent::getLocale() throw (accessibility::IllegalAccessibleComponentStateException, uno::RuntimeException) 768 { 769 OExternalLockGuard aGuard( this ); 770 771 return Application::GetSettings().GetLocale(); 772 } 773 774 uno::Reference< accessibility::XAccessible > VCLXAccessibleComponent::getAccessibleAtPoint( const awt::Point& rPoint ) throw (uno::RuntimeException) 775 { 776 OExternalLockGuard aGuard( this ); 777 778 uno::Reference< accessibility::XAccessible > xChild; 779 for ( sal_uInt32 i = 0, nCount = getAccessibleChildCount(); i < nCount; ++i ) 780 { 781 uno::Reference< accessibility::XAccessible > xAcc = getAccessibleChild( i ); 782 if ( xAcc.is() ) 783 { 784 uno::Reference< accessibility::XAccessibleComponent > xComp( xAcc->getAccessibleContext(), uno::UNO_QUERY ); 785 if ( xComp.is() ) 786 { 787 Rectangle aRect = VCLRectangle( xComp->getBounds() ); 788 Point aPos = VCLPoint( rPoint ); 789 if ( aRect.IsInside( aPos ) ) 790 { 791 xChild = xAcc; 792 break; 793 } 794 } 795 } 796 } 797 798 return xChild; 799 } 800 801 // accessibility::XAccessibleComponent 802 awt::Rectangle VCLXAccessibleComponent::implGetBounds() throw (uno::RuntimeException) 803 { 804 awt::Rectangle aBounds ( 0, 0, 0, 0 ); 805 806 Window* pWindow = GetWindow(); 807 if ( pWindow ) 808 { 809 Rectangle aRect = pWindow->GetWindowExtentsRelative( NULL ); 810 aBounds = AWTRectangle( aRect ); 811 Window* pParent = pWindow->GetAccessibleParentWindow(); 812 if ( pParent ) 813 { 814 Rectangle aParentRect = pParent->GetWindowExtentsRelative( NULL ); 815 awt::Point aParentScreenLoc = AWTPoint( aParentRect.TopLeft() ); 816 aBounds.X -= aParentScreenLoc.X; 817 aBounds.Y -= aParentScreenLoc.Y; 818 } 819 } 820 821 uno::Reference< accessibility::XAccessible > xParent( implGetForeignControlledParent() ); 822 if ( xParent.is() ) 823 { // hmm, we can't rely on our VCL coordinates, as in the Accessibility Hierarchy, somebody gave 824 // us a parent which is different from our VCL parent 825 // (actually, we did not check if it's really different ...) 826 827 // the screen location of the foreign parent 828 uno::Reference< accessibility::XAccessibleComponent > xParentComponent( xParent->getAccessibleContext(), uno::UNO_QUERY ); 829 DBG_ASSERT( xParentComponent.is(), "VCLXAccessibleComponent::implGetBounds: invalid (foreign) parent component!" ); 830 831 awt::Point aScreenLocForeign( 0, 0 ); 832 if ( xParentComponent.is() ) 833 aScreenLocForeign = xParentComponent->getLocationOnScreen(); 834 835 // the screen location of the VCL parent 836 xParent = getVclParent(); 837 if ( xParent.is() ) 838 xParentComponent = xParentComponent.query( xParent->getAccessibleContext() ); 839 840 awt::Point aScreenLocVCL( 0, 0 ); 841 if ( xParentComponent.is() ) 842 aScreenLocVCL = xParentComponent->getLocationOnScreen(); 843 844 // the difference between them 845 awt::Size aOffset( aScreenLocVCL.X - aScreenLocForeign.X, aScreenLocVCL.Y - aScreenLocForeign.Y ); 846 // move the bounds 847 aBounds.X += aOffset.Width; 848 aBounds.Y += aOffset.Height; 849 } 850 851 return aBounds; 852 } 853 854 awt::Point VCLXAccessibleComponent::getLocationOnScreen( ) throw (uno::RuntimeException) 855 { 856 OExternalLockGuard aGuard( this ); 857 858 awt::Point aPos; 859 if ( GetWindow() ) 860 { 861 Rectangle aRect = GetWindow()->GetWindowExtentsRelative( NULL ); 862 aPos.X = aRect.Left(); 863 aPos.Y = aRect.Top(); 864 } 865 866 return aPos; 867 } 868 869 void VCLXAccessibleComponent::grabFocus( ) throw (uno::RuntimeException) 870 { 871 OExternalLockGuard aGuard( this ); 872 873 uno::Reference< accessibility::XAccessibleStateSet > xStates = getAccessibleStateSet(); 874 if ( mxWindow.is() && xStates.is() && xStates->contains( accessibility::AccessibleStateType::FOCUSABLE ) ) 875 mxWindow->setFocus(); 876 } 877 878 sal_Int32 SAL_CALL VCLXAccessibleComponent::getForeground( ) throw (uno::RuntimeException) 879 { 880 OExternalLockGuard aGuard( this ); 881 882 sal_Int32 nColor = 0; 883 Window* pWindow = GetWindow(); 884 if ( pWindow ) 885 { 886 if ( pWindow->IsControlForeground() ) 887 nColor = pWindow->GetControlForeground().GetColor(); 888 else 889 { 890 Font aFont; 891 if ( pWindow->IsControlFont() ) 892 aFont = pWindow->GetControlFont(); 893 else 894 aFont = pWindow->GetFont(); 895 nColor = aFont.GetColor().GetColor(); 896 // COL_AUTO is not very meaningful for AT 897 if ( nColor == (sal_Int32)COL_AUTO) 898 nColor = pWindow->GetTextColor().GetColor(); 899 } 900 } 901 902 return nColor; 903 } 904 905 sal_Int32 SAL_CALL VCLXAccessibleComponent::getBackground( ) throw (uno::RuntimeException) 906 { 907 OExternalLockGuard aGuard( this ); 908 909 sal_Int32 nColor = 0; 910 Window* pWindow = GetWindow(); 911 if ( pWindow ) 912 { 913 if ( pWindow->IsControlBackground() ) 914 nColor = pWindow->GetControlBackground().GetColor(); 915 else 916 nColor = pWindow->GetBackground().GetColor().GetColor(); 917 } 918 919 return nColor; 920 } 921 922 // XAccessibleExtendedComponent 923 924 uno::Reference< awt::XFont > SAL_CALL VCLXAccessibleComponent::getFont( ) throw (uno::RuntimeException) 925 { 926 OExternalLockGuard aGuard( this ); 927 928 uno::Reference< awt::XFont > xFont; 929 Window* pWindow = GetWindow(); 930 if ( pWindow ) 931 { 932 uno::Reference< awt::XDevice > xDev( pWindow->GetComponentInterface(), uno::UNO_QUERY ); 933 if ( xDev.is() ) 934 { 935 Font aFont; 936 if ( pWindow->IsControlFont() ) 937 aFont = pWindow->GetControlFont(); 938 else 939 aFont = pWindow->GetFont(); 940 VCLXFont* pVCLXFont = new VCLXFont; 941 pVCLXFont->Init( *xDev.get(), aFont ); 942 xFont = pVCLXFont; 943 } 944 } 945 946 return xFont; 947 } 948 949 ::rtl::OUString SAL_CALL VCLXAccessibleComponent::getTitledBorderText( ) throw (uno::RuntimeException) 950 { 951 OExternalLockGuard aGuard( this ); 952 953 ::rtl::OUString sRet; 954 if ( GetWindow() ) 955 sRet = GetWindow()->GetText(); 956 957 return sRet; 958 } 959 960 ::rtl::OUString SAL_CALL VCLXAccessibleComponent::getToolTipText( ) throw (uno::RuntimeException) 961 { 962 OExternalLockGuard aGuard( this ); 963 964 ::rtl::OUString sRet; 965 if ( GetWindow() ) 966 sRet = GetWindow()->GetQuickHelpText(); 967 968 return sRet; 969 } 970 971