/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * 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 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include using ::com::sun::star::uno::Reference; using ::com::sun::star::uno::Sequence; using ::com::sun::star::uno::Any; using namespace ::com::sun::star; using namespace ::com::sun::star::accessibility; using namespace ::comphelper; namespace accessibility { using namespace com::sun::star::accessibility::AccessibleStateType; // Ctor/Dtor/disposing AccessibleBrowseBoxBase::AccessibleBrowseBoxBase( css::uno::Reference< css::accessibility::XAccessible > xParent, ::vcl::IAccessibleTableProvider& rBrowseBox, css::uno::Reference< css::awt::XWindow > _xFocusWindow, AccessibleBrowseBoxObjType eObjType ) : AccessibleBrowseBoxImplHelper( m_aMutex ), mxParent(std::move( xParent )), mpBrowseBox( &rBrowseBox ), m_xFocusWindow(std::move(_xFocusWindow)), maName( rBrowseBox.GetAccessibleObjectName( eObjType ) ), maDescription( rBrowseBox.GetAccessibleObjectDescription( eObjType ) ), meObjType( eObjType ), m_aClientId(0) { if ( m_xFocusWindow.is() ) m_xFocusWindow->addFocusListener( this ); } AccessibleBrowseBoxBase::AccessibleBrowseBoxBase( css::uno::Reference< css::accessibility::XAccessible > rxParent, ::vcl::IAccessibleTableProvider& rBrowseBox, css::uno::Reference< css::awt::XWindow > _xFocusWindow, AccessibleBrowseBoxObjType eObjType, OUString rName, OUString rDescription ) : AccessibleBrowseBoxImplHelper( m_aMutex ), mxParent(std::move( rxParent )), mpBrowseBox( &rBrowseBox ), m_xFocusWindow(std::move(_xFocusWindow)), maName(std::move( rName )), maDescription(std::move( rDescription )), meObjType( eObjType ), m_aClientId(0) { if ( m_xFocusWindow.is() ) m_xFocusWindow->addFocusListener( this ); } AccessibleBrowseBoxBase::~AccessibleBrowseBoxBase() { if( isAlive() ) { // increment ref count to prevent double call of Dtor osl_atomic_increment( &m_refCount ); dispose(); } } void SAL_CALL AccessibleBrowseBoxBase::disposing() { ::osl::MutexGuard aGuard( getMutex() ); if ( m_xFocusWindow.is() ) { SolarMutexGuard aSolarGuard; m_xFocusWindow->removeFocusListener( this ); } if ( getClientId( ) ) { AccessibleEventNotifier::TClientId nId( getClientId( ) ); setClientId( 0 ); AccessibleEventNotifier::revokeClientNotifyDisposing( nId, *this ); } mxParent = nullptr; mpBrowseBox = nullptr; } // css::accessibility::XAccessibleContext Reference< css::accessibility::XAccessible > SAL_CALL AccessibleBrowseBoxBase::getAccessibleParent() { ::osl::MutexGuard aGuard( getMutex() ); ensureIsAlive(); return mxParent; } sal_Int64 SAL_CALL AccessibleBrowseBoxBase::getAccessibleIndexInParent() { ::osl::MutexGuard aGuard( getMutex() ); ensureIsAlive(); // -1 for child not found/no parent (according to specification) sal_Int64 nRet = -1; css::uno::Reference< uno::XInterface > xMeMyselfAndI( static_cast< css::accessibility::XAccessibleContext* >( this ), uno::UNO_QUERY ); // iterate over parent's children and search for this object if( mxParent.is() ) { css::uno::Reference< css::accessibility::XAccessibleContext > xParentContext( mxParent->getAccessibleContext() ); if( xParentContext.is() ) { css::uno::Reference< uno::XInterface > xChild; sal_Int64 nChildCount = xParentContext->getAccessibleChildCount(); for( sal_Int64 nChild = 0; nChild < nChildCount; ++nChild ) { xChild.set(xParentContext->getAccessibleChild( nChild ), css::uno::UNO_QUERY); if ( xMeMyselfAndI.get() == xChild.get() ) { nRet = nChild; break; } } } } return nRet; } OUString SAL_CALL AccessibleBrowseBoxBase::getAccessibleDescription() { ::osl::MutexGuard aGuard( getMutex() ); ensureIsAlive(); return maDescription; } OUString SAL_CALL AccessibleBrowseBoxBase::getAccessibleName() { ::osl::MutexGuard aGuard( getMutex() ); ensureIsAlive(); return maName; } Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL AccessibleBrowseBoxBase::getAccessibleRelationSet() { ::osl::MutexGuard aGuard( getMutex() ); ensureIsAlive(); // BrowseBox does not have relations. return new utl::AccessibleRelationSetHelper; } sal_Int64 SAL_CALL AccessibleBrowseBoxBase::getAccessibleStateSet() { SolarMethodGuard aGuard( getMutex() ); // don't check whether alive -> StateSet may contain DEFUNC return implCreateStateSet(); } lang::Locale SAL_CALL AccessibleBrowseBoxBase::getLocale() { ::osl::MutexGuard aGuard( getMutex() ); ensureIsAlive(); if( mxParent.is() ) { css::uno::Reference< css::accessibility::XAccessibleContext > xParentContext( mxParent->getAccessibleContext() ); if( xParentContext.is() ) return xParentContext->getLocale(); } throw IllegalAccessibleComponentStateException(); } // css::accessibility::XAccessibleComponent sal_Bool SAL_CALL AccessibleBrowseBoxBase::containsPoint( const css::awt::Point& rPoint ) { return tools::Rectangle( Point(), getBoundingBox().GetSize() ).Contains( VCLPoint( rPoint ) ); } awt::Rectangle SAL_CALL AccessibleBrowseBoxBase::getBounds() { return AWTRectangle( getBoundingBox() ); } awt::Point SAL_CALL AccessibleBrowseBoxBase::getLocation() { return AWTPoint( getBoundingBox().TopLeft() ); } awt::Point SAL_CALL AccessibleBrowseBoxBase::getLocationOnScreen() { return AWTPoint( getBoundingBoxOnScreen().TopLeft() ); } awt::Size SAL_CALL AccessibleBrowseBoxBase::getSize() { return AWTSize( getBoundingBox().GetSize() ); } void SAL_CALL AccessibleBrowseBoxBase::focusGained( const css::awt::FocusEvent& ) { com::sun::star::uno::Any aFocused; com::sun::star::uno::Any aEmpty; aFocused <<= FOCUSED; commitEvent(AccessibleEventId::STATE_CHANGED,aFocused,aEmpty); } void SAL_CALL AccessibleBrowseBoxBase::focusLost( const css::awt::FocusEvent& ) { com::sun::star::uno::Any aFocused; com::sun::star::uno::Any aEmpty; aFocused <<= FOCUSED; commitEvent(AccessibleEventId::STATE_CHANGED,aEmpty,aFocused); } // css::accessibility::XAccessibleEventBroadcaster void SAL_CALL AccessibleBrowseBoxBase::addAccessibleEventListener( const css::uno::Reference< css::accessibility::XAccessibleEventListener>& _rxListener ) { if ( _rxListener.is() ) { ::osl::MutexGuard aGuard( getMutex() ); if ( !getClientId( ) ) setClientId( AccessibleEventNotifier::registerClient( ) ); AccessibleEventNotifier::addEventListener( getClientId( ), _rxListener ); } } void SAL_CALL AccessibleBrowseBoxBase::removeAccessibleEventListener( const css::uno::Reference< css::accessibility::XAccessibleEventListener>& _rxListener ) { if( !(_rxListener.is() && getClientId( )) ) return; ::osl::MutexGuard aGuard( getMutex() ); sal_Int32 nListenerCount = AccessibleEventNotifier::removeEventListener( getClientId( ), _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 AccessibleEventNotifier::TClientId nId( getClientId( ) ); setClientId( 0 ); AccessibleEventNotifier::revokeClient( nId ); } } // XTypeProvider Sequence< sal_Int8 > SAL_CALL AccessibleBrowseBoxBase::getImplementationId() { return css::uno::Sequence(); } // XServiceInfo sal_Bool SAL_CALL AccessibleBrowseBoxBase::supportsService( const OUString& rServiceName ) { return cppu::supportsService(this, rServiceName); } Sequence< OUString > SAL_CALL AccessibleBrowseBoxBase::getSupportedServiceNames() { return { "com.sun.star.accessibility.AccessibleContext" }; } // other public methods void AccessibleBrowseBoxBase::setAccessibleName( const OUString& rName ) { ::osl::ClearableMutexGuard aGuard( getMutex() ); Any aOld; aOld <<= maName; maName = rName; aGuard.clear(); commitEvent( AccessibleEventId::NAME_CHANGED, uno::Any( maName ), aOld ); } void AccessibleBrowseBoxBase::setAccessibleDescription( const OUString& rDescription ) { ::osl::ClearableMutexGuard aGuard( getMutex() ); Any aOld; aOld <<= maDescription; maDescription = rDescription; aGuard.clear(); commitEvent( AccessibleEventId::DESCRIPTION_CHANGED, uno::Any( maDescription ), aOld ); } // internal virtual methods bool AccessibleBrowseBoxBase::implIsShowing() { bool bShowing = false; if( mxParent.is() ) { css::uno::Reference< css::accessibility::XAccessibleComponent > xParentComp( mxParent->getAccessibleContext(), uno::UNO_QUERY ); if( xParentComp.is() ) bShowing = implGetBoundingBox().Overlaps( VCLRectangle( xParentComp->getBounds() ) ); } return bShowing; } sal_Int64 AccessibleBrowseBoxBase::implCreateStateSet() { sal_Int64 nStateSet = 0; if( isAlive() ) { // SHOWING done with mxParent if( implIsShowing() ) nStateSet |= AccessibleStateType::SHOWING; // BrowseBox fills StateSet with states depending on object type mpBrowseBox->FillAccessibleStateSet( nStateSet, getType() ); } else nStateSet |= AccessibleStateType::DEFUNC; return nStateSet; } // internal helper methods bool AccessibleBrowseBoxBase::isAlive() const { return !rBHelper.bDisposed && !rBHelper.bInDispose && mpBrowseBox; } void AccessibleBrowseBoxBase::ensureIsAlive() const { if( !isAlive() ) throw lang::DisposedException(); } tools::Rectangle AccessibleBrowseBoxBase::getBoundingBox() { SolarMethodGuard aGuard(getMutex()); ensureIsAlive(); tools::Rectangle aRect = implGetBoundingBox(); if ( aRect.Left() == 0 && aRect.Top() == 0 && aRect.Right() == 0 && aRect.Bottom() == 0 ) { SAL_WARN( "accessibility", "rectangle doesn't exist" ); } return aRect; } tools::Rectangle AccessibleBrowseBoxBase::getBoundingBoxOnScreen() { SolarMethodGuard aGuard(getMutex()); ensureIsAlive(); tools::Rectangle aRect = implGetBoundingBoxOnScreen(); if ( aRect.Left() == 0 && aRect.Top() == 0 && aRect.Right() == 0 && aRect.Bottom() == 0 ) { SAL_WARN( "accessibility", "rectangle doesn't exist" ); } return aRect; } void AccessibleBrowseBoxBase::commitEvent( sal_Int16 _nEventId, const Any& _rNewValue, const Any& _rOldValue ) { osl::MutexGuard aGuard( getMutex() ); if ( !getClientId( ) ) // if we don't have a client id for the notifier, then we don't have listeners, then // we don't need to notify anything return; // build an event object AccessibleEventObject aEvent; aEvent.Source = *this; aEvent.EventId = _nEventId; aEvent.OldValue = _rOldValue; aEvent.NewValue = _rNewValue; // let the notifier handle this event AccessibleEventNotifier::addEvent( getClientId( ), aEvent ); } sal_Int16 SAL_CALL AccessibleBrowseBoxBase::getAccessibleRole() { osl::MutexGuard aGuard( getMutex() ); ensureIsAlive(); sal_Int16 nRole = AccessibleRole::UNKNOWN; switch ( meObjType ) { case AccessibleBrowseBoxObjType::RowHeaderCell: nRole = AccessibleRole::ROW_HEADER; break; case AccessibleBrowseBoxObjType::ColumnHeaderCell: nRole = AccessibleRole::COLUMN_HEADER; break; case AccessibleBrowseBoxObjType::ColumnHeaderBar: case AccessibleBrowseBoxObjType::RowHeaderBar: case AccessibleBrowseBoxObjType::Table: nRole = AccessibleRole::TABLE; break; case AccessibleBrowseBoxObjType::TableCell: nRole = AccessibleRole::TABLE_CELL; break; case AccessibleBrowseBoxObjType::BrowseBox: nRole = AccessibleRole::PANEL; break; case AccessibleBrowseBoxObjType::CheckBoxCell: nRole = AccessibleRole::CHECK_BOX; break; } return nRole; } Reference SAL_CALL AccessibleBrowseBoxBase::getAccessibleAtPoint( const css::awt::Point& ) { return nullptr; } void SAL_CALL AccessibleBrowseBoxBase::disposing( const css::lang::EventObject& ) { m_xFocusWindow = nullptr; } sal_Int32 SAL_CALL AccessibleBrowseBoxBase::getForeground( ) { SolarMethodGuard aGuard(getMutex()); ensureIsAlive(); Color nColor; vcl::Window* pInst = mpBrowseBox->GetWindowInstance(); if ( pInst ) { if ( pInst->IsControlForeground() ) nColor = pInst->GetControlForeground(); else { vcl::Font aFont; if ( pInst->IsControlFont() ) aFont = pInst->GetControlFont(); else aFont = pInst->GetFont(); nColor = aFont.GetColor(); } } return sal_Int32(nColor); } sal_Int32 SAL_CALL AccessibleBrowseBoxBase::getBackground( ) { SolarMethodGuard aGuard(getMutex()); ensureIsAlive(); Color nColor; vcl::Window* pInst = mpBrowseBox->GetWindowInstance(); if ( pInst ) { if ( pInst->IsControlBackground() ) nColor = pInst->GetControlBackground(); else nColor = pInst->GetBackground().GetColor(); } return sal_Int32(nColor); } // XInterface IMPLEMENT_FORWARD_XINTERFACE2( BrowseBoxAccessibleElement, AccessibleBrowseBoxBase, BrowseBoxAccessibleElement_Base ) // XTypeProvider IMPLEMENT_FORWARD_XTYPEPROVIDER2( BrowseBoxAccessibleElement, AccessibleBrowseBoxBase, BrowseBoxAccessibleElement_Base ) // css::accessibility::XAccessible Reference< css::accessibility::XAccessibleContext > SAL_CALL BrowseBoxAccessibleElement::getAccessibleContext() { osl::MutexGuard aGuard( getMutex() ); ensureIsAlive(); return this; } BrowseBoxAccessibleElement::BrowseBoxAccessibleElement( const css::uno::Reference< css::accessibility::XAccessible >& rxParent, ::vcl::IAccessibleTableProvider& rBrowseBox, const css::uno::Reference< css::awt::XWindow >& _xFocusWindow, AccessibleBrowseBoxObjType eObjType ) :AccessibleBrowseBoxBase( rxParent, rBrowseBox, _xFocusWindow, eObjType ) { } BrowseBoxAccessibleElement::BrowseBoxAccessibleElement( const css::uno::Reference< css::accessibility::XAccessible >& rxParent, ::vcl::IAccessibleTableProvider& rBrowseBox, const css::uno::Reference< css::awt::XWindow >& _xFocusWindow, AccessibleBrowseBoxObjType eObjType, const OUString& rName, const OUString& rDescription ) :AccessibleBrowseBoxBase( rxParent, rBrowseBox, _xFocusWindow, eObjType, rName, rDescription ) { } BrowseBoxAccessibleElement::~BrowseBoxAccessibleElement( ) { } } // namespace accessibility /* vim:set shiftwidth=4 softtabstop=4 expandtab: */