/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_editeng.hxx" #include #include #include #include #include #include #include #include #include #include #include //#include #include using namespace ::rtl; using namespace ::com::sun::star; using namespace ::com::sun::star::accessibility; using ::com::sun::star::uno::Reference; namespace accessibility { //===== internal ============================================================ // Define a shortcut for the somewhot longish base class name. typedef ::cppu::WeakComponentImplHelper4< ::com::sun::star::accessibility::XAccessible, ::com::sun::star::accessibility::XAccessibleContext, ::com::sun::star::accessibility::XAccessibleEventBroadcaster, ::com::sun::star::lang::XServiceInfo> BaseClass; AccessibleContextBase::AccessibleContextBase ( const uno::Reference& rxParent, const sal_Int16 aRole) : BaseClass (MutexOwner::maMutex), mxStateSet (NULL), mxRelationSet (NULL), mxParent(rxParent), msDescription(), meDescriptionOrigin(NotSet), msName(), meNameOrigin(NotSet), mnClientId(0), maRole(aRole) { // Create the state set. ::utl::AccessibleStateSetHelper* pStateSet = new ::utl::AccessibleStateSetHelper (); mxStateSet = pStateSet; // Set some states. Don't use the SetState method because no events // shall be broadcastet (that is not yet initialized anyway). if (pStateSet != NULL) { pStateSet->AddState (AccessibleStateType::ENABLED); pStateSet->AddState (AccessibleStateType::SENSITIVE); pStateSet->AddState (AccessibleStateType::SHOWING); pStateSet->AddState (AccessibleStateType::VISIBLE); pStateSet->AddState (AccessibleStateType::FOCUSABLE); pStateSet->AddState (AccessibleStateType::SELECTABLE); } // Create the relation set. ::utl::AccessibleRelationSetHelper* pRelationSet = new ::utl::AccessibleRelationSetHelper (); mxRelationSet = pRelationSet; } AccessibleContextBase::~AccessibleContextBase(void) { } sal_Bool AccessibleContextBase::SetState (sal_Int16 aState) { ::osl::ClearableMutexGuard aGuard (maMutex); ::utl::AccessibleStateSetHelper* pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get()); if ((pStateSet != NULL) && !pStateSet->contains(aState)) { pStateSet->AddState (aState); // Clear the mutex guard so that it is not locked during calls to // listeners. aGuard.clear(); // Send event for all states except the DEFUNC state. if (aState != AccessibleStateType::DEFUNC) { uno::Any aNewValue; aNewValue <<= aState; CommitChange( AccessibleEventId::STATE_CHANGED, aNewValue, uno::Any()); } return sal_True; } else return sal_False; } sal_Bool AccessibleContextBase::ResetState (sal_Int16 aState) { ::osl::ClearableMutexGuard aGuard (maMutex); ::utl::AccessibleStateSetHelper* pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get()); if ((pStateSet != NULL) && pStateSet->contains(aState)) { pStateSet->RemoveState (aState); // Clear the mutex guard so that it is not locked during calls to listeners. aGuard.clear(); uno::Any aOldValue; aOldValue <<= aState; CommitChange( AccessibleEventId::STATE_CHANGED, uno::Any(), aOldValue); return sal_True; } else return sal_False; } sal_Bool AccessibleContextBase::GetState (sal_Int16 aState) { ::osl::MutexGuard aGuard (maMutex); ::utl::AccessibleStateSetHelper* pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get()); if (pStateSet != NULL) return pStateSet->contains(aState); else // If there is no state set then return false as a default value. return sal_False; } void AccessibleContextBase::SetRelationSet ( const uno::Reference& rxNewRelationSet) throw (::com::sun::star::uno::RuntimeException) { OSL_TRACE ("setting relation set"); // Try to emit some meaningful events indicating differing relations in // both sets. typedef std::pair RD; const RD aRelationDescriptors[] = { RD(AccessibleRelationType::CONTROLLED_BY, AccessibleEventId::CONTROLLED_BY_RELATION_CHANGED), RD(AccessibleRelationType::CONTROLLER_FOR, AccessibleEventId::CONTROLLER_FOR_RELATION_CHANGED), RD(AccessibleRelationType::LABELED_BY, AccessibleEventId::LABELED_BY_RELATION_CHANGED), RD(AccessibleRelationType::LABEL_FOR, AccessibleEventId::LABEL_FOR_RELATION_CHANGED), RD(AccessibleRelationType::MEMBER_OF, AccessibleEventId::MEMBER_OF_RELATION_CHANGED), RD(AccessibleRelationType::INVALID, -1), }; for (int i=0; aRelationDescriptors[i].first!=AccessibleRelationType::INVALID; i++) if (mxRelationSet->containsRelation(aRelationDescriptors[i].first) != rxNewRelationSet->containsRelation(aRelationDescriptors[i].first)) CommitChange (aRelationDescriptors[i].second, uno::Any(), uno::Any()); mxRelationSet = rxNewRelationSet; } //===== XAccessible ========================================================= uno::Reference< XAccessibleContext> SAL_CALL AccessibleContextBase::getAccessibleContext (void) throw (uno::RuntimeException) { ThrowIfDisposed (); return this; } //===== XAccessibleContext ================================================== /** No children. */ sal_Int32 SAL_CALL AccessibleContextBase::getAccessibleChildCount (void) throw (uno::RuntimeException) { ThrowIfDisposed (); return 0; } /** Forward the request to the shape. Return the requested shape or throw an exception for a wrong index. */ uno::Reference SAL_CALL AccessibleContextBase::getAccessibleChild (sal_Int32 nIndex) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException) { ThrowIfDisposed (); throw lang::IndexOutOfBoundsException ( ::rtl::OUString::createFromAscii ("no child with index " + nIndex), NULL); } uno::Reference SAL_CALL AccessibleContextBase::getAccessibleParent (void) throw (::com::sun::star::uno::RuntimeException) { ThrowIfDisposed (); return mxParent; } sal_Int32 SAL_CALL AccessibleContextBase::getAccessibleIndexInParent (void) throw (::com::sun::star::uno::RuntimeException) { ThrowIfDisposed (); // Use a simple but slow solution for now. Optimize later. // Iterate over all the parent's children and search for this object. if (mxParent.is()) { uno::Reference xParentContext ( mxParent->getAccessibleContext()); if (xParentContext.is()) { sal_Int32 nChildCount = xParentContext->getAccessibleChildCount(); for (sal_Int32 i=0; i xChild (xParentContext->getAccessibleChild (i)); if (xChild.is()) { uno::Reference xChildContext = xChild->getAccessibleContext(); if (xChildContext == (XAccessibleContext*)this) return i; } } } } // Return -1 to indicate that this object's parent does not know about the // object. return -1; } sal_Int16 SAL_CALL AccessibleContextBase::getAccessibleRole (void) throw (::com::sun::star::uno::RuntimeException) { ThrowIfDisposed (); return maRole; } ::rtl::OUString SAL_CALL AccessibleContextBase::getAccessibleDescription (void) throw (::com::sun::star::uno::RuntimeException) { ThrowIfDisposed (); return msDescription; } OUString SAL_CALL AccessibleContextBase::getAccessibleName (void) throw (::com::sun::star::uno::RuntimeException) { ThrowIfDisposed (); if (meNameOrigin == NotSet) { // Do not send an event because this is the first time it has been // requested. msName = CreateAccessibleName(); meNameOrigin = AutomaticallyCreated; } return msName; } /** Return a copy of the relation set. */ uno::Reference SAL_CALL AccessibleContextBase::getAccessibleRelationSet (void) throw (::com::sun::star::uno::RuntimeException) { ThrowIfDisposed (); // Create a copy of the relation set and return it. ::utl::AccessibleRelationSetHelper* pRelationSet = static_cast< ::utl::AccessibleRelationSetHelper*>(mxRelationSet.get()); if (pRelationSet != NULL) { return uno::Reference ( new ::utl::AccessibleRelationSetHelper (*pRelationSet)); } else return uno::Reference(NULL); } /** Return a copy of the state set. Possible states are: ENABLED SHOWING VISIBLE */ uno::Reference SAL_CALL AccessibleContextBase::getAccessibleStateSet (void) throw (::com::sun::star::uno::RuntimeException) { ::utl::AccessibleStateSetHelper* pStateSet = NULL; if (rBHelper.bDisposed) { // We are already disposed! // Create a new state set that has only set the DEFUNC state. pStateSet = new ::utl::AccessibleStateSetHelper (); if (pStateSet != NULL) pStateSet->AddState (AccessibleStateType::DEFUNC); } else { // Create a copy of the state set and return it. pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get()); // Merge current focused state from edit engine. #if 0 if (aState == AccessibleStateType::FOCUSED && pStateSet != NULL && mpText != NULL) { if (mpText->GetFocusedState ()) pStateSet->AddState (aState); else pStateSet->RemoveState (aState); } #endif if (pStateSet != NULL) pStateSet = new ::utl::AccessibleStateSetHelper (*pStateSet); } return uno::Reference(pStateSet); } lang::Locale SAL_CALL AccessibleContextBase::getLocale (void) throw (IllegalAccessibleComponentStateException, ::com::sun::star::uno::RuntimeException) { ThrowIfDisposed (); // Delegate request to parent. if (mxParent.is()) { uno::Reference xParentContext ( mxParent->getAccessibleContext()); if (xParentContext.is()) return xParentContext->getLocale (); } // No locale and no parent. Therefore throw exception to indicate this // cluelessness. throw IllegalAccessibleComponentStateException (); } //===== XAccessibleEventListener ============================================ void SAL_CALL AccessibleContextBase::addEventListener ( const uno::Reference& rxListener) throw (uno::RuntimeException) { if (rxListener.is()) { if (rBHelper.bDisposed || rBHelper.bInDispose) { uno::Reference x ((lang::XComponent *)this, uno::UNO_QUERY); rxListener->disposing (lang::EventObject (x)); } else { if (!mnClientId) mnClientId = comphelper::AccessibleEventNotifier::registerClient( ); comphelper::AccessibleEventNotifier::addEventListener( mnClientId, rxListener ); } } } void SAL_CALL AccessibleContextBase::removeEventListener ( const uno::Reference& rxListener ) throw (uno::RuntimeException) { ThrowIfDisposed (); if (rxListener.is()) { sal_Int32 nListenerCount = comphelper::AccessibleEventNotifier::removeEventListener( mnClientId, rxListener ); if ( !nListenerCount ) { // no listeners anymore // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client), // and at least to us not firing any events anymore, in case somebody calls // NotifyAccessibleEvent, again comphelper::AccessibleEventNotifier::revokeClient( mnClientId ); mnClientId = 0; } } } //===== XServiceInfo ======================================================== ::rtl::OUString SAL_CALL AccessibleContextBase::getImplementationName (void) throw (::com::sun::star::uno::RuntimeException) { ThrowIfDisposed (); return OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleContextBase")); } sal_Bool SAL_CALL AccessibleContextBase::supportsService (const OUString& sServiceName) throw (::com::sun::star::uno::RuntimeException) { ThrowIfDisposed (); // Iterate over all supported service names and return true if on of them // matches the given name. uno::Sequence< ::rtl::OUString> aSupportedServices ( getSupportedServiceNames ()); for (int i=0; i SAL_CALL AccessibleContextBase::getSupportedServiceNames (void) throw (::com::sun::star::uno::RuntimeException) { ThrowIfDisposed (); static const OUString sServiceNames[2] = { OUString(RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.accessibility.Accessible")), OUString(RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.accessibility.AccessibleContext")) }; return uno::Sequence (sServiceNames, 2); } //===== XTypeProvider ======================================================= uno::Sequence< ::com::sun::star::uno::Type> AccessibleContextBase::getTypes (void) throw (::com::sun::star::uno::RuntimeException) { ThrowIfDisposed (); // This class supports no interfaces on its own. Just return those // supported by the base class. return BaseClass::getTypes(); } uno::Sequence SAL_CALL AccessibleContextBase::getImplementationId (void) throw (::com::sun::star::uno::RuntimeException) { ThrowIfDisposed (); static uno::Sequence aId; if (aId.getLength() == 0) { ::osl::MutexGuard aGuard (maMutex); aId.realloc (16); rtl_createUuid ((sal_uInt8 *)aId.getArray(), 0, sal_True); } return aId; } //===== internal ============================================================ void SAL_CALL AccessibleContextBase::disposing (void) { SetState (AccessibleStateType::DEFUNC); ::osl::MutexGuard aGuard (maMutex); // Send a disposing to all listeners. if ( mnClientId ) { comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( mnClientId, *this ); mnClientId = 0; } } void AccessibleContextBase::SetAccessibleDescription ( const ::rtl::OUString& rDescription, StringOrigin eDescriptionOrigin) throw (uno::RuntimeException) { if (eDescriptionOrigin < meDescriptionOrigin || (eDescriptionOrigin == meDescriptionOrigin && msDescription != rDescription)) { uno::Any aOldValue, aNewValue; aOldValue <<= msDescription; aNewValue <<= rDescription; msDescription = rDescription; meDescriptionOrigin = eDescriptionOrigin; CommitChange( AccessibleEventId::DESCRIPTION_CHANGED, aNewValue, aOldValue); } } void AccessibleContextBase::SetAccessibleName ( const ::rtl::OUString& rName, StringOrigin eNameOrigin) throw (uno::RuntimeException) { if (eNameOrigin < meNameOrigin || (eNameOrigin == meNameOrigin && msName != rName)) { uno::Any aOldValue, aNewValue; aOldValue <<= msName; aNewValue <<= rName; msName = rName; meNameOrigin = eNameOrigin; CommitChange( AccessibleEventId::NAME_CHANGED, aNewValue, aOldValue); } } ::rtl::OUString AccessibleContextBase::CreateAccessibleDescription (void) throw (::com::sun::star::uno::RuntimeException) { return ::rtl::OUString::createFromAscii ("Empty Description"); } ::rtl::OUString AccessibleContextBase::CreateAccessibleName (void) throw (::com::sun::star::uno::RuntimeException) { return ::rtl::OUString::createFromAscii ("Empty Name"); } void AccessibleContextBase::CommitChange ( sal_Int16 nEventId, const uno::Any& rNewValue, const uno::Any& rOldValue) { // Do not call FireEvent and do not even create the event object when no // listener has been registered yet. Creating the event object can // otherwise lead to a crash. See issue 93419 for details. if (mnClientId != 0) { AccessibleEventObject aEvent ( static_cast(this), nEventId, rNewValue, rOldValue); FireEvent (aEvent); } } void AccessibleContextBase::FireEvent (const AccessibleEventObject& aEvent) { if (mnClientId) comphelper::AccessibleEventNotifier::addEvent( mnClientId, aEvent ); } void AccessibleContextBase::ThrowIfDisposed (void) throw (::com::sun::star::lang::DisposedException) { if (rBHelper.bDisposed || rBHelper.bInDispose) { OSL_TRACE ("Calling disposed object. Throwing exception:"); throw lang::DisposedException ( OUString(RTL_CONSTASCII_USTRINGPARAM("object has been already disposed")), static_cast(this)); } } sal_Bool AccessibleContextBase::IsDisposed (void) { return (rBHelper.bDisposed || rBHelper.bInDispose); } void AccessibleContextBase::SetAccessibleRole( sal_Int16 _nRole ) { maRole = _nRole; } } // end of namespace accessibility