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