1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "accessibility/extended/AccessibleToolPanelDeckTabBar.hxx"
22 #include "accessibility/extended/AccessibleToolPanelDeckTabBarItem.hxx"
23 #include "accessibility/helper/accresmgr.hxx"
24 #include "accessibility/helper/accessiblestrings.hrc"
26 #include <com/sun/star/accessibility/AccessibleRole.hpp>
27 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
28 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
29 #include <com/sun/star/lang/DisposedException.hpp>
31 #include <svtools/toolpanel/toolpaneldeck.hxx>
32 #include <svtools/toolpanel/paneltabbar.hxx>
33 #include <unotools/accessiblestatesethelper.hxx>
34 #include <toolkit/awt/vclxwindow.hxx>
35 #include <toolkit/helper/vclunohelper.hxx>
36 #include <vcl/svapp.hxx>
37 #include <vcl/button.hxx>
38 #include <osl/mutex.hxx>
39 #include <tools/diagnose_ex.h>
43 //......................................................................................................................
44 namespace accessibility
46 //......................................................................................................................
48 /** === begin UNO using === **/
49 using ::com::sun::star::uno::Reference
;
50 using ::com::sun::star::uno::XInterface
;
51 using ::com::sun::star::uno::UNO_QUERY
;
52 using ::com::sun::star::uno::UNO_QUERY_THROW
;
53 using ::com::sun::star::uno::UNO_SET_THROW
;
54 using ::com::sun::star::uno::Exception
;
55 using ::com::sun::star::uno::RuntimeException
;
56 using ::com::sun::star::uno::Any
;
57 using ::com::sun::star::uno::makeAny
;
58 using ::com::sun::star::uno::Sequence
;
59 using ::com::sun::star::uno::Type
;
60 using ::com::sun::star::accessibility::XAccessible
;
61 using ::com::sun::star::lang::DisposedException
;
62 using ::com::sun::star::lang::IndexOutOfBoundsException
;
63 using ::com::sun::star::accessibility::XAccessibleContext
;
64 /** === end UNO using === **/
66 namespace AccessibleRole
= ::com::sun::star::accessibility::AccessibleRole
;
67 namespace AccessibleEventId
= ::com::sun::star::accessibility::AccessibleEventId
;
68 namespace AccessibleStateType
= ::com::sun::star::accessibility::AccessibleStateType
;
70 typedef ::com::sun::star::awt::Point UnoPoint
;
72 //==================================================================================================================
74 //==================================================================================================================
75 typedef ::cppu::WeakImplHelper1
< XAccessible
> AccessibleWrapper_Base
;
76 class AccessibleWrapper
: public AccessibleWrapper_Base
79 AccessibleWrapper( const Reference
< XAccessibleContext
>& i_rContext
)
80 :m_xContext( i_rContext
)
85 virtual Reference
< XAccessibleContext
> SAL_CALL
getAccessibleContext( ) throw (RuntimeException
)
91 const Reference
< XAccessibleContext
> m_xContext
;
94 //==================================================================================================================
95 //= AccessibleToolPanelTabBar_Impl
96 //==================================================================================================================
97 class AccessibleToolPanelTabBar_Impl
:public ::boost::noncopyable
98 ,public ::svt::IToolPanelDeckListener
101 AccessibleToolPanelTabBar_Impl(
102 AccessibleToolPanelTabBar
& i_rAntiImpl
,
103 const Reference
< XAccessible
>& i_rAccessibleParent
,
104 ::svt::IToolPanelDeck
& i_rPanelDeck
,
105 ::svt::PanelTabBar
& i_rTabBar
107 virtual ~AccessibleToolPanelTabBar_Impl();
109 void checkDisposed();
110 bool isDisposed() const { return m_pPanelDeck
== NULL
; }
113 ::svt::IToolPanelDeck
* getPanelDeck() const { return m_pPanelDeck
; }
114 ::svt::PanelTabBar
* getTabBar() const { return m_pTabBar
; }
115 const Reference
< XAccessible
>& getAccessibleParent() const { return m_xAccessibleParent
; }
116 Reference
< XAccessible
> getAccessiblePanelItem( size_t i_nPosition
);
117 Reference
< XAccessible
> getOwnAccessible() const;
120 // IToolPanelDeckListener
121 virtual void PanelInserted( const ::svt::PToolPanel
& i_pPanel
, const size_t i_nPosition
);
122 virtual void PanelRemoved( const size_t i_nPosition
);
123 virtual void ActivePanelChanged( const ::boost::optional
< size_t >& i_rOldActive
, const ::boost::optional
< size_t >& i_rNewActive
);
124 virtual void LayouterChanged( const ::svt::PDeckLayouter
& i_rNewLayouter
);
125 virtual void Dying();
127 DECL_LINK( OnWindowEvent
, const VclSimpleEvent
* );
130 AccessibleToolPanelTabBar
& m_rAntiImpl
;
131 Reference
< XAccessible
> m_xAccessibleParent
;
132 ::svt::IToolPanelDeck
* m_pPanelDeck
;
133 ::svt::PanelTabBar
* m_pTabBar
;
134 ::std::vector
< Reference
< XAccessible
> > m_aChildren
;
137 //------------------------------------------------------------------------------------------------------------------
138 AccessibleToolPanelTabBar_Impl::AccessibleToolPanelTabBar_Impl( AccessibleToolPanelTabBar
& i_rAntiImpl
,
139 const Reference
< XAccessible
>& i_rAccessibleParent
, ::svt::IToolPanelDeck
& i_rPanelDeck
, ::svt::PanelTabBar
& i_rTabBar
)
140 :m_rAntiImpl( i_rAntiImpl
)
141 ,m_xAccessibleParent( i_rAccessibleParent
)
142 ,m_pPanelDeck( &i_rPanelDeck
)
143 ,m_pTabBar( &i_rTabBar
)
146 m_pPanelDeck
->AddListener( *this );
147 m_aChildren
.resize( m_pPanelDeck
->GetPanelCount() );
149 const String
sAccessibleDescription( TK_RES_STRING( RID_STR_ACC_DESC_PANELDECL_TABBAR
) );
150 i_rTabBar
.SetAccessibleName( sAccessibleDescription
);
151 i_rTabBar
.SetAccessibleDescription( sAccessibleDescription
);
153 i_rTabBar
.GetScrollButton( true ).AddEventListener( LINK( this, AccessibleToolPanelTabBar_Impl
, OnWindowEvent
) );
154 i_rTabBar
.GetScrollButton( false ).AddEventListener( LINK( this, AccessibleToolPanelTabBar_Impl
, OnWindowEvent
) );
157 //------------------------------------------------------------------------------------------------------------------
158 void AccessibleToolPanelTabBar_Impl::checkDisposed()
161 throw DisposedException( OUString(), *&m_rAntiImpl
);
164 //------------------------------------------------------------------------------------------------------------------
165 AccessibleToolPanelTabBar_Impl::~AccessibleToolPanelTabBar_Impl()
171 //------------------------------------------------------------------------------------------------------------------
172 void AccessibleToolPanelTabBar_Impl::dispose()
174 ENSURE_OR_RETURN_VOID( !isDisposed(), "disposed twice" );
175 m_pPanelDeck
->RemoveListener( *this );
178 m_pTabBar
->GetScrollButton( true ).RemoveEventListener( LINK( this, AccessibleToolPanelTabBar_Impl
, OnWindowEvent
) );
179 m_pTabBar
->GetScrollButton( false ).RemoveEventListener( LINK( this, AccessibleToolPanelTabBar_Impl
, OnWindowEvent
) );
182 m_xAccessibleParent
.clear();
185 //------------------------------------------------------------------------------------------------------------------
186 Reference
< XAccessible
> AccessibleToolPanelTabBar_Impl::getAccessiblePanelItem( size_t i_nPosition
)
188 ENSURE_OR_RETURN( !isDisposed(), "AccessibleToolPanelTabBar_Impl::getAccessiblePanelItem: already disposed!", NULL
);
189 ENSURE_OR_RETURN( i_nPosition
< m_aChildren
.size(), "AccessibleToolPanelTabBar_Impl::getAccessiblePanelItem: invalid index!", NULL
);
191 Reference
< XAccessible
>& rAccessibleChild( m_aChildren
[ i_nPosition
] );
192 if ( !rAccessibleChild
.is() )
194 ::rtl::Reference
< AccessibleToolPanelDeckTabBarItem
> pAccesibleItemContext( new AccessibleToolPanelDeckTabBarItem(
195 getOwnAccessible(), *m_pPanelDeck
, *m_pTabBar
, i_nPosition
) );
196 rAccessibleChild
.set( new AccessibleWrapper( pAccesibleItemContext
.get() ) );
197 pAccesibleItemContext
->lateInit( rAccessibleChild
);
199 return rAccessibleChild
;
202 //------------------------------------------------------------------------------------------------------------------
203 Reference
< XAccessible
> AccessibleToolPanelTabBar_Impl::getOwnAccessible() const
205 Reference
< XAccessible
> xOwnAccessible( static_cast< XAccessible
* >( m_rAntiImpl
.GetVCLXWindow() ) );
206 OSL_ENSURE( xOwnAccessible
->getAccessibleContext() == Reference
< XAccessibleContext
>( &m_rAntiImpl
),
207 "AccessibleToolPanelTabBar_Impl::getOwnAccessible: could not retrieve proper XAccessible for /myself!" );
208 return xOwnAccessible
;
211 //------------------------------------------------------------------------------------------------------------------
212 void AccessibleToolPanelTabBar_Impl::PanelInserted( const ::svt::PToolPanel
& i_pPanel
, const size_t i_nPosition
)
214 ENSURE_OR_RETURN_VOID( i_nPosition
<= m_aChildren
.size(), "AccessibleToolPanelTabBar_Impl::PanelInserted: illegal position (or invalid cache!)" );
216 m_aChildren
.insert( m_aChildren
.begin() + i_nPosition
, (Reference
< XAccessible
>)NULL
);
217 m_rAntiImpl
.NotifyAccessibleEvent( AccessibleEventId::CHILD
, Any(), makeAny( getAccessiblePanelItem( i_nPosition
) ) );
220 //------------------------------------------------------------------------------------------------------------------
221 void AccessibleToolPanelTabBar_Impl::PanelRemoved( const size_t i_nPosition
)
223 ENSURE_OR_RETURN_VOID( i_nPosition
< m_aChildren
.size(), "AccessibleToolPanelTabBar_Impl::PanelInserted: illegal position (or invalid cache!)" );
225 const Reference
< XAccessible
> xOldChild( getAccessiblePanelItem( i_nPosition
) );
226 m_aChildren
.erase( m_aChildren
.begin() + i_nPosition
);
227 m_rAntiImpl
.NotifyAccessibleEvent( AccessibleEventId::CHILD
, makeAny( xOldChild
), Any() );
230 //------------------------------------------------------------------------------------------------------------------
231 void AccessibleToolPanelTabBar_Impl::ActivePanelChanged( const ::boost::optional
< size_t >& i_rOldActive
, const ::boost::optional
< size_t >& i_rNewActive
)
237 //------------------------------------------------------------------------------------------------------------------
238 void AccessibleToolPanelTabBar_Impl::LayouterChanged( const ::svt::PDeckLayouter
& i_rNewLayouter
)
240 (void)i_rNewLayouter
;
241 m_rAntiImpl
.dispose();
244 //------------------------------------------------------------------------------------------------------------------
245 void AccessibleToolPanelTabBar_Impl::Dying()
247 m_rAntiImpl
.dispose();
250 //------------------------------------------------------------------------------------------------------------------
251 IMPL_LINK( AccessibleToolPanelTabBar_Impl
, OnWindowEvent
, const VclSimpleEvent
*, i_pEvent
)
253 ENSURE_OR_RETURN( !isDisposed(), "AccessibleToolPanelTabBar_Impl::OnWindowEvent: already disposed!", 0L );
255 const VclWindowEvent
* pWindowEvent( dynamic_cast< const VclWindowEvent
* >( i_pEvent
) );
259 const bool bForwardButton
= ( pWindowEvent
->GetWindow() == &m_pTabBar
->GetScrollButton( true ) );
260 const bool bBackwardButton
= ( pWindowEvent
->GetWindow() == &m_pTabBar
->GetScrollButton( false ) );
261 ENSURE_OR_RETURN( bForwardButton
|| bBackwardButton
, "AccessibleToolPanelTabBar_Impl::OnWindowEvent: where does this come from?", 0L );
263 const bool bShow
= ( i_pEvent
->GetId() == VCLEVENT_WINDOW_SHOW
);
264 const bool bHide
= ( i_pEvent
->GetId() == VCLEVENT_WINDOW_HIDE
);
265 if ( !bShow
&& !bHide
)
266 // not interested in events other than visibility changes
269 const Reference
< XAccessible
> xButtonAccessible( m_pTabBar
->GetScrollButton( bForwardButton
).GetAccessible() );
270 const Any
aOldChild( bHide
? xButtonAccessible
: Reference
< XAccessible
>() );
271 const Any
aNewChild( bShow
? xButtonAccessible
: Reference
< XAccessible
>() );
272 m_rAntiImpl
.NotifyAccessibleEvent( AccessibleEventId::CHILD
, aOldChild
, aNewChild
);
277 //==================================================================================================================
279 //==================================================================================================================
285 MethodGuard( AccessibleToolPanelTabBar_Impl
& i_rImpl
)
288 i_rImpl
.checkDisposed();
295 SolarMutexGuard m_aGuard
;
299 //==================================================================================================================
300 //= AccessibleToolPanelTabBar
301 //==================================================================================================================
302 //------------------------------------------------------------------------------------------------------------------
303 AccessibleToolPanelTabBar::AccessibleToolPanelTabBar( const Reference
< XAccessible
>& i_rAccessibleParent
,
304 ::svt::IToolPanelDeck
& i_rPanelDeck
, ::svt::PanelTabBar
& i_rTabBar
)
305 :AccessibleToolPanelTabBar_Base( i_rTabBar
.GetWindowPeer() )
306 ,m_pImpl( new AccessibleToolPanelTabBar_Impl( *this, i_rAccessibleParent
, i_rPanelDeck
, i_rTabBar
) )
310 //------------------------------------------------------------------------------------------------------------------
311 AccessibleToolPanelTabBar::~AccessibleToolPanelTabBar()
315 //------------------------------------------------------------------------------------------------------------------
316 sal_Int32 SAL_CALL
AccessibleToolPanelTabBar::getAccessibleChildCount( ) throw (RuntimeException
)
318 MethodGuard
aGuard( *m_pImpl
);
320 const bool bHasScrollBack
= m_pImpl
->getTabBar()->GetScrollButton( false ).IsVisible();
321 const bool bHasScrollForward
= m_pImpl
->getTabBar()->GetScrollButton( true ).IsVisible();
323 return m_pImpl
->getPanelDeck()->GetPanelCount()
324 + ( bHasScrollBack
? 1 : 0 )
325 + ( bHasScrollForward
? 1 : 0 );
328 //------------------------------------------------------------------------------------------------------------------
329 Reference
< XAccessible
> SAL_CALL
AccessibleToolPanelTabBar::getAccessibleChild( sal_Int32 i_nIndex
) throw (IndexOutOfBoundsException
, RuntimeException
)
331 MethodGuard
aGuard( *m_pImpl
);
333 const bool bHasScrollBack
= m_pImpl
->getTabBar()->GetScrollButton( false ).IsVisible();
334 const bool bHasScrollForward
= m_pImpl
->getTabBar()->GetScrollButton( true ).IsVisible();
336 const bool bScrollBackRequested
= ( bHasScrollBack
&& ( i_nIndex
== 0 ) );
337 const bool bScrollForwardRequested
= ( bHasScrollForward
&& ( i_nIndex
== getAccessibleChildCount() - 1 ) );
338 OSL_ENSURE( !( bScrollBackRequested
&& bScrollForwardRequested
), "AccessibleToolPanelTabBar::getAccessibleChild: ouch!" );
340 if ( bScrollBackRequested
|| bScrollForwardRequested
)
342 Reference
< XAccessible
> xScrollButtonAccessible( m_pImpl
->getTabBar()->GetScrollButton( bScrollForwardRequested
).GetAccessible() );
343 ENSURE_OR_RETURN( xScrollButtonAccessible
.is(), "AccessibleToolPanelTabBar::getAccessibleChild: invalid button accessible!", NULL
);
344 #if OSL_DEBUG_LEVEL > 0
345 Reference
< XAccessibleContext
> xScrollButtonContext( xScrollButtonAccessible
->getAccessibleContext() );
346 ENSURE_OR_RETURN( xScrollButtonContext
.is(), "AccessibleToolPanelTabBar::getAccessibleChild: invalid button accessible context!", xScrollButtonAccessible
);
347 OSL_ENSURE( xScrollButtonContext
->getAccessibleParent() == m_pImpl
->getOwnAccessible(),
348 "AccessibleToolPanelTabBar::getAccessibleChild: wrong parent at the button's accesible!" );
350 return xScrollButtonAccessible
;
353 return m_pImpl
->getAccessiblePanelItem( i_nIndex
- ( bHasScrollBack
? 1 : 0 ) );
356 //------------------------------------------------------------------------------------------------------------------
357 Reference
< XAccessible
> SAL_CALL
AccessibleToolPanelTabBar::getAccessibleParent( ) throw (RuntimeException
)
359 MethodGuard
aGuard( *m_pImpl
);
360 return m_pImpl
->getAccessibleParent();
363 //------------------------------------------------------------------------------------------------------------------
364 sal_Int16 SAL_CALL
AccessibleToolPanelTabBar::getAccessibleRole( ) throw (RuntimeException
)
366 MethodGuard
aGuard( *m_pImpl
);
367 return AccessibleRole::PAGE_TAB_LIST
;
370 //------------------------------------------------------------------------------------------------------------------
373 bool lcl_covers( const ::Window
& i_rWindow
, const ::Point
& i_rPoint
)
375 const Rectangle
aWindowBounds( i_rWindow
.GetWindowExtentsRelative( i_rWindow
.GetParent() ) );
376 return aWindowBounds
.IsInside( i_rPoint
);
380 //------------------------------------------------------------------------------------------------------------------
381 Reference
< XAccessible
> SAL_CALL
AccessibleToolPanelTabBar::getAccessibleAtPoint( const UnoPoint
& i_rPoint
) throw (RuntimeException
)
383 MethodGuard
aGuard( *m_pImpl
);
385 // check the tab items
386 const UnoPoint
aOwnScreenPos( getLocationOnScreen() );
387 const ::Point
aRequestedScreenPoint( i_rPoint
.X
+ aOwnScreenPos
.X
, i_rPoint
.Y
+ aOwnScreenPos
.Y
);
389 for ( size_t i
=0; i
<m_pImpl
->getPanelDeck()->GetPanelCount(); ++i
)
391 const ::Rectangle
aItemScreenRect( m_pImpl
->getTabBar()->GetItemScreenRect(i
) );
392 if ( aItemScreenRect
.IsInside( aRequestedScreenPoint
) )
393 return m_pImpl
->getAccessiblePanelItem(i
);
396 // check the scroll buttons
397 const ::Point
aRequestedClientPoint( VCLUnoHelper::ConvertToVCLPoint( i_rPoint
) );
399 const bool bHasScrollBack
= m_pImpl
->getTabBar()->GetScrollButton( false ).IsVisible();
400 if ( bHasScrollBack
&& lcl_covers( m_pImpl
->getTabBar()->GetScrollButton( false ), aRequestedClientPoint
) )
401 return m_pImpl
->getTabBar()->GetScrollButton( false ).GetAccessible();
403 const bool bHasScrollForward
= m_pImpl
->getTabBar()->GetScrollButton( true ).IsVisible();
404 if ( bHasScrollForward
&& lcl_covers( m_pImpl
->getTabBar()->GetScrollButton( true ), aRequestedClientPoint
) )
405 return m_pImpl
->getTabBar()->GetScrollButton( true ).GetAccessible();
411 //------------------------------------------------------------------------------------------------------------------
412 void SAL_CALL
AccessibleToolPanelTabBar::disposing()
414 AccessibleToolPanelTabBar_Base::disposing();
418 //------------------------------------------------------------------------------------------------------------------
419 Reference
< XAccessible
> AccessibleToolPanelTabBar::GetChildAccessible( const VclWindowEvent
& i_rVclWindowEvent
)
421 // don't let the base class generate any A11Y events from VclWindowEvent, we completely manage those
422 // A11Y events ourself
423 (void)i_rVclWindowEvent
;
427 //------------------------------------------------------------------------------------------------------------------
428 void AccessibleToolPanelTabBar::FillAccessibleStateSet( ::utl::AccessibleStateSetHelper
& i_rStateSet
)
430 AccessibleToolPanelTabBar_Base::FillAccessibleStateSet( i_rStateSet
);
431 i_rStateSet
.AddState( AccessibleStateType::FOCUSABLE
);
433 ENSURE_OR_RETURN_VOID( !m_pImpl
->isDisposed(), "AccessibleToolPanelTabBar::FillAccessibleStateSet: already disposed!" );
434 if ( m_pImpl
->getTabBar()->IsVertical() )
435 i_rStateSet
.AddState( AccessibleStateType::VERTICAL
);
437 i_rStateSet
.AddState( AccessibleStateType::HORIZONTAL
);
440 //......................................................................................................................
441 } // namespace accessibility
442 //......................................................................................................................
444 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */