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 which 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 { 129 uno::Any aAny (ScAccessibleContextBaseWeakImpl::queryInterface(rType)); 130 return aAny.hasValue() ? aAny : ScAccessibleContextBaseImplEvent::queryInterface(rType); 131 } 132 133 void SAL_CALL ScAccessibleContextBase::acquire() 134 throw () 135 { 136 ScAccessibleContextBaseWeakImpl::acquire(); 137 } 138 139 void SAL_CALL ScAccessibleContextBase::release() 140 throw () 141 { 142 ScAccessibleContextBaseWeakImpl::release(); 143 } 144 145 //===== SfxListener ===================================================== 146 147 void ScAccessibleContextBase::Notify( SfxBroadcaster&, const SfxHint& rHint ) 148 { 149 if (rHint.ISA( SfxSimpleHint ) ) 150 { 151 const SfxSimpleHint& rRef = (const SfxSimpleHint&)rHint; 152 if (rRef.GetId() == SFX_HINT_DYING) 153 { 154 // it seems the Broadcaster is dying, since the view is dying 155 dispose(); 156 } 157 } 158 } 159 160 //===== XAccessible ========================================================= 161 162 uno::Reference< XAccessibleContext> SAL_CALL 163 ScAccessibleContextBase::getAccessibleContext(void) 164 { 165 return this; 166 } 167 168 //===== XAccessibleComponent ================================================ 169 170 sal_Bool SAL_CALL ScAccessibleContextBase::containsPoint(const awt::Point& rPoint ) 171 { 172 ScUnoGuard aGuard; 173 IsObjectValid(); 174 return Rectangle (Point(), GetBoundingBox().GetSize()).IsInside(VCLPoint(rPoint)); 175 } 176 177 uno::Reference< XAccessible > SAL_CALL ScAccessibleContextBase::getAccessibleAtPoint( 178 const awt::Point& /* rPoint */ ) 179 { 180 DBG_ERROR("not implemented"); 181 return uno::Reference<XAccessible>(); 182 } 183 184 awt::Rectangle SAL_CALL ScAccessibleContextBase::getBounds( ) 185 { 186 ScUnoGuard aGuard; 187 IsObjectValid(); 188 return AWTRectangle(GetBoundingBox()); 189 } 190 191 awt::Point SAL_CALL ScAccessibleContextBase::getLocation( ) 192 { 193 ScUnoGuard aGuard; 194 IsObjectValid(); 195 return AWTPoint(GetBoundingBox().TopLeft()); 196 } 197 198 awt::Point SAL_CALL ScAccessibleContextBase::getLocationOnScreen( ) 199 { 200 ScUnoGuard aGuard; 201 IsObjectValid(); 202 return AWTPoint(GetBoundingBoxOnScreen().TopLeft()); 203 } 204 205 awt::Size SAL_CALL ScAccessibleContextBase::getSize( ) 206 { 207 ScUnoGuard aGuard; 208 IsObjectValid(); 209 return AWTSize(GetBoundingBox().GetSize()); 210 } 211 212 sal_Bool SAL_CALL ScAccessibleContextBase::isShowing( ) 213 { 214 ScUnoGuard aGuard; 215 IsObjectValid(); 216 sal_Bool bShowing(sal_False); 217 if (mxParent.is()) 218 { 219 uno::Reference<XAccessibleComponent> xParentComponent (mxParent->getAccessibleContext(), uno::UNO_QUERY); 220 if (xParentComponent.is()) 221 { 222 Rectangle aParentBounds(VCLRectangle(xParentComponent->getBounds())); 223 Rectangle aBounds(VCLRectangle(getBounds())); 224 bShowing = aBounds.IsOver(aParentBounds); 225 } 226 } 227 return bShowing; 228 } 229 230 sal_Bool SAL_CALL ScAccessibleContextBase::isVisible( ) 231 { 232 return sal_True; 233 } 234 235 void SAL_CALL ScAccessibleContextBase::grabFocus( ) 236 { 237 DBG_ERROR("not implemented"); 238 } 239 240 sal_Int32 SAL_CALL ScAccessibleContextBase::getForeground( ) 241 { 242 return COL_BLACK; 243 } 244 245 sal_Int32 SAL_CALL ScAccessibleContextBase::getBackground( ) 246 { 247 return COL_WHITE; 248 } 249 250 //===== XAccessibleContext ================================================== 251 252 sal_Int32 SAL_CALL 253 ScAccessibleContextBase::getAccessibleChildCount(void) 254 { 255 DBG_ERROR("should be implemented in the abrevated class"); 256 return 0; 257 } 258 259 uno::Reference<XAccessible> SAL_CALL 260 ScAccessibleContextBase::getAccessibleChild(sal_Int32 /* nIndex */) 261 { 262 DBG_ERROR("should be implemented in the abrevated class"); 263 return uno::Reference<XAccessible>(); 264 } 265 266 uno::Reference<XAccessible> SAL_CALL 267 ScAccessibleContextBase::getAccessibleParent(void) 268 { 269 return mxParent; 270 } 271 272 sal_Int32 SAL_CALL 273 ScAccessibleContextBase::getAccessibleIndexInParent(void) 274 { 275 ScUnoGuard aGuard; 276 IsObjectValid(); 277 // Use a simple but slow solution for now. Optimize later. 278 // Return -1 to indicate that this object's parent does not know about the 279 // object. 280 sal_Int32 nIndex(-1); 281 282 // Iterate over all the parent's children and search for this object. 283 if (mxParent.is()) 284 { 285 uno::Reference<XAccessibleContext> xParentContext ( 286 mxParent->getAccessibleContext()); 287 if (xParentContext.is()) 288 { 289 sal_Int32 nChildCount = xParentContext->getAccessibleChildCount(); 290 for (sal_Int32 i=0; i<nChildCount; ++i) 291 { 292 uno::Reference<XAccessible> xChild (xParentContext->getAccessibleChild (i)); 293 if (xChild.is()) 294 { 295 if (xChild.get() == this) 296 nIndex = i; 297 } 298 } 299 } 300 } 301 302 return nIndex; 303 } 304 305 sal_Int16 SAL_CALL 306 ScAccessibleContextBase::getAccessibleRole(void) 307 { 308 return maRole; 309 } 310 311 ::rtl::OUString SAL_CALL 312 ScAccessibleContextBase::getAccessibleDescription(void) 313 { 314 ScUnoGuard aGuard; 315 IsObjectValid(); 316 if (!msDescription.getLength()) 317 { 318 OUString sDescription(createAccessibleDescription()); 319 // DBG_ASSERT(sDescription.getLength(), "We should give always a description."); 320 321 if (msDescription != sDescription) 322 { 323 AccessibleEventObject aEvent; 324 aEvent.EventId = AccessibleEventId::DESCRIPTION_CHANGED; 325 aEvent.Source = uno::Reference< XAccessibleContext >(this); 326 aEvent.OldValue <<= msDescription; 327 aEvent.NewValue <<= sDescription; 328 329 msDescription = sDescription; 330 331 CommitChange(aEvent); 332 } 333 } 334 return msDescription; 335 } 336 337 OUString SAL_CALL 338 ScAccessibleContextBase::getAccessibleName(void) 339 { 340 ScUnoGuard aGuard; 341 IsObjectValid(); 342 if (!msName.getLength()) 343 { 344 OUString sName(createAccessibleName()); 345 DBG_ASSERT(sName.getLength(), "We should give always a name."); 346 347 if (msName != sName) 348 { 349 AccessibleEventObject aEvent; 350 aEvent.EventId = AccessibleEventId::NAME_CHANGED; 351 aEvent.Source = uno::Reference< XAccessibleContext >(this); 352 aEvent.OldValue <<= msName; 353 aEvent.NewValue <<= sName; 354 355 msName = sName; 356 357 CommitChange(aEvent); 358 } 359 } 360 return msName; 361 } 362 363 uno::Reference<XAccessibleRelationSet> SAL_CALL 364 ScAccessibleContextBase::getAccessibleRelationSet(void) 365 { 366 return new utl::AccessibleRelationSetHelper(); 367 } 368 369 uno::Reference<XAccessibleStateSet> SAL_CALL 370 ScAccessibleContextBase::getAccessibleStateSet(void) 371 { 372 return uno::Reference<XAccessibleStateSet>(); 373 } 374 375 lang::Locale SAL_CALL 376 ScAccessibleContextBase::getLocale(void) 377 { 378 ScUnoGuard aGuard; 379 IsObjectValid(); 380 if (mxParent.is()) 381 { 382 uno::Reference<XAccessibleContext> xParentContext ( 383 mxParent->getAccessibleContext()); 384 if (xParentContext.is()) 385 return xParentContext->getLocale (); 386 } 387 388 // No locale and no parent. Therefore throw exception to indicate this 389 // cluelessness. 390 throw IllegalAccessibleComponentStateException (); 391 } 392 393 //===== XAccessibleEventBroadcaster ===================================== 394 395 void SAL_CALL 396 ScAccessibleContextBase::addEventListener( 397 const uno::Reference<XAccessibleEventListener>& xListener) 398 { 399 if (xListener.is()) 400 { 401 ScUnoGuard aGuard; 402 IsObjectValid(); 403 if (!IsDefunc()) 404 { 405 if (!mnClientId) 406 mnClientId = comphelper::AccessibleEventNotifier::registerClient( ); 407 comphelper::AccessibleEventNotifier::addEventListener( mnClientId, xListener ); 408 } 409 } 410 } 411 412 void SAL_CALL 413 ScAccessibleContextBase::removeEventListener( 414 const uno::Reference<XAccessibleEventListener>& xListener) 415 { 416 if (xListener.is()) 417 { 418 ScUnoGuard aGuard; 419 if (!IsDefunc() && mnClientId) 420 { 421 sal_Int32 nListenerCount = comphelper::AccessibleEventNotifier::removeEventListener( mnClientId, xListener ); 422 if ( !nListenerCount ) 423 { 424 // no listeners anymore 425 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client), 426 // and at least to us not firing any events anymore, in case somebody calls 427 // NotifyAccessibleEvent, again 428 comphelper::AccessibleEventNotifier::revokeClient( mnClientId ); 429 mnClientId = 0; 430 } 431 } 432 } 433 } 434 435 //===== XAccessibleEventListener ======================================== 436 437 void SAL_CALL ScAccessibleContextBase::disposing( 438 const lang::EventObject& rSource ) 439 { 440 ScUnoGuard aGuard; 441 if (rSource.Source == mxParent) 442 dispose(); 443 } 444 445 void SAL_CALL ScAccessibleContextBase::notifyEvent( 446 const AccessibleEventObject& /* aEvent */ ) 447 { 448 } 449 450 //===== XServiceInfo ======================================================== 451 452 ::rtl::OUString SAL_CALL 453 ScAccessibleContextBase::getImplementationName(void) 454 { 455 return OUString(RTL_CONSTASCII_USTRINGPARAM ("ScAccessibleContextBase")); 456 } 457 458 sal_Bool SAL_CALL 459 ScAccessibleContextBase::supportsService(const OUString& sServiceName) 460 { 461 // Iterate over all supported service names and return true if on of them 462 // matches the given name. 463 uno::Sequence< ::rtl::OUString> aSupportedServices ( 464 getSupportedServiceNames ()); 465 sal_Int32 nLength(aSupportedServices.getLength()); 466 const OUString* pServiceNames = aSupportedServices.getConstArray(); 467 for (int i=0; i<nLength; ++i, ++pServiceNames) 468 if (sServiceName == *pServiceNames) 469 return sal_True; 470 return sal_False; 471 } 472 473 uno::Sequence< ::rtl::OUString> SAL_CALL 474 ScAccessibleContextBase::getSupportedServiceNames(void) 475 { 476 uno::Sequence<OUString> aServiceNames(2); 477 OUString* pServiceNames = aServiceNames.getArray(); 478 if (pServiceNames) 479 { 480 pServiceNames[0] = OUString(RTL_CONSTASCII_USTRINGPARAM ("com.sun.star.accessibility.Accessible")); 481 pServiceNames[1] = OUString(RTL_CONSTASCII_USTRINGPARAM ("com.sun.star.accessibility.AccessibleContext")); 482 } 483 484 return aServiceNames; 485 } 486 487 //===== XTypeProvider ======================================================= 488 489 uno::Sequence< uno::Type > SAL_CALL ScAccessibleContextBase::getTypes() 490 { 491 return comphelper::concatSequences(ScAccessibleContextBaseWeakImpl::getTypes(), ScAccessibleContextBaseImplEvent::getTypes()); 492 } 493 494 uno::Sequence<sal_Int8> SAL_CALL 495 ScAccessibleContextBase::getImplementationId(void) 496 { 497 ScUnoGuard aGuard; 498 IsObjectValid(); 499 static uno::Sequence<sal_Int8> aId; 500 if (aId.getLength() == 0) 501 { 502 aId.realloc (16); 503 rtl_createUuid (reinterpret_cast<sal_uInt8 *>(aId.getArray()), 0, sal_True); 504 } 505 return aId; 506 } 507 508 //===== internal ============================================================ 509 510 ::rtl::OUString SAL_CALL 511 ScAccessibleContextBase::createAccessibleDescription(void) 512 { 513 DBG_ERROR("should be implemented in the abrevated class"); 514 return rtl::OUString(); 515 } 516 517 ::rtl::OUString SAL_CALL 518 ScAccessibleContextBase::createAccessibleName(void) 519 { 520 DBG_ERROR("should be implemented in the abrevated class"); 521 return rtl::OUString(); 522 } 523 524 void ScAccessibleContextBase::CommitChange(const AccessibleEventObject& rEvent) const 525 { 526 if (mnClientId) 527 comphelper::AccessibleEventNotifier::addEvent( mnClientId, rEvent ); 528 } 529 530 void ScAccessibleContextBase::ChangeName() 531 { 532 AccessibleEventObject aEvent; 533 aEvent.EventId = AccessibleEventId::NAME_CHANGED; 534 aEvent.Source = uno::Reference< XAccessibleContext >(const_cast<ScAccessibleContextBase*>(this)); 535 aEvent.OldValue <<= msName; 536 537 msName = rtl::OUString(); // reset the name so it will be hold again 538 getAccessibleName(); // create the new name 539 540 aEvent.NewValue <<= msName; 541 542 CommitChange(aEvent); 543 } 544 545 void ScAccessibleContextBase::CommitFocusGained() const 546 { 547 AccessibleEventObject aEvent; 548 aEvent.EventId = AccessibleEventId::STATE_CHANGED; 549 aEvent.Source = uno::Reference< XAccessibleContext >(const_cast<ScAccessibleContextBase*>(this)); 550 aEvent.NewValue <<= AccessibleStateType::FOCUSED; 551 552 CommitChange(aEvent); 553 554 ::vcl::unohelper::NotifyAccessibleStateEventGlobally(aEvent); 555 } 556 557 void ScAccessibleContextBase::CommitFocusLost() const 558 { 559 AccessibleEventObject aEvent; 560 aEvent.EventId = AccessibleEventId::STATE_CHANGED; 561 aEvent.Source = uno::Reference< XAccessibleContext >(const_cast<ScAccessibleContextBase*>(this)); 562 aEvent.OldValue <<= AccessibleStateType::FOCUSED; 563 564 CommitChange(aEvent); 565 566 vcl::unohelper::NotifyAccessibleStateEventGlobally(aEvent); 567 } 568 569 Rectangle ScAccessibleContextBase::GetBoundingBoxOnScreen(void) const 570 { 571 DBG_ERROR("not implemented"); 572 return Rectangle(); 573 } 574 575 Rectangle ScAccessibleContextBase::GetBoundingBox(void) const 576 { 577 DBG_ERROR("not implemented"); 578 return Rectangle(); 579 } 580 581 void ScAccessibleContextBase::IsObjectValid() const 582 { 583 if (rBHelper.bDisposed || rBHelper.bInDispose) 584 throw lang::DisposedException(); 585 } 586