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