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_sc.hxx" 26 27 28 #include "AccessibleContextBase.hxx" 29 #include "unoguard.hxx" 30 #include <com/sun/star/accessibility/AccessibleRole.hpp> 31 #include <com/sun/star/accessibility/AccessibleEventId.hpp> 32 #ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLESTATETYPE_HPP_ 33 #include <com/sun/star/accessibility/AccessibleStateType.hpp> 34 #endif 35 #include <com/sun/star/beans/PropertyChangeEvent.hpp> 36 #include <rtl/uuid.h> 37 #include <tools/debug.hxx> 38 #include <tools/gen.hxx> 39 #ifndef _UTL_ACCESSIBLESTATESETHELPER_HXX 40 #include <unotools/accessiblestatesethelper.hxx> 41 #endif 42 #include <toolkit/helper/convert.hxx> 43 #include <svl/smplhint.hxx> 44 #include <comphelper/sequence.hxx> 45 #include <unotools/accessiblerelationsethelper.hxx> 46 #include <vcl/unohelp.hxx> 47 #include <tools/color.hxx> 48 #include <comphelper/accessibleeventnotifier.hxx> 49 50 using namespace ::rtl; 51 using namespace ::com::sun::star; 52 using namespace ::com::sun::star::accessibility; 53 54 //===== internal ============================================================ 55 56 DBG_NAME(ScAccessibleContextBase) 57 58 ScAccessibleContextBase::ScAccessibleContextBase( 59 const uno::Reference<XAccessible>& rxParent, 60 const sal_Int16 aRole) 61 : 62 ScAccessibleContextBaseWeakImpl(m_aMutex), 63 mxParent(rxParent), 64 mnClientId(0), 65 maRole(aRole) 66 { 67 DBG_CTOR(ScAccessibleContextBase, NULL); 68 } 69 70 71 ScAccessibleContextBase::~ScAccessibleContextBase(void) 72 { 73 DBG_DTOR(ScAccessibleContextBase, NULL); 74 75 if (!IsDefunc() && !rBHelper.bInDispose) 76 { 77 // increment refcount to prevent double call off dtor 78 osl_incrementInterlockedCount( &m_refCount ); 79 // call dispose to inform object wich have a weak reference to this object 80 dispose(); 81 } 82 } 83 84 void ScAccessibleContextBase::Init() 85 { 86 // hold reference to make sure that the destructor is not called 87 uno::Reference< XAccessibleContext > xOwnContext(this); 88 89 if (mxParent.is()) 90 { 91 uno::Reference< XAccessibleEventBroadcaster > xBroadcaster (mxParent->getAccessibleContext(), uno::UNO_QUERY); 92 if (xBroadcaster.is()) 93 xBroadcaster->addEventListener(this); 94 } 95 msName = createAccessibleName(); 96 msDescription = createAccessibleDescription(); 97 } 98 99 void SAL_CALL ScAccessibleContextBase::disposing() 100 { 101 ScUnoGuard aGuard; 102 // CommitDefunc(); not necessary and should not be send, because it cost a lot of time 103 104 // hold reference to make sure that the destructor is not called 105 uno::Reference< XAccessibleContext > xOwnContext(this); 106 107 if ( mnClientId ) 108 { 109 sal_Int32 nTemClientId(mnClientId); 110 mnClientId = 0; 111 comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( nTemClientId, *this ); 112 } 113 114 if (mxParent.is()) 115 { 116 uno::Reference< XAccessibleEventBroadcaster > xBroadcaster (mxParent->getAccessibleContext(), uno::UNO_QUERY); 117 if (xBroadcaster.is()) 118 xBroadcaster->removeEventListener(this); 119 mxParent = NULL; 120 } 121 122 ScAccessibleContextBaseWeakImpl::disposing(); 123 } 124 125 //===== XInterface ===================================================== 126 127 uno::Any SAL_CALL ScAccessibleContextBase::queryInterface( uno::Type const & rType ) 128 throw (uno::RuntimeException) 129 { 130 uno::Any aAny (ScAccessibleContextBaseWeakImpl::queryInterface(rType)); 131 return aAny.hasValue() ? aAny : ScAccessibleContextBaseImplEvent::queryInterface(rType); 132 } 133 134 void SAL_CALL ScAccessibleContextBase::acquire() 135 throw () 136 { 137 ScAccessibleContextBaseWeakImpl::acquire(); 138 } 139 140 void SAL_CALL ScAccessibleContextBase::release() 141 throw () 142 { 143 ScAccessibleContextBaseWeakImpl::release(); 144 } 145 146 //===== SfxListener ===================================================== 147 148 void ScAccessibleContextBase::Notify( SfxBroadcaster&, const SfxHint& rHint ) 149 { 150 if (rHint.ISA( SfxSimpleHint ) ) 151 { 152 const SfxSimpleHint& rRef = (const SfxSimpleHint&)rHint; 153 if (rRef.GetId() == SFX_HINT_DYING) 154 { 155 // it seems the Broadcaster is dying, since the view is dying 156 dispose(); 157 } 158 } 159 } 160 161 //===== XAccessible ========================================================= 162 163 uno::Reference< XAccessibleContext> SAL_CALL 164 ScAccessibleContextBase::getAccessibleContext(void) 165 throw (uno::RuntimeException) 166 { 167 return this; 168 } 169 170 //===== XAccessibleComponent ================================================ 171 172 sal_Bool SAL_CALL ScAccessibleContextBase::containsPoint(const awt::Point& rPoint ) 173 throw (uno::RuntimeException) 174 { 175 ScUnoGuard aGuard; 176 IsObjectValid(); 177 return Rectangle (Point(), GetBoundingBox().GetSize()).IsInside(VCLPoint(rPoint)); 178 } 179 180 uno::Reference< XAccessible > SAL_CALL ScAccessibleContextBase::getAccessibleAtPoint( 181 const awt::Point& /* rPoint */ ) 182 throw (uno::RuntimeException) 183 { 184 DBG_ERROR("not implemented"); 185 return uno::Reference<XAccessible>(); 186 } 187 188 awt::Rectangle SAL_CALL ScAccessibleContextBase::getBounds( ) 189 throw (uno::RuntimeException) 190 { 191 ScUnoGuard aGuard; 192 IsObjectValid(); 193 return AWTRectangle(GetBoundingBox()); 194 } 195 196 awt::Point SAL_CALL ScAccessibleContextBase::getLocation( ) 197 throw (uno::RuntimeException) 198 { 199 ScUnoGuard aGuard; 200 IsObjectValid(); 201 return AWTPoint(GetBoundingBox().TopLeft()); 202 } 203 204 awt::Point SAL_CALL ScAccessibleContextBase::getLocationOnScreen( ) 205 throw (uno::RuntimeException) 206 { 207 ScUnoGuard aGuard; 208 IsObjectValid(); 209 return AWTPoint(GetBoundingBoxOnScreen().TopLeft()); 210 } 211 212 awt::Size SAL_CALL ScAccessibleContextBase::getSize( ) 213 throw (uno::RuntimeException) 214 { 215 ScUnoGuard aGuard; 216 IsObjectValid(); 217 return AWTSize(GetBoundingBox().GetSize()); 218 } 219 220 sal_Bool SAL_CALL ScAccessibleContextBase::isShowing( ) 221 throw (uno::RuntimeException) 222 { 223 ScUnoGuard aGuard; 224 IsObjectValid(); 225 sal_Bool bShowing(sal_False); 226 if (mxParent.is()) 227 { 228 uno::Reference<XAccessibleComponent> xParentComponent (mxParent->getAccessibleContext(), uno::UNO_QUERY); 229 if (xParentComponent.is()) 230 { 231 Rectangle aParentBounds(VCLRectangle(xParentComponent->getBounds())); 232 Rectangle aBounds(VCLRectangle(getBounds())); 233 bShowing = aBounds.IsOver(aParentBounds); 234 } 235 } 236 return bShowing; 237 } 238 239 sal_Bool SAL_CALL ScAccessibleContextBase::isVisible( ) 240 throw (uno::RuntimeException) 241 { 242 return sal_True; 243 } 244 245 void SAL_CALL ScAccessibleContextBase::grabFocus( ) 246 throw (uno::RuntimeException) 247 { 248 DBG_ERROR("not implemented"); 249 } 250 251 sal_Int32 SAL_CALL ScAccessibleContextBase::getForeground( ) 252 throw (uno::RuntimeException) 253 { 254 return COL_BLACK; 255 } 256 257 sal_Int32 SAL_CALL ScAccessibleContextBase::getBackground( ) 258 throw (uno::RuntimeException) 259 { 260 return COL_WHITE; 261 } 262 263 //===== XAccessibleContext ================================================== 264 265 sal_Int32 SAL_CALL 266 ScAccessibleContextBase::getAccessibleChildCount(void) 267 throw (uno::RuntimeException) 268 { 269 DBG_ERROR("should be implemented in the abrevated class"); 270 return 0; 271 } 272 273 uno::Reference<XAccessible> SAL_CALL 274 ScAccessibleContextBase::getAccessibleChild(sal_Int32 /* nIndex */) 275 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 276 { 277 DBG_ERROR("should be implemented in the abrevated class"); 278 return uno::Reference<XAccessible>(); 279 } 280 281 uno::Reference<XAccessible> SAL_CALL 282 ScAccessibleContextBase::getAccessibleParent(void) 283 throw (uno::RuntimeException) 284 { 285 return mxParent; 286 } 287 288 sal_Int32 SAL_CALL 289 ScAccessibleContextBase::getAccessibleIndexInParent(void) 290 throw (uno::RuntimeException) 291 { 292 ScUnoGuard aGuard; 293 IsObjectValid(); 294 // Use a simple but slow solution for now. Optimize later. 295 // Return -1 to indicate that this object's parent does not know about the 296 // object. 297 sal_Int32 nIndex(-1); 298 299 // Iterate over all the parent's children and search for this object. 300 if (mxParent.is()) 301 { 302 uno::Reference<XAccessibleContext> xParentContext ( 303 mxParent->getAccessibleContext()); 304 if (xParentContext.is()) 305 { 306 sal_Int32 nChildCount = xParentContext->getAccessibleChildCount(); 307 for (sal_Int32 i=0; i<nChildCount; ++i) 308 { 309 uno::Reference<XAccessible> xChild (xParentContext->getAccessibleChild (i)); 310 if (xChild.is()) 311 { 312 if (xChild.get() == this) 313 nIndex = i; 314 } 315 } 316 } 317 } 318 319 return nIndex; 320 } 321 322 sal_Int16 SAL_CALL 323 ScAccessibleContextBase::getAccessibleRole(void) 324 throw (uno::RuntimeException) 325 { 326 return maRole; 327 } 328 329 ::rtl::OUString SAL_CALL 330 ScAccessibleContextBase::getAccessibleDescription(void) 331 throw (uno::RuntimeException) 332 { 333 ScUnoGuard aGuard; 334 IsObjectValid(); 335 if (!msDescription.getLength()) 336 { 337 OUString sDescription(createAccessibleDescription()); 338 // DBG_ASSERT(sDescription.getLength(), "We should give always a descripition."); 339 340 if (msDescription != sDescription) 341 { 342 AccessibleEventObject aEvent; 343 aEvent.EventId = AccessibleEventId::DESCRIPTION_CHANGED; 344 aEvent.Source = uno::Reference< XAccessibleContext >(this); 345 aEvent.OldValue <<= msDescription; 346 aEvent.NewValue <<= sDescription; 347 348 msDescription = sDescription; 349 350 CommitChange(aEvent); 351 } 352 } 353 return msDescription; 354 } 355 356 OUString SAL_CALL 357 ScAccessibleContextBase::getAccessibleName(void) 358 throw (uno::RuntimeException) 359 { 360 ScUnoGuard aGuard; 361 IsObjectValid(); 362 if (!msName.getLength()) 363 { 364 OUString sName(createAccessibleName()); 365 DBG_ASSERT(sName.getLength(), "We should give always a name."); 366 367 if (msName != sName) 368 { 369 AccessibleEventObject aEvent; 370 aEvent.EventId = AccessibleEventId::NAME_CHANGED; 371 aEvent.Source = uno::Reference< XAccessibleContext >(this); 372 aEvent.OldValue <<= msName; 373 aEvent.NewValue <<= sName; 374 375 msName = sName; 376 377 CommitChange(aEvent); 378 } 379 } 380 return msName; 381 } 382 383 uno::Reference<XAccessibleRelationSet> SAL_CALL 384 ScAccessibleContextBase::getAccessibleRelationSet(void) 385 throw (uno::RuntimeException) 386 { 387 return new utl::AccessibleRelationSetHelper(); 388 } 389 390 uno::Reference<XAccessibleStateSet> SAL_CALL 391 ScAccessibleContextBase::getAccessibleStateSet(void) 392 throw (uno::RuntimeException) 393 { 394 return uno::Reference<XAccessibleStateSet>(); 395 } 396 397 lang::Locale SAL_CALL 398 ScAccessibleContextBase::getLocale(void) 399 throw (IllegalAccessibleComponentStateException, 400 uno::RuntimeException) 401 { 402 ScUnoGuard aGuard; 403 IsObjectValid(); 404 if (mxParent.is()) 405 { 406 uno::Reference<XAccessibleContext> xParentContext ( 407 mxParent->getAccessibleContext()); 408 if (xParentContext.is()) 409 return xParentContext->getLocale (); 410 } 411 412 // No locale and no parent. Therefore throw exception to indicate this 413 // cluelessness. 414 throw IllegalAccessibleComponentStateException (); 415 } 416 417 //===== XAccessibleEventBroadcaster ===================================== 418 419 void SAL_CALL 420 ScAccessibleContextBase::addEventListener( 421 const uno::Reference<XAccessibleEventListener>& xListener) 422 throw (uno::RuntimeException) 423 { 424 if (xListener.is()) 425 { 426 ScUnoGuard aGuard; 427 IsObjectValid(); 428 if (!IsDefunc()) 429 { 430 if (!mnClientId) 431 mnClientId = comphelper::AccessibleEventNotifier::registerClient( ); 432 comphelper::AccessibleEventNotifier::addEventListener( mnClientId, xListener ); 433 } 434 } 435 } 436 437 void SAL_CALL 438 ScAccessibleContextBase::removeEventListener( 439 const uno::Reference<XAccessibleEventListener>& xListener) 440 throw (uno::RuntimeException) 441 { 442 if (xListener.is()) 443 { 444 ScUnoGuard aGuard; 445 if (!IsDefunc() && mnClientId) 446 { 447 sal_Int32 nListenerCount = comphelper::AccessibleEventNotifier::removeEventListener( mnClientId, xListener ); 448 if ( !nListenerCount ) 449 { 450 // no listeners anymore 451 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client), 452 // and at least to us not firing any events anymore, in case somebody calls 453 // NotifyAccessibleEvent, again 454 comphelper::AccessibleEventNotifier::revokeClient( mnClientId ); 455 mnClientId = 0; 456 } 457 } 458 } 459 } 460 461 //===== XAccessibleEventListener ======================================== 462 463 void SAL_CALL ScAccessibleContextBase::disposing( 464 const lang::EventObject& rSource ) 465 throw (uno::RuntimeException) 466 { 467 ScUnoGuard aGuard; 468 if (rSource.Source == mxParent) 469 dispose(); 470 } 471 472 void SAL_CALL ScAccessibleContextBase::notifyEvent( 473 const AccessibleEventObject& /* aEvent */ ) 474 throw (uno::RuntimeException) 475 { 476 } 477 478 //===== XServiceInfo ======================================================== 479 480 ::rtl::OUString SAL_CALL 481 ScAccessibleContextBase::getImplementationName(void) 482 throw (uno::RuntimeException) 483 { 484 return OUString(RTL_CONSTASCII_USTRINGPARAM ("ScAccessibleContextBase")); 485 } 486 487 sal_Bool SAL_CALL 488 ScAccessibleContextBase::supportsService(const OUString& sServiceName) 489 throw (uno::RuntimeException) 490 { 491 // Iterate over all supported service names and return true if on of them 492 // matches the given name. 493 uno::Sequence< ::rtl::OUString> aSupportedServices ( 494 getSupportedServiceNames ()); 495 sal_Int32 nLength(aSupportedServices.getLength()); 496 const OUString* pServiceNames = aSupportedServices.getConstArray(); 497 for (int i=0; i<nLength; ++i, ++pServiceNames) 498 if (sServiceName == *pServiceNames) 499 return sal_True; 500 return sal_False; 501 } 502 503 uno::Sequence< ::rtl::OUString> SAL_CALL 504 ScAccessibleContextBase::getSupportedServiceNames(void) 505 throw (uno::RuntimeException) 506 { 507 uno::Sequence<OUString> aServiceNames(2); 508 OUString* pServiceNames = aServiceNames.getArray(); 509 if (pServiceNames) 510 { 511 pServiceNames[0] = OUString(RTL_CONSTASCII_USTRINGPARAM ("com.sun.star.accessibility.Accessible")); 512 pServiceNames[1] = OUString(RTL_CONSTASCII_USTRINGPARAM ("com.sun.star.accessibility.AccessibleContext")); 513 } 514 515 return aServiceNames; 516 } 517 518 //===== XTypeProvider ======================================================= 519 520 uno::Sequence< uno::Type > SAL_CALL ScAccessibleContextBase::getTypes() 521 throw (uno::RuntimeException) 522 { 523 return comphelper::concatSequences(ScAccessibleContextBaseWeakImpl::getTypes(), ScAccessibleContextBaseImplEvent::getTypes()); 524 } 525 526 uno::Sequence<sal_Int8> SAL_CALL 527 ScAccessibleContextBase::getImplementationId(void) 528 throw (uno::RuntimeException) 529 { 530 ScUnoGuard aGuard; 531 IsObjectValid(); 532 static uno::Sequence<sal_Int8> aId; 533 if (aId.getLength() == 0) 534 { 535 aId.realloc (16); 536 rtl_createUuid (reinterpret_cast<sal_uInt8 *>(aId.getArray()), 0, sal_True); 537 } 538 return aId; 539 } 540 541 //===== internal ============================================================ 542 543 ::rtl::OUString SAL_CALL 544 ScAccessibleContextBase::createAccessibleDescription(void) 545 throw (uno::RuntimeException) 546 { 547 DBG_ERROR("should be implemented in the abrevated class"); 548 return rtl::OUString(); 549 } 550 551 ::rtl::OUString SAL_CALL 552 ScAccessibleContextBase::createAccessibleName(void) 553 throw (uno::RuntimeException) 554 { 555 DBG_ERROR("should be implemented in the abrevated class"); 556 return rtl::OUString(); 557 } 558 559 void ScAccessibleContextBase::CommitChange(const AccessibleEventObject& rEvent) const 560 { 561 if (mnClientId) 562 comphelper::AccessibleEventNotifier::addEvent( mnClientId, rEvent ); 563 } 564 565 void ScAccessibleContextBase::ChangeName() 566 { 567 AccessibleEventObject aEvent; 568 aEvent.EventId = AccessibleEventId::NAME_CHANGED; 569 aEvent.Source = uno::Reference< XAccessibleContext >(const_cast<ScAccessibleContextBase*>(this)); 570 aEvent.OldValue <<= msName; 571 572 msName = rtl::OUString(); // reset the name so it will be hold again 573 getAccessibleName(); // create the new name 574 575 aEvent.NewValue <<= msName; 576 577 CommitChange(aEvent); 578 } 579 580 void ScAccessibleContextBase::CommitFocusGained() const 581 { 582 AccessibleEventObject aEvent; 583 aEvent.EventId = AccessibleEventId::STATE_CHANGED; 584 aEvent.Source = uno::Reference< XAccessibleContext >(const_cast<ScAccessibleContextBase*>(this)); 585 aEvent.NewValue <<= AccessibleStateType::FOCUSED; 586 587 CommitChange(aEvent); 588 589 ::vcl::unohelper::NotifyAccessibleStateEventGlobally(aEvent); 590 } 591 592 void ScAccessibleContextBase::CommitFocusLost() const 593 { 594 AccessibleEventObject aEvent; 595 aEvent.EventId = AccessibleEventId::STATE_CHANGED; 596 aEvent.Source = uno::Reference< XAccessibleContext >(const_cast<ScAccessibleContextBase*>(this)); 597 aEvent.OldValue <<= AccessibleStateType::FOCUSED; 598 599 CommitChange(aEvent); 600 601 vcl::unohelper::NotifyAccessibleStateEventGlobally(aEvent); 602 } 603 604 Rectangle ScAccessibleContextBase::GetBoundingBoxOnScreen(void) const 605 throw (uno::RuntimeException) 606 { 607 DBG_ERROR("not implemented"); 608 return Rectangle(); 609 } 610 611 Rectangle ScAccessibleContextBase::GetBoundingBox(void) const 612 throw (uno::RuntimeException) 613 { 614 DBG_ERROR("not implemented"); 615 return Rectangle(); 616 } 617 618 void ScAccessibleContextBase::IsObjectValid() const 619 throw (lang::DisposedException) 620 { 621 if (rBHelper.bDisposed || rBHelper.bInDispose) 622 throw lang::DisposedException(); 623 } 624 625