1 /************************************************************************* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * Copyright 2000, 2010 Oracle and/or its affiliates. 5 * 6 * OpenOffice.org - a multi-platform office productivity suite 7 * 8 * This file is part of OpenOffice.org. 9 * 10 * OpenOffice.org is free software: you can redistribute it and/or modify 11 * it under the terms of the GNU Lesser General Public License version 3 12 * only, as published by the Free Software Foundation. 13 * 14 * OpenOffice.org is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU Lesser General Public License version 3 for more details 18 * (a copy is included in the LICENSE file that accompanied this code). 19 * 20 * You should have received a copy of the GNU Lesser General Public License 21 * version 3 along with OpenOffice.org. If not, see 22 * <http://www.openoffice.org/license.html> 23 * for a copy of the LGPLv3 License. 24 * 25 ************************************************************************/ 26 27 #include "precompiled_accessibility.hxx" 28 29 #include "accessibility/extended/AccessibleToolPanelDeck.hxx" 30 31 /** === begin UNO includes === **/ 32 #include <com/sun/star/accessibility/AccessibleRole.hpp> 33 #include <com/sun/star/accessibility/AccessibleEventId.hpp> 34 #include <com/sun/star/accessibility/AccessibleStateType.hpp> 35 #include <com/sun/star/lang/DisposedException.hpp> 36 /** === end UNO includes === **/ 37 38 #include <svtools/toolpanel/toolpaneldeck.hxx> 39 #include <toolkit/awt/vclxwindow.hxx> 40 #include <toolkit/helper/vclunohelper.hxx> 41 #include <vcl/svapp.hxx> 42 #include <vos/mutex.hxx> 43 #include <unotools/accessiblestatesethelper.hxx> 44 #include <tools/diagnose_ex.h> 45 46 #include <boost/noncopyable.hpp> 47 #include <vector> 48 49 //...................................................................................................................... 50 namespace accessibility 51 { 52 //...................................................................................................................... 53 54 /** === begin UNO using === **/ 55 using ::com::sun::star::uno::Reference; 56 using ::com::sun::star::uno::XInterface; 57 using ::com::sun::star::uno::UNO_QUERY; 58 using ::com::sun::star::uno::UNO_QUERY_THROW; 59 using ::com::sun::star::uno::UNO_SET_THROW; 60 using ::com::sun::star::uno::Exception; 61 using ::com::sun::star::uno::RuntimeException; 62 using ::com::sun::star::uno::Any; 63 using ::com::sun::star::uno::makeAny; 64 using ::com::sun::star::uno::Sequence; 65 using ::com::sun::star::uno::Type; 66 using ::com::sun::star::accessibility::XAccessible; 67 using ::com::sun::star::accessibility::XAccessibleContext; 68 using ::com::sun::star::lang::DisposedException; 69 using ::com::sun::star::lang::IndexOutOfBoundsException; 70 using ::com::sun::star::lang::Locale; 71 using ::com::sun::star::accessibility::XAccessibleRelationSet; 72 using ::com::sun::star::accessibility::XAccessibleStateSet; 73 using ::com::sun::star::accessibility::IllegalAccessibleComponentStateException; 74 using ::com::sun::star::awt::XFont; 75 /** === end UNO using === **/ 76 namespace AccessibleRole = ::com::sun::star::accessibility::AccessibleRole; 77 namespace AccessibleEventId = ::com::sun::star::accessibility::AccessibleEventId; 78 namespace AccessibleStateType = ::com::sun::star::accessibility::AccessibleStateType; 79 80 typedef ::com::sun::star::awt::Rectangle UnoRectangle; 81 typedef ::com::sun::star::awt::Point UnoPoint; 82 83 //================================================================================================================== 84 //= AccessibleToolPanelDeck_Impl - declaration 85 //================================================================================================================== 86 class AccessibleToolPanelDeck_Impl :public ::boost::noncopyable 87 ,public ::svt::IToolPanelDeckListener 88 { 89 public: 90 AccessibleToolPanelDeck_Impl( 91 AccessibleToolPanelDeck& i_rAntiImpl, 92 const Reference< XAccessible >& i_rAccessibleParent, 93 ::svt::ToolPanelDeck& i_rPanelDeck 94 ); 95 96 void checkDisposed(); 97 bool isDisposed() const { return m_pPanelDeck == NULL; } 98 void dispose(); 99 100 ~AccessibleToolPanelDeck_Impl(); 101 102 Reference< XAccessible > getOwnAccessible() const; 103 Reference< XAccessible > getActivePanelAccessible(); 104 105 protected: 106 // IToolPanelDeckListener 107 virtual void PanelInserted( const ::svt::PToolPanel& i_pPanel, const size_t i_nPosition ); 108 virtual void PanelRemoved( const size_t i_nPosition ); 109 virtual void ActivePanelChanged( const ::boost::optional< size_t >& i_rOldActive, const ::boost::optional< size_t >& i_rNewActive ); 110 virtual void LayouterChanged( const ::svt::PDeckLayouter& i_rNewLayouter ); 111 virtual void Dying(); 112 113 public: 114 AccessibleToolPanelDeck& m_rAntiImpl; 115 Reference< XAccessible > m_xAccessibleParent; 116 ::svt::ToolPanelDeck* m_pPanelDeck; 117 118 typedef ::std::vector< Reference< XAccessible > > AccessibleChildren; 119 Reference< XAccessible > m_xActivePanelAccessible; 120 }; 121 122 //================================================================================================================== 123 //= MethodGuard 124 //================================================================================================================== 125 namespace 126 { 127 class MethodGuard 128 { 129 public: 130 MethodGuard( AccessibleToolPanelDeck_Impl& i_rImpl ) 131 :m_aGuard( Application::GetSolarMutex() ) 132 { 133 i_rImpl.checkDisposed(); 134 } 135 ~MethodGuard() 136 { 137 } 138 139 void clear() 140 { 141 m_aGuard.clear(); 142 } 143 144 private: 145 ::vos::OClearableGuard m_aGuard; 146 }; 147 } 148 149 //================================================================================================================== 150 //= AccessibleToolPanelDeck_Impl - implementation 151 //================================================================================================================== 152 //------------------------------------------------------------------------------------------------------------------ 153 AccessibleToolPanelDeck_Impl::AccessibleToolPanelDeck_Impl( AccessibleToolPanelDeck& i_rAntiImpl, const Reference< XAccessible >& i_rAccessibleParent, 154 ::svt::ToolPanelDeck& i_rPanelDeck ) 155 :m_rAntiImpl( i_rAntiImpl ) 156 ,m_xAccessibleParent( i_rAccessibleParent ) 157 ,m_pPanelDeck( &i_rPanelDeck ) 158 ,m_xActivePanelAccessible() 159 { 160 m_pPanelDeck->AddListener( *this ); 161 } 162 163 //------------------------------------------------------------------------------------------------------------------ 164 AccessibleToolPanelDeck_Impl::~AccessibleToolPanelDeck_Impl() 165 { 166 if ( !isDisposed() ) 167 dispose(); 168 } 169 170 //------------------------------------------------------------------------------------------------------------------ 171 void AccessibleToolPanelDeck_Impl::dispose() 172 { 173 ENSURE_OR_RETURN_VOID( !isDisposed(), "disposed twice" ); 174 m_pPanelDeck->RemoveListener( *this ); 175 m_pPanelDeck = NULL; 176 m_xAccessibleParent.clear(); 177 } 178 179 //------------------------------------------------------------------------------------------------------------------ 180 void AccessibleToolPanelDeck_Impl::checkDisposed() 181 { 182 if ( isDisposed() ) 183 throw DisposedException( ::rtl::OUString(), *&m_rAntiImpl ); 184 } 185 186 //------------------------------------------------------------------------------------------------------------------ 187 Reference< XAccessible > AccessibleToolPanelDeck_Impl::getOwnAccessible() const 188 { 189 Reference< XAccessible > xOwnAccessible( static_cast< XAccessible* >( m_rAntiImpl.GetVCLXWindow() ) ); 190 OSL_ENSURE( xOwnAccessible->getAccessibleContext() == Reference< XAccessibleContext >( &m_rAntiImpl ), 191 "AccessibleToolPanelDeck_Impl::getOwnAccessible: could not retrieve proper XAccessible for /myself!" ); 192 return xOwnAccessible; 193 } 194 195 //------------------------------------------------------------------------------------------------------------------ 196 Reference< XAccessible > AccessibleToolPanelDeck_Impl::getActivePanelAccessible() 197 { 198 ENSURE_OR_RETURN( !isDisposed(), "AccessibleToolPanelDeck_Impl::getActivePanelAccessible: already disposed!", NULL ); 199 200 if ( !m_xActivePanelAccessible.is() ) 201 { 202 ::boost::optional< size_t > aActivePanel( m_pPanelDeck->GetActivePanel() ); 203 ENSURE_OR_RETURN( !!aActivePanel, "AccessibleToolPanelDeck_Impl::getActivePanelAccessible: this should not be called without an active panel!", NULL ); 204 ::svt::PToolPanel pActivePanel( m_pPanelDeck->GetPanel( *aActivePanel ) ); 205 ENSURE_OR_RETURN( pActivePanel.get() != NULL, "AccessibleToolPanelDeck_Impl::getActivePanelAccessible: no active panel!", NULL ); 206 m_xActivePanelAccessible = pActivePanel->CreatePanelAccessible( getOwnAccessible() ); 207 OSL_ENSURE( m_xActivePanelAccessible.is(), "AccessibleToolPanelDeck_Impl::getActivePanelAccessible: illegal accessible returned by the panel!" ); 208 } 209 210 return m_xActivePanelAccessible; 211 } 212 213 //------------------------------------------------------------------------------------------------------------------ 214 void AccessibleToolPanelDeck_Impl::PanelInserted( const ::svt::PToolPanel& i_pPanel, const size_t i_nPosition ) 215 { 216 (void)i_pPanel; 217 (void)i_nPosition; 218 } 219 220 //------------------------------------------------------------------------------------------------------------------ 221 void AccessibleToolPanelDeck_Impl::PanelRemoved( const size_t i_nPosition ) 222 { 223 (void)i_nPosition; 224 } 225 226 //------------------------------------------------------------------------------------------------------------------ 227 void AccessibleToolPanelDeck_Impl::ActivePanelChanged( const ::boost::optional< size_t >& i_rOldActive, const ::boost::optional< size_t >& i_rNewActive ) 228 { 229 if ( !!i_rOldActive ) 230 { 231 if ( !m_xActivePanelAccessible.is() ) 232 { 233 // again, this might in theory happen if the XAccessible for the active panel has never before been requested. 234 // In this case, just say that all our children are invalid, so they all must be re-requested. 235 m_rAntiImpl.NotifyAccessibleEvent( AccessibleEventId::INVALIDATE_ALL_CHILDREN, Any(), Any() ); 236 } 237 else 238 { 239 m_rAntiImpl.NotifyAccessibleEvent( AccessibleEventId::CHILD, makeAny( m_xActivePanelAccessible ), Any() ); 240 } 241 } 242 243 m_xActivePanelAccessible.clear(); 244 245 if ( !!i_rNewActive ) 246 { 247 m_rAntiImpl.NotifyAccessibleEvent( AccessibleEventId::CHILD, Any(), makeAny( getActivePanelAccessible() ) ); 248 } 249 } 250 251 //------------------------------------------------------------------------------------------------------------------ 252 void AccessibleToolPanelDeck_Impl::LayouterChanged( const ::svt::PDeckLayouter& i_rNewLayouter ) 253 { 254 MethodGuard aGuard( *this ); 255 256 (void)i_rNewLayouter; 257 m_rAntiImpl.NotifyAccessibleEvent( AccessibleEventId::INVALIDATE_ALL_CHILDREN, Any(), Any() ); 258 } 259 260 //------------------------------------------------------------------------------------------------------------------ 261 void AccessibleToolPanelDeck_Impl::Dying() 262 { 263 // the tool panel deck is dying, so dispose ourself 264 m_rAntiImpl.dispose(); 265 } 266 267 //================================================================================================================== 268 //= AccessibleToolPanelDeck 269 //================================================================================================================== 270 //------------------------------------------------------------------------------------------------------------------ 271 AccessibleToolPanelDeck::AccessibleToolPanelDeck( const Reference< XAccessible >& i_rAccessibleParent, 272 ::svt::ToolPanelDeck& i_rPanelDeck ) 273 :AccessibleToolPanelDeck_Base( i_rPanelDeck.GetWindowPeer() ) 274 ,m_pImpl( new AccessibleToolPanelDeck_Impl( *this, i_rAccessibleParent, i_rPanelDeck ) ) 275 { 276 } 277 278 //------------------------------------------------------------------------------------------------------------------ 279 AccessibleToolPanelDeck::~AccessibleToolPanelDeck() 280 { 281 } 282 283 //------------------------------------------------------------------------------------------------------------------ 284 sal_Int32 SAL_CALL AccessibleToolPanelDeck::getAccessibleChildCount( ) throw (RuntimeException) 285 { 286 MethodGuard aGuard( *m_pImpl ); 287 288 sal_Int32 nChildCount( m_pImpl->m_pPanelDeck->GetLayouter()->GetAccessibleChildCount() ); 289 290 ::boost::optional< size_t > aActivePanel( m_pImpl->m_pPanelDeck->GetActivePanel() ); 291 if ( !!aActivePanel ) 292 return ++nChildCount; 293 294 return nChildCount; 295 } 296 297 //------------------------------------------------------------------------------------------------------------------ 298 Reference< XAccessible > SAL_CALL AccessibleToolPanelDeck::getAccessibleChild( sal_Int32 i_nIndex ) throw (IndexOutOfBoundsException, RuntimeException) 299 { 300 MethodGuard aGuard( *m_pImpl ); 301 302 const sal_Int32 nChildCount( getAccessibleChildCount() ); 303 if ( ( i_nIndex < 0 ) || ( i_nIndex >= nChildCount ) ) 304 throw IndexOutOfBoundsException( ::rtl::OUString(), *this ); 305 306 // first "n" children are provided by the layouter 307 const size_t nLayouterCount( m_pImpl->m_pPanelDeck->GetLayouter()->GetAccessibleChildCount() ); 308 if ( size_t( i_nIndex ) < nLayouterCount ) 309 return m_pImpl->m_pPanelDeck->GetLayouter()->GetAccessibleChild( 310 size_t( i_nIndex ), 311 m_pImpl->getOwnAccessible() 312 ); 313 314 // the last child is the XAccessible of the active panel 315 return m_pImpl->getActivePanelAccessible(); 316 } 317 318 //------------------------------------------------------------------------------------------------------------------ 319 Reference< XAccessible > SAL_CALL AccessibleToolPanelDeck::getAccessibleParent( ) throw (RuntimeException) 320 { 321 MethodGuard aGuard( *m_pImpl ); 322 const Reference< XAccessible > xParent = implGetForeignControlledParent(); 323 if ( xParent.is() ) 324 return xParent; 325 return m_pImpl->m_xAccessibleParent; 326 } 327 328 //------------------------------------------------------------------------------------------------------------------ 329 sal_Int16 SAL_CALL AccessibleToolPanelDeck::getAccessibleRole( ) throw (RuntimeException) 330 { 331 MethodGuard aGuard( *m_pImpl ); 332 return AccessibleRole::PANEL; 333 } 334 335 //------------------------------------------------------------------------------------------------------------------ 336 Reference< XAccessible > SAL_CALL AccessibleToolPanelDeck::getAccessibleAtPoint( const UnoPoint& i_rPoint ) throw (RuntimeException) 337 { 338 MethodGuard aGuard( *m_pImpl ); 339 340 const ::Point aRequestedPoint( VCLUnoHelper::ConvertToVCLPoint( i_rPoint ) ); 341 // check the panel window itself 342 const ::Window& rActivePanelAnchor( m_pImpl->m_pPanelDeck->GetPanelWindowAnchor() ); 343 const Rectangle aPanelAnchorArea( rActivePanelAnchor.GetPosPixel(), rActivePanelAnchor.GetOutputSizePixel() ); 344 if ( aPanelAnchorArea.IsInside( aRequestedPoint ) ) 345 // note that this assumes that the Window which actually implements the concrete panel covers 346 // the complete area of its "anchor" Window. But this is ensured by the ToolPanelDeck implementation. 347 return m_pImpl->getActivePanelAccessible(); 348 349 // check the XAccessible instances provided by the layouter 350 try 351 { 352 const ::svt::PDeckLayouter pLayouter( m_pImpl->m_pPanelDeck->GetLayouter() ); 353 ENSURE_OR_THROW( pLayouter.get() != NULL, "invalid layouter" ); 354 355 const size_t nLayouterChildren = pLayouter->GetAccessibleChildCount(); 356 for ( size_t i=0; i<nLayouterChildren; ++i ) 357 { 358 const Reference< XAccessible > xLayoutItemAccessible( pLayouter->GetAccessibleChild( i, m_pImpl->getOwnAccessible() ), UNO_SET_THROW ); 359 const Reference< XAccessibleComponent > xLayoutItemComponent( xLayoutItemAccessible->getAccessibleContext(), UNO_QUERY_THROW ); 360 const ::Rectangle aLayoutItemBounds( VCLUnoHelper::ConvertToVCLRect( xLayoutItemComponent->getBounds() ) ); 361 if ( aLayoutItemBounds.IsInside( aRequestedPoint ) ) 362 return xLayoutItemAccessible; 363 } 364 } 365 catch( const Exception& ) 366 { 367 DBG_UNHANDLED_EXCEPTION(); 368 } 369 370 return NULL; 371 } 372 373 //------------------------------------------------------------------------------------------------------------------ 374 void SAL_CALL AccessibleToolPanelDeck::grabFocus( ) throw (RuntimeException) 375 { 376 MethodGuard aGuard( *m_pImpl ); 377 m_pImpl->m_pPanelDeck->GrabFocus(); 378 } 379 380 //------------------------------------------------------------------------------------------------------------------ 381 void SAL_CALL AccessibleToolPanelDeck::disposing() 382 { 383 AccessibleToolPanelDeck_Base::disposing(); 384 m_pImpl->dispose(); 385 } 386 387 //------------------------------------------------------------------------------------------------------------------ 388 Reference< XAccessible > AccessibleToolPanelDeck::GetChildAccessible( const VclWindowEvent& i_rVclWindowEvent ) 389 { 390 // don't let the base class generate any A11Y events from VclWindowEvent, we completely manage those 391 // A11Y events ourself 392 (void)i_rVclWindowEvent; 393 return NULL; 394 } 395 396 //------------------------------------------------------------------------------------------------------------------ 397 void AccessibleToolPanelDeck::FillAccessibleStateSet( ::utl::AccessibleStateSetHelper& i_rStateSet ) 398 { 399 AccessibleToolPanelDeck_Base::FillAccessibleStateSet( i_rStateSet ); 400 if ( m_pImpl->isDisposed() ) 401 { 402 i_rStateSet.AddState( AccessibleStateType::DEFUNC ); 403 } 404 else 405 { 406 i_rStateSet.AddState( AccessibleStateType::FOCUSABLE ); 407 } 408 } 409 410 //...................................................................................................................... 411 } // namespace accessibility 412 //...................................................................................................................... 413