/************************************************************************* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2000, 2010 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ #include "precompiled_accessibility.hxx" #include "accessibility/extended/AccessibleToolPanelDeck.hxx" /** === begin UNO includes === **/ #include #include #include #include /** === end UNO includes === **/ #include #include #include #include #include #include #include #include #include //...................................................................................................................... namespace accessibility { //...................................................................................................................... /** === begin UNO using === **/ using ::com::sun::star::uno::Reference; using ::com::sun::star::uno::XInterface; using ::com::sun::star::uno::UNO_QUERY; using ::com::sun::star::uno::UNO_QUERY_THROW; using ::com::sun::star::uno::UNO_SET_THROW; using ::com::sun::star::uno::Exception; using ::com::sun::star::uno::RuntimeException; using ::com::sun::star::uno::Any; using ::com::sun::star::uno::makeAny; using ::com::sun::star::uno::Sequence; using ::com::sun::star::uno::Type; using ::com::sun::star::accessibility::XAccessible; using ::com::sun::star::accessibility::XAccessibleContext; using ::com::sun::star::lang::DisposedException; using ::com::sun::star::lang::IndexOutOfBoundsException; using ::com::sun::star::lang::Locale; using ::com::sun::star::accessibility::XAccessibleRelationSet; using ::com::sun::star::accessibility::XAccessibleStateSet; using ::com::sun::star::accessibility::IllegalAccessibleComponentStateException; using ::com::sun::star::awt::XFont; /** === end UNO using === **/ namespace AccessibleRole = ::com::sun::star::accessibility::AccessibleRole; namespace AccessibleEventId = ::com::sun::star::accessibility::AccessibleEventId; namespace AccessibleStateType = ::com::sun::star::accessibility::AccessibleStateType; typedef ::com::sun::star::awt::Rectangle UnoRectangle; typedef ::com::sun::star::awt::Point UnoPoint; //================================================================================================================== //= AccessibleToolPanelDeck_Impl - declaration //================================================================================================================== class AccessibleToolPanelDeck_Impl :public ::boost::noncopyable ,public ::svt::IToolPanelDeckListener { public: AccessibleToolPanelDeck_Impl( AccessibleToolPanelDeck& i_rAntiImpl, const Reference< XAccessible >& i_rAccessibleParent, ::svt::ToolPanelDeck& i_rPanelDeck ); void checkDisposed(); bool isDisposed() const { return m_pPanelDeck == NULL; } void dispose(); ~AccessibleToolPanelDeck_Impl(); Reference< XAccessible > getOwnAccessible() const; Reference< XAccessible > getActivePanelAccessible(); protected: // IToolPanelDeckListener virtual void PanelInserted( const ::svt::PToolPanel& i_pPanel, const size_t i_nPosition ); virtual void PanelRemoved( const size_t i_nPosition ); virtual void ActivePanelChanged( const ::boost::optional< size_t >& i_rOldActive, const ::boost::optional< size_t >& i_rNewActive ); virtual void LayouterChanged( const ::svt::PDeckLayouter& i_rNewLayouter ); virtual void Dying(); public: AccessibleToolPanelDeck& m_rAntiImpl; Reference< XAccessible > m_xAccessibleParent; ::svt::ToolPanelDeck* m_pPanelDeck; typedef ::std::vector< Reference< XAccessible > > AccessibleChildren; Reference< XAccessible > m_xActivePanelAccessible; }; //================================================================================================================== //= MethodGuard //================================================================================================================== namespace { class MethodGuard { public: MethodGuard( AccessibleToolPanelDeck_Impl& i_rImpl ) :m_aGuard( Application::GetSolarMutex() ) { i_rImpl.checkDisposed(); } ~MethodGuard() { } void clear() { m_aGuard.clear(); } private: ::vos::OClearableGuard m_aGuard; }; } //================================================================================================================== //= AccessibleToolPanelDeck_Impl - implementation //================================================================================================================== //------------------------------------------------------------------------------------------------------------------ AccessibleToolPanelDeck_Impl::AccessibleToolPanelDeck_Impl( AccessibleToolPanelDeck& i_rAntiImpl, const Reference< XAccessible >& i_rAccessibleParent, ::svt::ToolPanelDeck& i_rPanelDeck ) :m_rAntiImpl( i_rAntiImpl ) ,m_xAccessibleParent( i_rAccessibleParent ) ,m_pPanelDeck( &i_rPanelDeck ) ,m_xActivePanelAccessible() { m_pPanelDeck->AddListener( *this ); } //------------------------------------------------------------------------------------------------------------------ AccessibleToolPanelDeck_Impl::~AccessibleToolPanelDeck_Impl() { if ( !isDisposed() ) dispose(); } //------------------------------------------------------------------------------------------------------------------ void AccessibleToolPanelDeck_Impl::dispose() { ENSURE_OR_RETURN_VOID( !isDisposed(), "disposed twice" ); m_pPanelDeck->RemoveListener( *this ); m_pPanelDeck = NULL; m_xAccessibleParent.clear(); } //------------------------------------------------------------------------------------------------------------------ void AccessibleToolPanelDeck_Impl::checkDisposed() { if ( isDisposed() ) throw DisposedException( ::rtl::OUString(), *&m_rAntiImpl ); } //------------------------------------------------------------------------------------------------------------------ Reference< XAccessible > AccessibleToolPanelDeck_Impl::getOwnAccessible() const { Reference< XAccessible > xOwnAccessible( static_cast< XAccessible* >( m_rAntiImpl.GetVCLXWindow() ) ); OSL_ENSURE( xOwnAccessible->getAccessibleContext() == Reference< XAccessibleContext >( &m_rAntiImpl ), "AccessibleToolPanelDeck_Impl::getOwnAccessible: could not retrieve proper XAccessible for /myself!" ); return xOwnAccessible; } //------------------------------------------------------------------------------------------------------------------ Reference< XAccessible > AccessibleToolPanelDeck_Impl::getActivePanelAccessible() { ENSURE_OR_RETURN( !isDisposed(), "AccessibleToolPanelDeck_Impl::getActivePanelAccessible: already disposed!", NULL ); if ( !m_xActivePanelAccessible.is() ) { ::boost::optional< size_t > aActivePanel( m_pPanelDeck->GetActivePanel() ); ENSURE_OR_RETURN( !!aActivePanel, "AccessibleToolPanelDeck_Impl::getActivePanelAccessible: this should not be called without an active panel!", NULL ); ::svt::PToolPanel pActivePanel( m_pPanelDeck->GetPanel( *aActivePanel ) ); ENSURE_OR_RETURN( pActivePanel.get() != NULL, "AccessibleToolPanelDeck_Impl::getActivePanelAccessible: no active panel!", NULL ); m_xActivePanelAccessible = pActivePanel->CreatePanelAccessible( getOwnAccessible() ); OSL_ENSURE( m_xActivePanelAccessible.is(), "AccessibleToolPanelDeck_Impl::getActivePanelAccessible: illegal accessible returned by the panel!" ); } return m_xActivePanelAccessible; } //------------------------------------------------------------------------------------------------------------------ void AccessibleToolPanelDeck_Impl::PanelInserted( const ::svt::PToolPanel& i_pPanel, const size_t i_nPosition ) { (void)i_pPanel; (void)i_nPosition; } //------------------------------------------------------------------------------------------------------------------ void AccessibleToolPanelDeck_Impl::PanelRemoved( const size_t i_nPosition ) { (void)i_nPosition; } //------------------------------------------------------------------------------------------------------------------ void AccessibleToolPanelDeck_Impl::ActivePanelChanged( const ::boost::optional< size_t >& i_rOldActive, const ::boost::optional< size_t >& i_rNewActive ) { if ( !!i_rOldActive ) { if ( !m_xActivePanelAccessible.is() ) { // again, this might in theory happen if the XAccessible for the active panel has never before been requested. // In this case, just say that all our children are invalid, so they all must be re-requested. m_rAntiImpl.NotifyAccessibleEvent( AccessibleEventId::INVALIDATE_ALL_CHILDREN, Any(), Any() ); } else { m_rAntiImpl.NotifyAccessibleEvent( AccessibleEventId::CHILD, makeAny( m_xActivePanelAccessible ), Any() ); } } m_xActivePanelAccessible.clear(); if ( !!i_rNewActive ) { m_rAntiImpl.NotifyAccessibleEvent( AccessibleEventId::CHILD, Any(), makeAny( getActivePanelAccessible() ) ); } } //------------------------------------------------------------------------------------------------------------------ void AccessibleToolPanelDeck_Impl::LayouterChanged( const ::svt::PDeckLayouter& i_rNewLayouter ) { MethodGuard aGuard( *this ); (void)i_rNewLayouter; m_rAntiImpl.NotifyAccessibleEvent( AccessibleEventId::INVALIDATE_ALL_CHILDREN, Any(), Any() ); } //------------------------------------------------------------------------------------------------------------------ void AccessibleToolPanelDeck_Impl::Dying() { // the tool panel deck is dying, so dispose ourself m_rAntiImpl.dispose(); } //================================================================================================================== //= AccessibleToolPanelDeck //================================================================================================================== //------------------------------------------------------------------------------------------------------------------ AccessibleToolPanelDeck::AccessibleToolPanelDeck( const Reference< XAccessible >& i_rAccessibleParent, ::svt::ToolPanelDeck& i_rPanelDeck ) :AccessibleToolPanelDeck_Base( i_rPanelDeck.GetWindowPeer() ) ,m_pImpl( new AccessibleToolPanelDeck_Impl( *this, i_rAccessibleParent, i_rPanelDeck ) ) { } //------------------------------------------------------------------------------------------------------------------ AccessibleToolPanelDeck::~AccessibleToolPanelDeck() { } //------------------------------------------------------------------------------------------------------------------ sal_Int32 SAL_CALL AccessibleToolPanelDeck::getAccessibleChildCount( ) throw (RuntimeException) { MethodGuard aGuard( *m_pImpl ); sal_Int32 nChildCount( m_pImpl->m_pPanelDeck->GetLayouter()->GetAccessibleChildCount() ); ::boost::optional< size_t > aActivePanel( m_pImpl->m_pPanelDeck->GetActivePanel() ); if ( !!aActivePanel ) return ++nChildCount; return nChildCount; } //------------------------------------------------------------------------------------------------------------------ Reference< XAccessible > SAL_CALL AccessibleToolPanelDeck::getAccessibleChild( sal_Int32 i_nIndex ) throw (IndexOutOfBoundsException, RuntimeException) { MethodGuard aGuard( *m_pImpl ); const sal_Int32 nChildCount( getAccessibleChildCount() ); if ( ( i_nIndex < 0 ) || ( i_nIndex >= nChildCount ) ) throw IndexOutOfBoundsException( ::rtl::OUString(), *this ); // first "n" children are provided by the layouter const size_t nLayouterCount( m_pImpl->m_pPanelDeck->GetLayouter()->GetAccessibleChildCount() ); if ( size_t( i_nIndex ) < nLayouterCount ) return m_pImpl->m_pPanelDeck->GetLayouter()->GetAccessibleChild( size_t( i_nIndex ), m_pImpl->getOwnAccessible() ); // the last child is the XAccessible of the active panel return m_pImpl->getActivePanelAccessible(); } //------------------------------------------------------------------------------------------------------------------ Reference< XAccessible > SAL_CALL AccessibleToolPanelDeck::getAccessibleParent( ) throw (RuntimeException) { MethodGuard aGuard( *m_pImpl ); return m_pImpl->m_xAccessibleParent; } //------------------------------------------------------------------------------------------------------------------ sal_Int16 SAL_CALL AccessibleToolPanelDeck::getAccessibleRole( ) throw (RuntimeException) { MethodGuard aGuard( *m_pImpl ); return AccessibleRole::PANEL; } //------------------------------------------------------------------------------------------------------------------ Reference< XAccessible > SAL_CALL AccessibleToolPanelDeck::getAccessibleAtPoint( const UnoPoint& i_rPoint ) throw (RuntimeException) { MethodGuard aGuard( *m_pImpl ); const ::Point aRequestedPoint( VCLUnoHelper::ConvertToVCLPoint( i_rPoint ) ); // check the panel window itself const ::Window& rActivePanelAnchor( m_pImpl->m_pPanelDeck->GetPanelWindowAnchor() ); const Rectangle aPanelAnchorArea( rActivePanelAnchor.GetPosPixel(), rActivePanelAnchor.GetOutputSizePixel() ); if ( aPanelAnchorArea.IsInside( aRequestedPoint ) ) // note that this assumes that the Window which actually implements the concrete panel covers // the complete area of its "anchor" Window. But this is ensured by the ToolPanelDeck implementation. return m_pImpl->getActivePanelAccessible(); // check the XAccessible instances provided by the layouter try { const ::svt::PDeckLayouter pLayouter( m_pImpl->m_pPanelDeck->GetLayouter() ); ENSURE_OR_THROW( pLayouter.get() != NULL, "invalid layouter" ); const size_t nLayouterChildren = pLayouter->GetAccessibleChildCount(); for ( size_t i=0; i xLayoutItemAccessible( pLayouter->GetAccessibleChild( i, m_pImpl->getOwnAccessible() ), UNO_SET_THROW ); const Reference< XAccessibleComponent > xLayoutItemComponent( xLayoutItemAccessible->getAccessibleContext(), UNO_QUERY_THROW ); const ::Rectangle aLayoutItemBounds( VCLUnoHelper::ConvertToVCLRect( xLayoutItemComponent->getBounds() ) ); if ( aLayoutItemBounds.IsInside( aRequestedPoint ) ) return xLayoutItemAccessible; } } catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); } return NULL; } //------------------------------------------------------------------------------------------------------------------ void SAL_CALL AccessibleToolPanelDeck::grabFocus( ) throw (RuntimeException) { MethodGuard aGuard( *m_pImpl ); m_pImpl->m_pPanelDeck->GrabFocus(); } //------------------------------------------------------------------------------------------------------------------ void SAL_CALL AccessibleToolPanelDeck::disposing() { AccessibleToolPanelDeck_Base::disposing(); m_pImpl->dispose(); } //------------------------------------------------------------------------------------------------------------------ Reference< XAccessible > AccessibleToolPanelDeck::GetChildAccessible( const VclWindowEvent& i_rVclWindowEvent ) { // don't let the base class generate any A11Y events from VclWindowEvent, we completely manage those // A11Y events ourself (void)i_rVclWindowEvent; return NULL; } //------------------------------------------------------------------------------------------------------------------ void AccessibleToolPanelDeck::FillAccessibleStateSet( ::utl::AccessibleStateSetHelper& i_rStateSet ) { AccessibleToolPanelDeck_Base::FillAccessibleStateSet( i_rStateSet ); if ( m_pImpl->isDisposed() ) { i_rStateSet.AddState( AccessibleStateType::DEFUNC ); } else { i_rStateSet.AddState( AccessibleStateType::FOCUSABLE ); } } //...................................................................................................................... } // namespace accessibility //......................................................................................................................