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 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_accessibility.hxx"
26 #include "accessibility/extended/AccessibleGridControl.hxx"
27 #include "accessibility/extended/AccessibleGridControlTable.hxx"
28 #include "accessibility/extended/AccessibleGridControlHeader.hxx"
29 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
30 #include <com/sun/star/accessibility/AccessibleTableModelChange.hpp>
31 #include <com/sun/star/accessibility/AccessibleTableModelChangeType.hpp>
32 #include <svtools/accessibletable.hxx>
33 #include <comphelper/types.hxx>
34 #include <toolkit/helper/vclunohelper.hxx>
35
36 // ============================================================================
37
38 namespace accessibility
39 {
40
41 // ============================================================================
42
43 using ::rtl::OUString;
44
45 using namespace ::com::sun::star::uno;
46 using namespace ::com::sun::star;
47 using namespace ::com::sun::star::lang;
48 using namespace ::com::sun::star::accessibility;
49 using namespace ::svt;
50 using namespace ::svt::table;
51
52 // ============================================================================
53 class AccessibleGridControl_Impl
54 {
55 public:
56 /// the XAccessible which created the AccessibleGridControl
57 WeakReference< XAccessible > m_aCreator;
58
59 /** The data table child. */
60 Reference<
61 ::com::sun::star::accessibility::XAccessible > m_xTable;
62 AccessibleGridControlTable* m_pTable;
63
64 /** The header bar for rows. */
65 Reference<
66 ::com::sun::star::accessibility::XAccessible > m_xRowHeaderBar;
67 AccessibleGridControlHeader* m_pRowHeaderBar;
68
69 /** The header bar for columns (first row of the table). */
70 Reference<
71 ::com::sun::star::accessibility::XAccessible > m_xColumnHeaderBar;
72 AccessibleGridControlHeader* m_pColumnHeaderBar;
73
74 /** The table cell child. */
75 Reference<
76 ::com::sun::star::accessibility::XAccessible > m_xCell;
77 AccessibleGridControlTableCell* m_pCell;
78 };
79
DBG_NAME(AccessibleGridControl)80 DBG_NAME( AccessibleGridControl )
81
82 AccessibleGridControl::AccessibleGridControl(
83 const Reference< XAccessible >& _rxParent, const Reference< XAccessible >& _rxCreator,
84 IAccessibleTable& _rTable )
85 : AccessibleGridControlBase( _rxParent, _rTable, TCTYPE_GRIDCONTROL )
86 {
87 m_pImpl.reset( new AccessibleGridControl_Impl() );
88 m_pImpl->m_aCreator = _rxCreator;
89 }
90
91 // -----------------------------------------------------------------------------
~AccessibleGridControl()92 AccessibleGridControl::~AccessibleGridControl()
93 {
94 }
95 // -----------------------------------------------------------------------------
96
disposing()97 void SAL_CALL AccessibleGridControl::disposing()
98 {
99 ::osl::MutexGuard aGuard( getOslMutex() );
100
101 m_pImpl->m_pTable = NULL;
102 m_pImpl->m_pColumnHeaderBar = NULL;
103 m_pImpl->m_pRowHeaderBar = NULL;
104 m_pImpl->m_pCell = NULL;
105 m_pImpl->m_aCreator = Reference< XAccessible >();
106
107 Reference< XAccessible > xTable = m_pImpl->m_xTable;
108
109 Reference< XComponent > xComp( m_pImpl->m_xTable, UNO_QUERY );
110 if ( xComp.is() )
111 {
112 xComp->dispose();
113 }
114 Reference< XAccessible > xCell = m_pImpl->m_xCell;
115
116 Reference< XComponent > xCellComp( m_pImpl->m_xCell, UNO_QUERY );
117 if ( xCellComp.is() )
118 {
119 xCellComp->dispose();
120 }
121
122 ::comphelper::disposeComponent(m_pImpl->m_xRowHeaderBar);
123 ::comphelper::disposeComponent(m_pImpl->m_xColumnHeaderBar);
124 AccessibleGridControlBase::disposing();
125 }
126 // -----------------------------------------------------------------------------
127
128 // XAccessibleContext ---------------------------------------------------------
129
getAccessibleChildCount()130 sal_Int32 SAL_CALL AccessibleGridControl::getAccessibleChildCount()
131 {
132 TCSolarGuard aSolarGuard;
133 ::osl::MutexGuard aGuard( getOslMutex() );
134 ensureIsAlive();
135 return m_aTable.GetAccessibleControlCount();
136 }
137 // -----------------------------------------------------------------------------
138
139 Reference< XAccessible > SAL_CALL
getAccessibleChild(sal_Int32 nChildIndex)140 AccessibleGridControl::getAccessibleChild( sal_Int32 nChildIndex )
141 {
142 TCSolarGuard aSolarGuard;
143 ::osl::MutexGuard aGuard( getOslMutex() );
144
145 if (nChildIndex<0 || nChildIndex>=getAccessibleChildCount())
146 throw IndexOutOfBoundsException();
147
148 Reference< XAccessible > xChild;
149 if (isAlive())
150 {
151 if(nChildIndex == 0 && m_aTable.HasColHeader())
152 {
153 if(!m_pImpl->m_xColumnHeaderBar.is())
154 {
155 AccessibleGridControlHeader* pColHeaderBar = new AccessibleGridControlHeader(m_pImpl->m_aCreator, m_aTable, svt::table::TCTYPE_COLUMNHEADERBAR);
156 m_pImpl->m_xColumnHeaderBar = pColHeaderBar;
157 }
158 xChild = m_pImpl->m_xColumnHeaderBar;
159 }
160 else if(m_aTable.HasRowHeader() && (nChildIndex == 1 || nChildIndex == 0))
161 {
162 if(!m_pImpl->m_xRowHeaderBar.is())
163 {
164 AccessibleGridControlHeader* pRowHeaderBar = new AccessibleGridControlHeader(m_pImpl->m_aCreator, m_aTable, svt::table::TCTYPE_ROWHEADERBAR);
165 m_pImpl->m_xRowHeaderBar = pRowHeaderBar;
166 }
167 xChild = m_pImpl->m_xRowHeaderBar;
168 }
169 else
170 {
171 if(!m_pImpl->m_xTable.is())
172 {
173 AccessibleGridControlTable* pTable = new AccessibleGridControlTable(m_pImpl->m_aCreator, m_aTable, svt::table::TCTYPE_TABLE);
174 m_pImpl->m_xTable = pTable;
175 m_pImpl->m_pTable = pTable;
176 }
177 xChild = m_pImpl->m_xTable;
178 }
179 }
180 return xChild;
181 }
182 // -----------------------------------------------------------------------------
183
getAccessibleRole()184 sal_Int16 SAL_CALL AccessibleGridControl::getAccessibleRole()
185 {
186 ensureIsAlive();
187 return AccessibleRole::PANEL;
188 }
189 // -----------------------------------------------------------------------------
190
191 // XAccessibleComponent -------------------------------------------------------
192
193 Reference< XAccessible > SAL_CALL
getAccessibleAtPoint(const awt::Point & rPoint)194 AccessibleGridControl::getAccessibleAtPoint( const awt::Point& rPoint )
195 {
196 TCSolarGuard aSolarGuard;
197 ::osl::MutexGuard aGuard( getOslMutex() );
198 ensureIsAlive();
199
200 Reference< XAccessible > xChild;
201 sal_Int32 nIndex = 0;
202 if( m_aTable.ConvertPointToControlIndex( nIndex, VCLPoint( rPoint ) ) )
203 xChild = m_aTable.CreateAccessibleControl( nIndex );
204 else
205 {
206 // try whether point is in one of the fixed children
207 // (table, header bars, corner control)
208 Point aPoint( VCLPoint( rPoint ) );
209 for( nIndex = 0; (nIndex < 3) && !xChild.is(); ++nIndex )
210 {
211 Reference< XAccessible > xCurrChild( implGetFixedChild( nIndex ) );
212 Reference< XAccessibleComponent >
213 xCurrChildComp( xCurrChild, uno::UNO_QUERY );
214
215 if( xCurrChildComp.is() &&
216 VCLRectangle( xCurrChildComp->getBounds() ).IsInside( aPoint ) )
217 xChild = xCurrChild;
218 }
219 }
220 return xChild;
221 }
222 // -----------------------------------------------------------------------------
223
grabFocus()224 void SAL_CALL AccessibleGridControl::grabFocus()
225 {
226 TCSolarGuard aSolarGuard;
227 ::osl::MutexGuard aGuard( getOslMutex() );
228 ensureIsAlive();
229 m_aTable.GrabFocus();
230 }
231 // -----------------------------------------------------------------------------
232
getAccessibleKeyBinding()233 Any SAL_CALL AccessibleGridControl::getAccessibleKeyBinding()
234 {
235 ensureIsAlive();
236 return Any();
237 }
238 // -----------------------------------------------------------------------------
239
240 // XServiceInfo ---------------------------------------------------------------
241
getImplementationName()242 OUString SAL_CALL AccessibleGridControl::getImplementationName()
243 {
244 return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.accessibility.AccessibleGridControl" ) );
245 }
246 // -----------------------------------------------------------------------------
247
248 // internal virtual methods ---------------------------------------------------
249
implGetBoundingBox()250 Rectangle AccessibleGridControl::implGetBoundingBox()
251 {
252 Window* pParent = m_aTable.GetAccessibleParentWindow();
253 DBG_ASSERT( pParent, "implGetBoundingBox - missing parent window" );
254 return m_aTable.GetWindowExtentsRelative( pParent );
255 }
256 // -----------------------------------------------------------------------------
257
implGetBoundingBoxOnScreen()258 Rectangle AccessibleGridControl::implGetBoundingBoxOnScreen()
259 {
260 return m_aTable.GetWindowExtentsRelative( NULL );
261 }
262 // internal helper methods ----------------------------------------------------
263
implGetTable()264 Reference< XAccessible > AccessibleGridControl::implGetTable()
265 {
266 if( !m_pImpl->m_xTable.is() )
267 {
268 m_pImpl->m_pTable = createAccessibleTable();
269 m_pImpl->m_xTable = m_pImpl->m_pTable;
270 }
271 return m_pImpl->m_xTable;
272 }
273 // -----------------------------------------------------------------------------
274
275 Reference< XAccessible >
implGetHeaderBar(AccessibleTableControlObjType eObjType)276 AccessibleGridControl::implGetHeaderBar( AccessibleTableControlObjType eObjType )
277 {
278 Reference< XAccessible > xRet;
279 Reference< XAccessible >* pxMember = NULL;
280
281 if( eObjType == TCTYPE_ROWHEADERBAR )
282 pxMember = &m_pImpl->m_xRowHeaderBar;
283 else if( eObjType == TCTYPE_COLUMNHEADERBAR )
284 pxMember = &m_pImpl->m_xColumnHeaderBar;
285
286 if( pxMember )
287 {
288 if( !pxMember->is() )
289 {
290 AccessibleGridControlHeader* pHeaderBar = new AccessibleGridControlHeader(
291 (Reference< XAccessible >)m_pImpl->m_aCreator, m_aTable, eObjType );
292
293 if ( TCTYPE_COLUMNHEADERBAR == eObjType)
294 m_pImpl->m_pColumnHeaderBar = pHeaderBar;
295 else
296 m_pImpl->m_pRowHeaderBar = pHeaderBar;
297
298 *pxMember = pHeaderBar;
299 }
300 xRet = *pxMember;
301 }
302 return xRet;
303 }
304 // -----------------------------------------------------------------------------
305 Reference< XAccessible >
implGetFixedChild(sal_Int32 nChildIndex)306 AccessibleGridControl::implGetFixedChild( sal_Int32 nChildIndex )
307 {
308 Reference< XAccessible > xRet;
309 switch( nChildIndex )
310 {
311 case TCINDEX_COLUMNHEADERBAR:
312 xRet = implGetHeaderBar( TCTYPE_COLUMNHEADERBAR );
313 break;
314 case TCINDEX_ROWHEADERBAR:
315 xRet = implGetHeaderBar( TCTYPE_ROWHEADERBAR );
316 break;
317 case TCINDEX_TABLE:
318 xRet = implGetTable();
319 break;
320 }
321 return xRet;
322 }
323 // -----------------------------------------------------------------------------
createAccessibleTable()324 AccessibleGridControlTable* AccessibleGridControl::createAccessibleTable()
325 {
326 Reference< XAccessible > xCreator = (Reference< XAccessible >)m_pImpl->m_aCreator;
327 DBG_ASSERT( xCreator.is(), "accessibility/extended/AccessibleGirdControl::createAccessibleTable: my creator died - how this?" );
328 return new AccessibleGridControlTable( xCreator, m_aTable, TCTYPE_TABLE );
329 }
330 // -----------------------------------------------------------------------------
commitCellEvent(sal_Int16 _nEventId,const Any & _rNewValue,const Any & _rOldValue)331 void AccessibleGridControl::commitCellEvent(sal_Int16 _nEventId,const Any& _rNewValue,const Any& _rOldValue)
332 {
333 sal_Int32 nChildCount = getAccessibleChildCount();
334 if(nChildCount != 0)
335 {
336 for(sal_Int32 i=0;i<nChildCount;i++)
337 {
338 Reference< XAccessible > xAccessible = getAccessibleChild(i);
339 com::sun::star::uno::Reference< com::sun::star::accessibility::XAccessibleContext > xAccessibleChild = xAccessible->getAccessibleContext();
340 if(m_pImpl->m_xTable == xAccessible)
341 {
342 std::vector< AccessibleGridControlTableCell* > xCellCont = m_pImpl->m_pTable->getCellVector();
343 int nIndex = m_aTable.GetCurrentRow()*m_aTable.GetColumnCount()+m_aTable.GetCurrentColumn();
344 if(!xCellCont.empty() && xCellCont[nIndex])
345 {
346 m_pImpl->m_pCell = xCellCont[nIndex];
347 m_pImpl->m_pCell->commitEvent( _nEventId, _rNewValue, _rOldValue );
348 }
349 }
350 }
351 }
352 else
353 {
354 if ( m_pImpl->m_xTable.is() )
355 m_pImpl->m_pTable->commitEvent(_nEventId,_rNewValue,_rOldValue);
356 }
357 }
commitTableEvent(sal_Int16 _nEventId,const Any & _rNewValue,const Any & _rOldValue)358 void AccessibleGridControl::commitTableEvent(sal_Int16 _nEventId,const Any& _rNewValue,const Any& _rOldValue)
359 {
360 if ( m_pImpl->m_xTable.is() )
361 {
362 if(_nEventId == AccessibleEventId::ACTIVE_DESCENDANT_CHANGED)
363 {
364 Reference< XAccessible > xChild = m_pImpl->m_pTable->getAccessibleChild(m_aTable.GetCurrentRow()*m_aTable.GetColumnCount()+m_aTable.GetCurrentColumn());
365 m_pImpl->m_pTable->commitEvent(_nEventId, makeAny(xChild),_rOldValue);
366 }
367 else if(_nEventId == AccessibleEventId::TABLE_MODEL_CHANGED)
368 {
369 AccessibleTableModelChange aChange;
370 if(_rNewValue >>= aChange)
371 {
372 if(aChange.Type == AccessibleTableModelChangeType::DELETE)
373 {
374 std::vector< AccessibleGridControlTableCell* >::iterator m_pCell = m_pImpl->m_pTable->getCellVector().begin();
375 std::vector< Reference< XAccessible > >::iterator m_xAccessibleVector = m_pImpl->m_pTable->getAccessibleCellVector().begin();
376 int nColCount = m_aTable.GetColumnCount();
377 m_pImpl->m_pTable->getCellVector().erase(m_pCell+nColCount*aChange.FirstRow, m_pCell+nColCount*aChange.LastRow );
378 m_pImpl->m_pTable->getAccessibleCellVector().erase(m_xAccessibleVector+nColCount*aChange.FirstRow, m_xAccessibleVector+nColCount*aChange.LastRow);
379 m_pImpl->m_pTable->commitEvent(_nEventId,_rNewValue,_rOldValue);
380 }
381 else
382 m_pImpl->m_pTable->commitEvent(_nEventId,_rNewValue,_rOldValue);
383 }
384 }
385 else
386 m_pImpl->m_pTable->commitEvent(_nEventId,_rNewValue,_rOldValue);
387 }
388 }
389 // ============================================================================
390 // = AccessibleGridControlAccess
391 // ============================================================================
DBG_NAME(AccessibleGridControlAccess)392 DBG_NAME( AccessibleGridControlAccess )
393 // -----------------------------------------------------------------------------
394 AccessibleGridControlAccess::AccessibleGridControlAccess( const Reference< XAccessible >& _rxParent, IAccessibleTable& _rTable )
395 :m_xParent( _rxParent )
396 ,m_rTable( _rTable )
397 ,m_pContext( NULL )
398 {
399 }
400
401 // -----------------------------------------------------------------------------
~AccessibleGridControlAccess()402 AccessibleGridControlAccess::~AccessibleGridControlAccess()
403 {
404 }
405
406 // -----------------------------------------------------------------------------
dispose()407 void AccessibleGridControlAccess::dispose()
408 {
409 ::osl::MutexGuard aGuard( m_aMutex );
410
411 m_pContext = NULL;
412 ::comphelper::disposeComponent( m_xContext );
413 }
414
415 // -----------------------------------------------------------------------------
getAccessibleContext()416 Reference< XAccessibleContext > SAL_CALL AccessibleGridControlAccess::getAccessibleContext()
417 {
418 ::osl::MutexGuard aGuard( m_aMutex );
419
420 DBG_ASSERT( ( m_pContext && m_xContext.is() ) || ( !m_pContext && !m_xContext.is() ),
421 "accessibility/extended/AccessibleGridControlAccess::getAccessibleContext: inconsistency!" );
422
423 // if the context died meanwhile (we're no listener, so it won't tell us explicitly when this happens),
424 // then reset an re-create.
425 if ( m_pContext && !m_pContext->isAlive() )
426 m_xContext = m_pContext = NULL;
427
428 if ( !m_xContext.is() )
429 m_xContext = m_pContext = new AccessibleGridControl( m_xParent, this, m_rTable );
430
431 return m_xContext;
432 }
433
434 // -----------------------------------------------------------------------------
isContextAlive() const435 bool AccessibleGridControlAccess::isContextAlive() const
436 {
437 return ( NULL != m_pContext ) && m_pContext->isAlive();
438 }
439
440 // ============================================================================
441
442 } // namespace accessibility
443