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/AccessibleToolPanelDeckTabBar.hxx" 30 #include "accessibility/extended/AccessibleToolPanelDeckTabBarItem.hxx" 31 #include "accessibility/helper/accresmgr.hxx" 32 #include "accessibility/helper/accessiblestrings.hrc" 33 34 /** === begin UNO includes === **/ 35 #include <com/sun/star/accessibility/AccessibleRole.hpp> 36 #include <com/sun/star/accessibility/AccessibleEventId.hpp> 37 #include <com/sun/star/accessibility/AccessibleStateType.hpp> 38 #include <com/sun/star/lang/DisposedException.hpp> 39 /** === end UNO includes === **/ 40 41 #include <svtools/toolpanel/toolpaneldeck.hxx> 42 #include <svtools/toolpanel/paneltabbar.hxx> 43 #include <unotools/accessiblestatesethelper.hxx> 44 #include <toolkit/awt/vclxwindow.hxx> 45 #include <toolkit/helper/vclunohelper.hxx> 46 #include <vcl/svapp.hxx> 47 #include <vcl/button.hxx> 48 #include <vos/mutex.hxx> 49 #include <tools/diagnose_ex.h> 50 51 #include <vector> 52 53 //...................................................................................................................... 54 namespace accessibility 55 { 56 //...................................................................................................................... 57 58 /** === begin UNO using === **/ 59 using ::com::sun::star::uno::Reference; 60 using ::com::sun::star::uno::XInterface; 61 using ::com::sun::star::uno::UNO_QUERY; 62 using ::com::sun::star::uno::UNO_QUERY_THROW; 63 using ::com::sun::star::uno::UNO_SET_THROW; 64 using ::com::sun::star::uno::Exception; 65 using ::com::sun::star::uno::RuntimeException; 66 using ::com::sun::star::uno::Any; 67 using ::com::sun::star::uno::makeAny; 68 using ::com::sun::star::uno::Sequence; 69 using ::com::sun::star::uno::Type; 70 using ::com::sun::star::accessibility::XAccessible; 71 using ::com::sun::star::lang::DisposedException; 72 using ::com::sun::star::lang::IndexOutOfBoundsException; 73 using ::com::sun::star::accessibility::XAccessibleContext; 74 /** === end UNO using === **/ 75 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::Point UnoPoint; 81 typedef ::com::sun::star::awt::Size UnoSize; 82 typedef ::com::sun::star::awt::Rectangle UnoRectangle; 83 84 //================================================================================================================== 85 //= AccessibleWrapper 86 //================================================================================================================== 87 typedef ::cppu::WeakImplHelper1< XAccessible > AccessibleWrapper_Base; 88 class AccessibleWrapper : public AccessibleWrapper_Base 89 { 90 public: 91 AccessibleWrapper( const Reference< XAccessibleContext >& i_rContext ) 92 :m_xContext( i_rContext ) 93 { 94 } 95 96 // XAccessible 97 virtual Reference< XAccessibleContext > SAL_CALL getAccessibleContext( ) throw (RuntimeException) 98 { 99 return m_xContext; 100 } 101 102 private: 103 const Reference< XAccessibleContext > m_xContext; 104 }; 105 106 //================================================================================================================== 107 //= AccessibleToolPanelTabBar_Impl 108 //================================================================================================================== 109 class AccessibleToolPanelTabBar_Impl :public ::boost::noncopyable 110 ,public ::svt::IToolPanelDeckListener 111 { 112 public: 113 AccessibleToolPanelTabBar_Impl( 114 AccessibleToolPanelTabBar& i_rAntiImpl, 115 const Reference< XAccessible >& i_rAccessibleParent, 116 ::svt::IToolPanelDeck& i_rPanelDeck, 117 ::svt::PanelTabBar& i_rTabBar 118 ); 119 ~AccessibleToolPanelTabBar_Impl(); 120 121 void checkDisposed(); 122 bool isDisposed() const { return m_pPanelDeck == NULL; } 123 void dispose(); 124 125 ::svt::IToolPanelDeck* getPanelDeck() const { return m_pPanelDeck; } 126 ::svt::PanelTabBar* getTabBar() const { return m_pTabBar; } 127 const Reference< XAccessible >& getAccessibleParent() const { return m_xAccessibleParent; } 128 Reference< XAccessible > getAccessiblePanelItem( size_t i_nPosition ); 129 Reference< XAccessible > getOwnAccessible() const; 130 131 protected: 132 // IToolPanelDeckListener 133 virtual void PanelInserted( const ::svt::PToolPanel& i_pPanel, const size_t i_nPosition ); 134 virtual void PanelRemoved( const size_t i_nPosition ); 135 virtual void ActivePanelChanged( const ::boost::optional< size_t >& i_rOldActive, const ::boost::optional< size_t >& i_rNewActive ); 136 virtual void LayouterChanged( const ::svt::PDeckLayouter& i_rNewLayouter ); 137 virtual void Dying(); 138 139 DECL_LINK( OnWindowEvent, const VclSimpleEvent* ); 140 141 private: 142 AccessibleToolPanelTabBar& m_rAntiImpl; 143 Reference< XAccessible > m_xAccessibleParent; 144 ::svt::IToolPanelDeck* m_pPanelDeck; 145 ::svt::PanelTabBar* m_pTabBar; 146 ::std::vector< Reference< XAccessible > > m_aChildren; 147 }; 148 149 //------------------------------------------------------------------------------------------------------------------ 150 AccessibleToolPanelTabBar_Impl::AccessibleToolPanelTabBar_Impl( AccessibleToolPanelTabBar& i_rAntiImpl, 151 const Reference< XAccessible >& i_rAccessibleParent, ::svt::IToolPanelDeck& i_rPanelDeck, ::svt::PanelTabBar& i_rTabBar ) 152 :m_rAntiImpl( i_rAntiImpl ) 153 ,m_xAccessibleParent( i_rAccessibleParent ) 154 ,m_pPanelDeck( &i_rPanelDeck ) 155 ,m_pTabBar( &i_rTabBar ) 156 ,m_aChildren() 157 { 158 m_pPanelDeck->AddListener( *this ); 159 m_aChildren.resize( m_pPanelDeck->GetPanelCount() ); 160 161 const String sAccessibleDescription( TK_RES_STRING( RID_STR_ACC_DESC_PANELDECL_TABBAR ) ); 162 i_rTabBar.SetAccessibleName( sAccessibleDescription ); 163 i_rTabBar.SetAccessibleDescription( sAccessibleDescription ); 164 165 i_rTabBar.GetScrollButton( true ).AddEventListener( LINK( this, AccessibleToolPanelTabBar_Impl, OnWindowEvent ) ); 166 i_rTabBar.GetScrollButton( false ).AddEventListener( LINK( this, AccessibleToolPanelTabBar_Impl, OnWindowEvent ) ); 167 } 168 169 //------------------------------------------------------------------------------------------------------------------ 170 void AccessibleToolPanelTabBar_Impl::checkDisposed() 171 { 172 if ( isDisposed() ) 173 throw DisposedException( ::rtl::OUString(), *&m_rAntiImpl ); 174 } 175 176 //------------------------------------------------------------------------------------------------------------------ 177 AccessibleToolPanelTabBar_Impl::~AccessibleToolPanelTabBar_Impl() 178 { 179 if ( !isDisposed() ) 180 dispose(); 181 } 182 183 //------------------------------------------------------------------------------------------------------------------ 184 void AccessibleToolPanelTabBar_Impl::dispose() 185 { 186 ENSURE_OR_RETURN_VOID( !isDisposed(), "disposed twice" ); 187 m_pPanelDeck->RemoveListener( *this ); 188 m_pPanelDeck = NULL; 189 190 m_pTabBar->GetScrollButton( true ).RemoveEventListener( LINK( this, AccessibleToolPanelTabBar_Impl, OnWindowEvent ) ); 191 m_pTabBar->GetScrollButton( false ).RemoveEventListener( LINK( this, AccessibleToolPanelTabBar_Impl, OnWindowEvent ) ); 192 m_pTabBar = NULL; 193 194 m_xAccessibleParent.clear(); 195 } 196 197 //------------------------------------------------------------------------------------------------------------------ 198 Reference< XAccessible > AccessibleToolPanelTabBar_Impl::getAccessiblePanelItem( size_t i_nPosition ) 199 { 200 ENSURE_OR_RETURN( !isDisposed(), "AccessibleToolPanelTabBar_Impl::getAccessiblePanelItem: already disposed!", NULL ); 201 ENSURE_OR_RETURN( i_nPosition < m_aChildren.size(), "AccessibleToolPanelTabBar_Impl::getAccessiblePanelItem: invalid index!", NULL ); 202 203 Reference< XAccessible >& rAccessibleChild( m_aChildren[ i_nPosition ] ); 204 if ( !rAccessibleChild.is() ) 205 { 206 ::rtl::Reference< AccessibleToolPanelDeckTabBarItem > pAccesibleItemContext( new AccessibleToolPanelDeckTabBarItem( 207 getOwnAccessible(), *m_pPanelDeck, *m_pTabBar, i_nPosition ) ); 208 rAccessibleChild.set( new AccessibleWrapper( pAccesibleItemContext.get() ) ); 209 pAccesibleItemContext->lateInit( rAccessibleChild ); 210 } 211 return rAccessibleChild; 212 } 213 214 //------------------------------------------------------------------------------------------------------------------ 215 Reference< XAccessible > AccessibleToolPanelTabBar_Impl::getOwnAccessible() const 216 { 217 Reference< XAccessible > xOwnAccessible( static_cast< XAccessible* >( m_rAntiImpl.GetVCLXWindow() ) ); 218 OSL_ENSURE( xOwnAccessible->getAccessibleContext() == Reference< XAccessibleContext >( &m_rAntiImpl ), 219 "AccessibleToolPanelTabBar_Impl::getOwnAccessible: could not retrieve proper XAccessible for /myself!" ); 220 return xOwnAccessible; 221 } 222 223 //------------------------------------------------------------------------------------------------------------------ 224 void AccessibleToolPanelTabBar_Impl::PanelInserted( const ::svt::PToolPanel& i_pPanel, const size_t i_nPosition ) 225 { 226 ENSURE_OR_RETURN_VOID( i_nPosition <= m_aChildren.size(), "AccessibleToolPanelTabBar_Impl::PanelInserted: illegal position (or invalid cache!)" ); 227 (void)i_pPanel; 228 m_aChildren.insert( m_aChildren.begin() + i_nPosition, NULL ); 229 m_rAntiImpl.NotifyAccessibleEvent( AccessibleEventId::CHILD, Any(), makeAny( getAccessiblePanelItem( i_nPosition ) ) ); 230 } 231 232 //------------------------------------------------------------------------------------------------------------------ 233 void AccessibleToolPanelTabBar_Impl::PanelRemoved( const size_t i_nPosition ) 234 { 235 ENSURE_OR_RETURN_VOID( i_nPosition < m_aChildren.size(), "AccessibleToolPanelTabBar_Impl::PanelInserted: illegal position (or invalid cache!)" ); 236 237 const Reference< XAccessible > xOldChild( getAccessiblePanelItem( i_nPosition ) ); 238 m_aChildren.erase( m_aChildren.begin() + i_nPosition ); 239 m_rAntiImpl.NotifyAccessibleEvent( AccessibleEventId::CHILD, makeAny( xOldChild ), Any() ); 240 } 241 242 //------------------------------------------------------------------------------------------------------------------ 243 void AccessibleToolPanelTabBar_Impl::ActivePanelChanged( const ::boost::optional< size_t >& i_rOldActive, const ::boost::optional< size_t >& i_rNewActive ) 244 { 245 (void)i_rOldActive; 246 (void)i_rNewActive; 247 } 248 249 //------------------------------------------------------------------------------------------------------------------ 250 void AccessibleToolPanelTabBar_Impl::LayouterChanged( const ::svt::PDeckLayouter& i_rNewLayouter ) 251 { 252 (void)i_rNewLayouter; 253 m_rAntiImpl.dispose(); 254 } 255 256 //------------------------------------------------------------------------------------------------------------------ 257 void AccessibleToolPanelTabBar_Impl::Dying() 258 { 259 m_rAntiImpl.dispose(); 260 } 261 262 //------------------------------------------------------------------------------------------------------------------ 263 IMPL_LINK( AccessibleToolPanelTabBar_Impl, OnWindowEvent, const VclSimpleEvent*, i_pEvent ) 264 { 265 ENSURE_OR_RETURN( !isDisposed(), "AccessibleToolPanelTabBar_Impl::OnWindowEvent: already disposed!", 0L ); 266 267 const VclWindowEvent* pWindowEvent( dynamic_cast< const VclWindowEvent* >( i_pEvent ) ); 268 if ( !pWindowEvent ) 269 return 0L; 270 271 const bool bForwardButton = ( pWindowEvent->GetWindow() == &m_pTabBar->GetScrollButton( true ) ); 272 const bool bBackwardButton = ( pWindowEvent->GetWindow() == &m_pTabBar->GetScrollButton( false ) ); 273 ENSURE_OR_RETURN( bForwardButton || bBackwardButton, "AccessibleToolPanelTabBar_Impl::OnWindowEvent: where does this come from?", 0L ); 274 275 const bool bShow = ( i_pEvent->GetId() == VCLEVENT_WINDOW_SHOW ); 276 const bool bHide = ( i_pEvent->GetId() == VCLEVENT_WINDOW_HIDE ); 277 if ( !bShow && !bHide ) 278 // not interested in events other than visibility changes 279 return 0L; 280 281 const Reference< XAccessible > xButtonAccessible( m_pTabBar->GetScrollButton( bForwardButton ).GetAccessible() ); 282 const Any aOldChild( bHide ? xButtonAccessible : Reference< XAccessible >() ); 283 const Any aNewChild( bShow ? xButtonAccessible : Reference< XAccessible >() ); 284 m_rAntiImpl.NotifyAccessibleEvent( AccessibleEventId::CHILD, aOldChild, aNewChild ); 285 286 return 1L; 287 } 288 289 //================================================================================================================== 290 //= MethodGuard 291 //================================================================================================================== 292 namespace 293 { 294 class MethodGuard 295 { 296 public: 297 MethodGuard( AccessibleToolPanelTabBar_Impl& i_rImpl ) 298 :m_aGuard( Application::GetSolarMutex() ) 299 { 300 i_rImpl.checkDisposed(); 301 } 302 ~MethodGuard() 303 { 304 } 305 306 void clear() 307 { 308 m_aGuard.clear(); 309 } 310 311 private: 312 ::vos::OClearableGuard m_aGuard; 313 }; 314 } 315 316 //================================================================================================================== 317 //= AccessibleToolPanelTabBar 318 //================================================================================================================== 319 //------------------------------------------------------------------------------------------------------------------ 320 AccessibleToolPanelTabBar::AccessibleToolPanelTabBar( const Reference< XAccessible >& i_rAccessibleParent, 321 ::svt::IToolPanelDeck& i_rPanelDeck, ::svt::PanelTabBar& i_rTabBar ) 322 :AccessibleToolPanelTabBar_Base( i_rTabBar.GetWindowPeer() ) 323 ,m_pImpl( new AccessibleToolPanelTabBar_Impl( *this, i_rAccessibleParent, i_rPanelDeck, i_rTabBar ) ) 324 { 325 } 326 327 //------------------------------------------------------------------------------------------------------------------ 328 AccessibleToolPanelTabBar::~AccessibleToolPanelTabBar() 329 { 330 } 331 332 //------------------------------------------------------------------------------------------------------------------ 333 sal_Int32 SAL_CALL AccessibleToolPanelTabBar::getAccessibleChildCount( ) throw (RuntimeException) 334 { 335 MethodGuard aGuard( *m_pImpl ); 336 337 const bool bHasScrollBack = m_pImpl->getTabBar()->GetScrollButton( false ).IsVisible(); 338 const bool bHasScrollForward = m_pImpl->getTabBar()->GetScrollButton( true ).IsVisible(); 339 340 return m_pImpl->getPanelDeck()->GetPanelCount() 341 + ( bHasScrollBack ? 1 : 0 ) 342 + ( bHasScrollForward ? 1 : 0 ); 343 } 344 345 //------------------------------------------------------------------------------------------------------------------ 346 Reference< XAccessible > SAL_CALL AccessibleToolPanelTabBar::getAccessibleChild( sal_Int32 i_nIndex ) throw (IndexOutOfBoundsException, RuntimeException) 347 { 348 MethodGuard aGuard( *m_pImpl ); 349 350 const bool bHasScrollBack = m_pImpl->getTabBar()->GetScrollButton( false ).IsVisible(); 351 const bool bHasScrollForward = m_pImpl->getTabBar()->GetScrollButton( true ).IsVisible(); 352 353 const bool bScrollBackRequested = ( bHasScrollBack && ( i_nIndex == 0 ) ); 354 const bool bScrollForwardRequested = ( bHasScrollForward && ( i_nIndex == getAccessibleChildCount() - 1 ) ); 355 OSL_ENSURE( !( bScrollBackRequested && bScrollForwardRequested ), "AccessibleToolPanelTabBar::getAccessibleChild: ouch!" ); 356 357 if ( bScrollBackRequested || bScrollForwardRequested ) 358 { 359 Reference< XAccessible > xScrollButtonAccessible( m_pImpl->getTabBar()->GetScrollButton( bScrollForwardRequested ).GetAccessible() ); 360 ENSURE_OR_RETURN( xScrollButtonAccessible.is(), "AccessibleToolPanelTabBar::getAccessibleChild: invalid button accessible!", NULL ); 361 #if OSL_DEBUG_LEVEL > 0 362 Reference< XAccessibleContext > xScrollButtonContext( xScrollButtonAccessible->getAccessibleContext() ); 363 ENSURE_OR_RETURN( xScrollButtonContext.is(), "AccessibleToolPanelTabBar::getAccessibleChild: invalid button accessible context!", xScrollButtonAccessible ); 364 OSL_ENSURE( xScrollButtonContext->getAccessibleParent() == m_pImpl->getOwnAccessible(), 365 "AccessibleToolPanelTabBar::getAccessibleChild: wrong parent at the button's accesible!" ); 366 #endif 367 return xScrollButtonAccessible; 368 } 369 370 return m_pImpl->getAccessiblePanelItem( i_nIndex - ( bHasScrollBack ? 1 : 0 ) ); 371 } 372 373 //------------------------------------------------------------------------------------------------------------------ 374 Reference< XAccessible > SAL_CALL AccessibleToolPanelTabBar::getAccessibleParent( ) throw (RuntimeException) 375 { 376 MethodGuard aGuard( *m_pImpl ); 377 return m_pImpl->getAccessibleParent(); 378 } 379 380 //------------------------------------------------------------------------------------------------------------------ 381 sal_Int16 SAL_CALL AccessibleToolPanelTabBar::getAccessibleRole( ) throw (RuntimeException) 382 { 383 MethodGuard aGuard( *m_pImpl ); 384 return AccessibleRole::PAGE_TAB_LIST; 385 } 386 387 //------------------------------------------------------------------------------------------------------------------ 388 namespace 389 { 390 bool lcl_covers( const ::Window& i_rWindow, const ::Point& i_rPoint ) 391 { 392 const Rectangle aWindowBounds( i_rWindow.GetWindowExtentsRelative( i_rWindow.GetParent() ) ); 393 return aWindowBounds.IsInside( i_rPoint ); 394 } 395 } 396 397 //------------------------------------------------------------------------------------------------------------------ 398 Reference< XAccessible > SAL_CALL AccessibleToolPanelTabBar::getAccessibleAtPoint( const UnoPoint& i_rPoint ) throw (RuntimeException) 399 { 400 MethodGuard aGuard( *m_pImpl ); 401 402 // check the tab items 403 const UnoPoint aOwnScreenPos( getLocationOnScreen() ); 404 const ::Point aRequestedScreenPoint( i_rPoint.X + aOwnScreenPos.X, i_rPoint.Y + aOwnScreenPos.Y ); 405 406 for ( size_t i=0; i<m_pImpl->getPanelDeck()->GetPanelCount(); ++i ) 407 { 408 const ::Rectangle aItemScreenRect( m_pImpl->getTabBar()->GetItemScreenRect(i) ); 409 if ( aItemScreenRect.IsInside( aRequestedScreenPoint ) ) 410 return m_pImpl->getAccessiblePanelItem(i); 411 } 412 413 // check the scroll buttons 414 const ::Point aRequestedClientPoint( VCLUnoHelper::ConvertToVCLPoint( i_rPoint ) ); 415 416 const bool bHasScrollBack = m_pImpl->getTabBar()->GetScrollButton( false ).IsVisible(); 417 if ( bHasScrollBack && lcl_covers( m_pImpl->getTabBar()->GetScrollButton( false ), aRequestedClientPoint ) ) 418 return m_pImpl->getTabBar()->GetScrollButton( false ).GetAccessible(); 419 420 const bool bHasScrollForward = m_pImpl->getTabBar()->GetScrollButton( true ).IsVisible(); 421 if ( bHasScrollForward && lcl_covers( m_pImpl->getTabBar()->GetScrollButton( true ), aRequestedClientPoint ) ) 422 return m_pImpl->getTabBar()->GetScrollButton( true ).GetAccessible(); 423 424 // no hit 425 return NULL; 426 } 427 428 //------------------------------------------------------------------------------------------------------------------ 429 void SAL_CALL AccessibleToolPanelTabBar::disposing() 430 { 431 AccessibleToolPanelTabBar_Base::disposing(); 432 m_pImpl->dispose(); 433 } 434 435 //------------------------------------------------------------------------------------------------------------------ 436 Reference< XAccessible > AccessibleToolPanelTabBar::GetChildAccessible( const VclWindowEvent& i_rVclWindowEvent ) 437 { 438 // don't let the base class generate any A11Y events from VclWindowEvent, we completely manage those 439 // A11Y events ourself 440 (void)i_rVclWindowEvent; 441 return NULL; 442 } 443 444 //------------------------------------------------------------------------------------------------------------------ 445 void AccessibleToolPanelTabBar::FillAccessibleStateSet( ::utl::AccessibleStateSetHelper& i_rStateSet ) 446 { 447 AccessibleToolPanelTabBar_Base::FillAccessibleStateSet( i_rStateSet ); 448 i_rStateSet.AddState( AccessibleStateType::FOCUSABLE ); 449 450 ENSURE_OR_RETURN_VOID( !m_pImpl->isDisposed(), "AccessibleToolPanelTabBar::FillAccessibleStateSet: already disposed!" ); 451 if ( m_pImpl->getTabBar()->IsVertical() ) 452 i_rStateSet.AddState( AccessibleStateType::VERTICAL ); 453 else 454 i_rStateSet.AddState( AccessibleStateType::HORIZONTAL ); 455 } 456 457 //...................................................................................................................... 458 } // namespace accessibility 459 //...................................................................................................................... 460