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 <extended/AccessibleBrowseBox.hxx>
21 #include <extended/AccessibleBrowseBoxTable.hxx>
22 #include <extended/AccessibleBrowseBoxHeaderBar.hxx>
23 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
24 #include <vcl/accessibletableprovider.hxx>
25 #include <toolkit/helper/convert.hxx>
26 #include <toolkit/helper/vclunohelper.hxx>
27 #include <sal/types.h>
28 
29 
30 namespace accessibility
31 {
32 
33 using namespace ::com::sun::star::uno;
34 using namespace ::com::sun::star;
35 using namespace ::com::sun::star::lang;
36 using namespace ::com::sun::star::accessibility;
37 
38 // Ctor/Dtor/disposing
39 
AccessibleBrowseBox(const css::uno::Reference<css::accessibility::XAccessible> & _rxParent,const css::uno::Reference<css::accessibility::XAccessible> & _rxCreator,::vcl::IAccessibleTableProvider & _rBrowseBox)40 AccessibleBrowseBox::AccessibleBrowseBox(
41             const css::uno::Reference< css::accessibility::XAccessible >& _rxParent, const css::uno::Reference< css::accessibility::XAccessible >& _rxCreator,
42             ::vcl::IAccessibleTableProvider& _rBrowseBox )
43     : AccessibleBrowseBoxBase( _rxParent, _rBrowseBox,nullptr, vcl::BBTYPE_BROWSEBOX ),
44       m_aCreator(_rxCreator)
45 {
46     m_xFocusWindow = VCLUnoHelper::GetInterface(mpBrowseBox->GetWindowInstance());
47 }
48 
setCreator(const css::uno::Reference<css::accessibility::XAccessible> & _rxCreator)49 void AccessibleBrowseBox::setCreator( const css::uno::Reference< css::accessibility::XAccessible >& _rxCreator )
50 {
51 #if OSL_DEBUG_LEVEL > 0
52     css::uno::Reference< css::accessibility::XAccessible > xCreator(m_aCreator);
53     OSL_ENSURE( !xCreator.is(), "extended/AccessibleBrowseBox::setCreator: creator already set!" );
54 #endif
55     m_aCreator = _rxCreator;
56 }
57 
58 
~AccessibleBrowseBox()59 AccessibleBrowseBox::~AccessibleBrowseBox()
60 {
61 }
62 
63 
disposing()64 void SAL_CALL AccessibleBrowseBox::disposing()
65 {
66     ::osl::MutexGuard aGuard( getMutex() );
67 
68     m_aCreator.clear();
69 
70     if ( mxTable.is() )
71     {
72         mxTable->dispose();
73         mxTable.clear();
74     }
75     if ( mxRowHeaderBar.is() )
76     {
77         mxRowHeaderBar->dispose();
78         mxRowHeaderBar.clear();
79     }
80     if ( mxColumnHeaderBar.is() )
81     {
82         mxColumnHeaderBar->dispose();
83         mxColumnHeaderBar.clear();
84     }
85 
86     AccessibleBrowseBoxBase::disposing();
87 }
88 
89 
90 // css::accessibility::XAccessibleContext
91 
getAccessibleChildCount()92 sal_Int32 SAL_CALL AccessibleBrowseBox::getAccessibleChildCount()
93 {
94     SolarMethodGuard aGuard(getMutex());
95     ensureIsAlive();
96 
97     return vcl::BBINDEX_FIRSTCONTROL + mpBrowseBox->GetAccessibleControlCount();
98 }
99 
100 
101 css::uno::Reference< css::accessibility::XAccessible > SAL_CALL
getAccessibleChild(sal_Int32 nChildIndex)102 AccessibleBrowseBox::getAccessibleChild( sal_Int32 nChildIndex )
103 {
104     SolarMethodGuard aGuard(getMutex());
105     ensureIsAlive();
106 
107     css::uno::Reference< css::accessibility::XAccessible > xRet;
108     if( nChildIndex >= 0 )
109     {
110         if( nChildIndex < vcl::BBINDEX_FIRSTCONTROL )
111             xRet = implGetFixedChild( nChildIndex );
112         else
113         {
114             // additional controls
115             nChildIndex -= vcl::BBINDEX_FIRSTCONTROL;
116             if( nChildIndex < mpBrowseBox->GetAccessibleControlCount() )
117                 xRet = mpBrowseBox->CreateAccessibleControl( nChildIndex );
118         }
119     }
120 
121     if( !xRet.is() )
122         throw lang::IndexOutOfBoundsException();
123     return xRet;
124 }
125 
126 // css::accessibility::XAccessibleComponent
127 
128 css::uno::Reference< css::accessibility::XAccessible > SAL_CALL
getAccessibleAtPoint(const awt::Point & rPoint)129 AccessibleBrowseBox::getAccessibleAtPoint( const awt::Point& rPoint )
130 {
131     SolarMethodGuard aGuard(getMutex());
132     ensureIsAlive();
133 
134     css::uno::Reference< css::accessibility::XAccessible > xChild;
135     sal_Int32 nIndex = 0;
136     if( mpBrowseBox->ConvertPointToControlIndex( nIndex, VCLPoint( rPoint ) ) )
137         xChild = mpBrowseBox->CreateAccessibleControl( nIndex );
138     else
139     {
140         // try whether point is in one of the fixed children
141         // (table, header bars, corner control)
142         Point aPoint( VCLPoint( rPoint ) );
143         for( nIndex = 0; (nIndex < vcl::BBINDEX_FIRSTCONTROL) && !xChild.is(); ++nIndex )
144         {
145             css::uno::Reference< css::accessibility::XAccessible > xCurrChild( implGetFixedChild( nIndex ) );
146             css::uno::Reference< css::accessibility::XAccessibleComponent >
147                 xCurrChildComp( xCurrChild, uno::UNO_QUERY );
148 
149             if( xCurrChildComp.is() &&
150                     VCLRectangle( xCurrChildComp->getBounds() ).IsInside( aPoint ) )
151                 xChild = xCurrChild;
152         }
153     }
154     return xChild;
155 }
156 
157 
grabFocus()158 void SAL_CALL AccessibleBrowseBox::grabFocus()
159 {
160     SolarMethodGuard aGuard(getMutex());
161     ensureIsAlive();
162 
163     mpBrowseBox->GrabFocus();
164 }
165 
166 // XServiceInfo
167 
getImplementationName()168 OUString SAL_CALL AccessibleBrowseBox::getImplementationName()
169 {
170     return "com.sun.star.comp.svtools.AccessibleBrowseBox";
171 }
172 
173 
174 // internal virtual methods
175 
implGetBoundingBox()176 tools::Rectangle AccessibleBrowseBox::implGetBoundingBox()
177 {
178     vcl::Window* pParent = mpBrowseBox->GetAccessibleParentWindow();
179     OSL_ENSURE( pParent, "implGetBoundingBox - missing parent window" );
180     return mpBrowseBox->GetWindowExtentsRelative( pParent );
181 }
182 
183 
implGetBoundingBoxOnScreen()184 tools::Rectangle AccessibleBrowseBox::implGetBoundingBoxOnScreen()
185 {
186     return mpBrowseBox->GetWindowExtentsRelative( nullptr );
187 }
188 
189 // internal helper methods
implGetTable()190 css::uno::Reference< css::accessibility::XAccessible > AccessibleBrowseBox::implGetTable()
191 {
192     if( !mxTable.is() )
193     {
194         mxTable = createAccessibleTable();
195 
196     }
197     return mxTable;
198 }
199 
200 css::uno::Reference< css::accessibility::XAccessible >
implGetHeaderBar(vcl::AccessibleBrowseBoxObjType eObjType)201 AccessibleBrowseBox::implGetHeaderBar(vcl::AccessibleBrowseBoxObjType eObjType)
202 {
203     css::uno::Reference< css::accessibility::XAccessible > xRet;
204     rtl::Reference< AccessibleBrowseBoxHeaderBar >* pxMember = nullptr;
205 
206     if( eObjType == vcl::BBTYPE_ROWHEADERBAR )
207         pxMember = &mxRowHeaderBar;
208     else if( eObjType == vcl::BBTYPE_COLUMNHEADERBAR )
209         pxMember = &mxColumnHeaderBar;
210 
211     if( pxMember )
212     {
213         if( !pxMember->is() )
214         {
215             rtl::Reference<AccessibleBrowseBoxHeaderBar> pHeaderBar = new AccessibleBrowseBoxHeaderBar(
216                 m_aCreator, *mpBrowseBox, eObjType );
217             *pxMember = pHeaderBar;
218         }
219         xRet = pxMember->get();
220     }
221     return xRet;
222 }
223 
224 css::uno::Reference< css::accessibility::XAccessible >
implGetFixedChild(sal_Int32 nChildIndex)225 AccessibleBrowseBox::implGetFixedChild( sal_Int32 nChildIndex )
226 {
227     css::uno::Reference< css::accessibility::XAccessible > xRet;
228     switch( nChildIndex )
229     {
230         case vcl::BBINDEX_COLUMNHEADERBAR:
231             xRet = implGetHeaderBar( vcl::BBTYPE_COLUMNHEADERBAR );
232         break;
233         case vcl::BBINDEX_ROWHEADERBAR:
234             xRet = implGetHeaderBar( vcl::BBTYPE_ROWHEADERBAR );
235         break;
236         case vcl::BBINDEX_TABLE:
237             xRet = implGetTable();
238         break;
239     }
240     return xRet;
241 }
242 
createAccessibleTable()243 rtl::Reference<AccessibleBrowseBoxTable> AccessibleBrowseBox::createAccessibleTable()
244 {
245     css::uno::Reference< css::accessibility::XAccessible > xCreator(m_aCreator);
246     OSL_ENSURE( xCreator.is(), "extended/AccessibleBrowseBox::createAccessibleTable: my creator died - how this?" );
247     return new AccessibleBrowseBoxTable( xCreator, *mpBrowseBox );
248 }
249 
commitTableEvent(sal_Int16 _nEventId,const Any & _rNewValue,const Any & _rOldValue)250 void AccessibleBrowseBox::commitTableEvent(sal_Int16 _nEventId,const Any& _rNewValue,const Any& _rOldValue)
251 {
252     if ( mxTable.is() )
253     {
254         mxTable->commitEvent(_nEventId,_rNewValue,_rOldValue);
255     }
256 }
257 
commitHeaderBarEvent(sal_Int16 _nEventId,const Any & _rNewValue,const Any & _rOldValue,bool _bColumnHeaderBar)258 void AccessibleBrowseBox::commitHeaderBarEvent( sal_Int16 _nEventId,
259                                                 const Any& _rNewValue,
260                                                 const Any& _rOldValue,bool _bColumnHeaderBar)
261 {
262     rtl::Reference< AccessibleBrowseBoxHeaderBar >& xHeaderBar = _bColumnHeaderBar ? mxColumnHeaderBar : mxRowHeaderBar;
263     if ( xHeaderBar.is() )
264         xHeaderBar->commitEvent(_nEventId,_rNewValue,_rOldValue);
265 }
266 
267 
268 // = AccessibleBrowseBoxAccess
269 
AccessibleBrowseBoxAccess(const css::uno::Reference<css::accessibility::XAccessible> & _rxParent,::vcl::IAccessibleTableProvider & _rBrowseBox)270 AccessibleBrowseBoxAccess::AccessibleBrowseBoxAccess( const css::uno::Reference< css::accessibility::XAccessible >& _rxParent, ::vcl::IAccessibleTableProvider& _rBrowseBox )
271         :m_xParent( _rxParent )
272         ,m_rBrowseBox( _rBrowseBox )
273 {
274 }
275 
276 
~AccessibleBrowseBoxAccess()277 AccessibleBrowseBoxAccess::~AccessibleBrowseBoxAccess()
278 {
279 }
280 
281 
dispose()282 void AccessibleBrowseBoxAccess::dispose()
283 {
284     ::osl::MutexGuard aGuard( m_aMutex );
285 
286     if (m_xContext.is())
287     {
288         m_xContext->dispose();
289         m_xContext.clear();
290     }
291 }
292 
293 
getAccessibleContext()294 css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL AccessibleBrowseBoxAccess::getAccessibleContext()
295 {
296     ::osl::MutexGuard aGuard( m_aMutex );
297 
298     // if the context died meanwhile (there is no listener, so it won't tell us explicitly when this happens),
299     // then reset and re-create.
300     if ( m_xContext.is() && !m_xContext->isAlive() )
301         m_xContext = nullptr;
302 
303     if ( !m_xContext.is() )
304         m_xContext = new AccessibleBrowseBox( m_xParent, this, m_rBrowseBox );
305 
306     return m_xContext;
307 }
308 
309 
310 
311 } // namespace accessibility
312 
313 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
314