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