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     throw ( uno::RuntimeException )
132 {
133 	TCSolarGuard aSolarGuard;
134 	::osl::MutexGuard aGuard( getOslMutex() );
135 	ensureIsAlive();
136 	return m_aTable.GetAccessibleControlCount();
137 }
138 // -----------------------------------------------------------------------------
139 
140 Reference< XAccessible > SAL_CALL
getAccessibleChild(sal_Int32 nChildIndex)141 AccessibleGridControl::getAccessibleChild( sal_Int32 nChildIndex )
142     throw ( lang::IndexOutOfBoundsException, uno::RuntimeException )
143 {
144 	TCSolarGuard aSolarGuard;
145 	::osl::MutexGuard aGuard( getOslMutex() );
146 
147 	if (nChildIndex<0 || nChildIndex>=getAccessibleChildCount())
148 		throw IndexOutOfBoundsException();
149 
150 	Reference< XAccessible > xChild;
151 	if (isAlive())
152 	{
153 		if(nChildIndex == 0 && m_aTable.HasColHeader())
154 		{
155 			if(!m_pImpl->m_xColumnHeaderBar.is())
156 			{
157 				AccessibleGridControlHeader* pColHeaderBar = new AccessibleGridControlHeader(m_pImpl->m_aCreator, m_aTable, svt::table::TCTYPE_COLUMNHEADERBAR);
158 				m_pImpl->m_xColumnHeaderBar = pColHeaderBar;
159 			}
160 			xChild = m_pImpl->m_xColumnHeaderBar;
161 		}
162 		else if(m_aTable.HasRowHeader() && (nChildIndex == 1 || nChildIndex == 0))
163 		{
164 			if(!m_pImpl->m_xRowHeaderBar.is())
165 			{
166 				AccessibleGridControlHeader* pRowHeaderBar = new AccessibleGridControlHeader(m_pImpl->m_aCreator, m_aTable, svt::table::TCTYPE_ROWHEADERBAR);
167 				m_pImpl->m_xRowHeaderBar = pRowHeaderBar;
168 			}
169 			xChild = m_pImpl->m_xRowHeaderBar;
170 		}
171 		else
172 		{
173 			if(!m_pImpl->m_xTable.is())
174 			{
175 			AccessibleGridControlTable* pTable = new AccessibleGridControlTable(m_pImpl->m_aCreator, m_aTable, svt::table::TCTYPE_TABLE);
176 			m_pImpl->m_xTable = pTable;
177 				m_pImpl->m_pTable = pTable;
178 			}
179 			xChild = m_pImpl->m_xTable;
180 		}
181 	}
182 	return xChild;
183 }
184 // -----------------------------------------------------------------------------
185 
getAccessibleRole()186 sal_Int16 SAL_CALL AccessibleGridControl::getAccessibleRole()
187     throw ( uno::RuntimeException )
188 {
189 	ensureIsAlive();
190 	return AccessibleRole::PANEL;
191 }
192 // -----------------------------------------------------------------------------
193 
194 // XAccessibleComponent -------------------------------------------------------
195 
196 Reference< XAccessible > SAL_CALL
getAccessibleAtPoint(const awt::Point & rPoint)197 AccessibleGridControl::getAccessibleAtPoint( const awt::Point& rPoint )
198     throw ( uno::RuntimeException )
199 {
200 	TCSolarGuard aSolarGuard;
201 	::osl::MutexGuard aGuard( getOslMutex() );
202 	ensureIsAlive();
203 
204 	Reference< XAccessible > xChild;
205 	sal_Int32 nIndex = 0;
206 	if( m_aTable.ConvertPointToControlIndex( nIndex, VCLPoint( rPoint ) ) )
207 		xChild = m_aTable.CreateAccessibleControl( nIndex );
208 	else
209 	{
210 		// try whether point is in one of the fixed children
211 		// (table, header bars, corner control)
212 		Point aPoint( VCLPoint( rPoint ) );
213 		for( nIndex = 0; (nIndex < 3) && !xChild.is(); ++nIndex )
214 		{
215 			Reference< XAccessible > xCurrChild( implGetFixedChild( nIndex ) );
216 			Reference< XAccessibleComponent >
217 			xCurrChildComp( xCurrChild, uno::UNO_QUERY );
218 
219 			if( xCurrChildComp.is() &&
220 				VCLRectangle( xCurrChildComp->getBounds() ).IsInside( aPoint ) )
221 			xChild = xCurrChild;
222 		}
223 	}
224 	return xChild;
225 }
226 // -----------------------------------------------------------------------------
227 
grabFocus()228 void SAL_CALL AccessibleGridControl::grabFocus()
229     throw ( uno::RuntimeException )
230 {
231 	TCSolarGuard aSolarGuard;
232 	::osl::MutexGuard aGuard( getOslMutex() );
233 	ensureIsAlive();
234     	m_aTable.GrabFocus();
235 }
236 // -----------------------------------------------------------------------------
237 
getAccessibleKeyBinding()238 Any SAL_CALL AccessibleGridControl::getAccessibleKeyBinding()
239     throw ( uno::RuntimeException )
240 {
241 	ensureIsAlive();
242 	return Any();
243 }
244 // -----------------------------------------------------------------------------
245 
246 // XServiceInfo ---------------------------------------------------------------
247 
getImplementationName()248 OUString SAL_CALL AccessibleGridControl::getImplementationName()
249     throw ( uno::RuntimeException )
250 {
251 	return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.accessibility.AccessibleGridControl" ) );
252 }
253 // -----------------------------------------------------------------------------
254 
255 // internal virtual methods ---------------------------------------------------
256 
implGetBoundingBox()257 Rectangle AccessibleGridControl::implGetBoundingBox()
258 {
259 	Window* pParent = m_aTable.GetAccessibleParentWindow();
260 	DBG_ASSERT( pParent, "implGetBoundingBox - missing parent window" );
261 	return m_aTable.GetWindowExtentsRelative( pParent );
262 }
263 // -----------------------------------------------------------------------------
264 
implGetBoundingBoxOnScreen()265 Rectangle AccessibleGridControl::implGetBoundingBoxOnScreen()
266 {
267 	return m_aTable.GetWindowExtentsRelative( NULL );
268 }
269 // internal helper methods ----------------------------------------------------
270 
implGetTable()271 Reference< XAccessible > AccessibleGridControl::implGetTable()
272 {
273 	if( !m_pImpl->m_xTable.is() )
274 	{
275 		m_pImpl->m_pTable = createAccessibleTable();
276 		m_pImpl->m_xTable  = m_pImpl->m_pTable;
277 	}
278 	return m_pImpl->m_xTable;
279 }
280 // -----------------------------------------------------------------------------
281 
282 Reference< XAccessible >
implGetHeaderBar(AccessibleTableControlObjType eObjType)283 AccessibleGridControl::implGetHeaderBar( AccessibleTableControlObjType eObjType )
284 {
285 	Reference< XAccessible > xRet;
286 	Reference< XAccessible >* pxMember = NULL;
287 
288 	if( eObjType == TCTYPE_ROWHEADERBAR )
289 		pxMember = &m_pImpl->m_xRowHeaderBar;
290 	else if( eObjType ==  TCTYPE_COLUMNHEADERBAR )
291 		pxMember = &m_pImpl->m_xColumnHeaderBar;
292 
293 	if( pxMember )
294 	{
295 		if( !pxMember->is() )
296 		{
297 			AccessibleGridControlHeader* pHeaderBar = new AccessibleGridControlHeader(
298 				(Reference< XAccessible >)m_pImpl->m_aCreator, m_aTable, eObjType );
299 
300 			if ( TCTYPE_COLUMNHEADERBAR == eObjType)
301 				m_pImpl->m_pColumnHeaderBar = pHeaderBar;
302 			else
303 				m_pImpl->m_pRowHeaderBar	= pHeaderBar;
304 
305 			*pxMember = pHeaderBar;
306 		}
307 		xRet = *pxMember;
308 	}
309 	return xRet;
310 }
311 // -----------------------------------------------------------------------------
312 Reference< XAccessible >
implGetFixedChild(sal_Int32 nChildIndex)313 AccessibleGridControl::implGetFixedChild( sal_Int32 nChildIndex )
314 {
315 	Reference< XAccessible > xRet;
316 	switch( nChildIndex )
317 	{
318       	case TCINDEX_COLUMNHEADERBAR:
319             xRet = implGetHeaderBar( TCTYPE_COLUMNHEADERBAR );
320 	    break;
321         case TCINDEX_ROWHEADERBAR:
322             xRet = implGetHeaderBar( TCTYPE_ROWHEADERBAR );
323 	    break;
324         case TCINDEX_TABLE:
325             xRet = implGetTable();
326 	    break;
327 	}
328 	return xRet;
329 }
330 // -----------------------------------------------------------------------------
createAccessibleTable()331 AccessibleGridControlTable* AccessibleGridControl::createAccessibleTable()
332 {
333 	Reference< XAccessible > xCreator = (Reference< XAccessible >)m_pImpl->m_aCreator;
334     	DBG_ASSERT( xCreator.is(), "accessibility/extended/AccessibleGirdControl::createAccessibleTable: my creator died - how this?" );
335 	return new AccessibleGridControlTable( xCreator, m_aTable, TCTYPE_TABLE );
336 }
337 // -----------------------------------------------------------------------------
commitCellEvent(sal_Int16 _nEventId,const Any & _rNewValue,const Any & _rOldValue)338 void AccessibleGridControl::commitCellEvent(sal_Int16 _nEventId,const Any& _rNewValue,const Any& _rOldValue)
339 {
340 	sal_Int32 nChildCount = getAccessibleChildCount();
341     if(nChildCount != 0)
342 	{
343 		for(sal_Int32 i=0;i<nChildCount;i++)
344 		{
345 			Reference< XAccessible > xAccessible = getAccessibleChild(i);
346 			com::sun::star::uno::Reference< com::sun::star::accessibility::XAccessibleContext > xAccessibleChild = xAccessible->getAccessibleContext();
347 			if(m_pImpl->m_xTable == xAccessible)
348 			{
349 				std::vector< AccessibleGridControlTableCell* > xCellCont = m_pImpl->m_pTable->getCellVector();
350 				int nIndex = m_aTable.GetCurrentRow()*m_aTable.GetColumnCount()+m_aTable.GetCurrentColumn();
351 				if(!xCellCont.empty() && xCellCont[nIndex])
352 				{
353 					m_pImpl->m_pCell = xCellCont[nIndex];
354 					m_pImpl->m_pCell->commitEvent( _nEventId, _rNewValue, _rOldValue );
355 				}
356 			}
357 		}
358 	}
359 	else
360 	{
361 		if ( m_pImpl->m_xTable.is() )
362 			m_pImpl->m_pTable->commitEvent(_nEventId,_rNewValue,_rOldValue);
363 	}
364 }
commitTableEvent(sal_Int16 _nEventId,const Any & _rNewValue,const Any & _rOldValue)365 void AccessibleGridControl::commitTableEvent(sal_Int16 _nEventId,const Any& _rNewValue,const Any& _rOldValue)
366 {
367 	if ( m_pImpl->m_xTable.is() )
368 	{
369 		if(_nEventId == AccessibleEventId::ACTIVE_DESCENDANT_CHANGED)
370 		{
371 			Reference< XAccessible > xChild = m_pImpl->m_pTable->getAccessibleChild(m_aTable.GetCurrentRow()*m_aTable.GetColumnCount()+m_aTable.GetCurrentColumn());
372 			m_pImpl->m_pTable->commitEvent(_nEventId, makeAny(xChild),_rOldValue);
373 		}
374 		else if(_nEventId == AccessibleEventId::TABLE_MODEL_CHANGED)
375 		{
376 			AccessibleTableModelChange aChange;
377 			if(_rNewValue >>= aChange)
378 			{
379 				if(aChange.Type == AccessibleTableModelChangeType::DELETE)
380 				{
381 					std::vector< AccessibleGridControlTableCell* >::iterator m_pCell = m_pImpl->m_pTable->getCellVector().begin();
382 					std::vector< Reference< XAccessible > >::iterator m_xAccessibleVector = m_pImpl->m_pTable->getAccessibleCellVector().begin();
383 					int nColCount = m_aTable.GetColumnCount();
384 					m_pImpl->m_pTable->getCellVector().erase(m_pCell+nColCount*aChange.FirstRow, m_pCell+nColCount*aChange.LastRow );
385 					m_pImpl->m_pTable->getAccessibleCellVector().erase(m_xAccessibleVector+nColCount*aChange.FirstRow, m_xAccessibleVector+nColCount*aChange.LastRow);
386 					m_pImpl->m_pTable->commitEvent(_nEventId,_rNewValue,_rOldValue);
387 				}
388 				else
389 					m_pImpl->m_pTable->commitEvent(_nEventId,_rNewValue,_rOldValue);
390 			}
391 		}
392 		else
393 			m_pImpl->m_pTable->commitEvent(_nEventId,_rNewValue,_rOldValue);
394 	}
395 }
396 // ============================================================================
397 // = AccessibleGridControlAccess
398 // ============================================================================
DBG_NAME(AccessibleGridControlAccess)399 DBG_NAME( AccessibleGridControlAccess )
400 // -----------------------------------------------------------------------------
401 AccessibleGridControlAccess::AccessibleGridControlAccess( const Reference< XAccessible >& _rxParent, IAccessibleTable& _rTable )
402         :m_xParent( _rxParent )
403         ,m_rTable( _rTable )
404         ,m_pContext( NULL )
405 {
406 }
407 
408 // -----------------------------------------------------------------------------
~AccessibleGridControlAccess()409 AccessibleGridControlAccess::~AccessibleGridControlAccess()
410 {
411 }
412 
413 // -----------------------------------------------------------------------------
dispose()414 void AccessibleGridControlAccess::dispose()
415 {
416 	::osl::MutexGuard aGuard( m_aMutex );
417 
418 	m_pContext = NULL;
419 	::comphelper::disposeComponent( m_xContext );
420 }
421 
422 // -----------------------------------------------------------------------------
getAccessibleContext()423 Reference< XAccessibleContext > SAL_CALL AccessibleGridControlAccess::getAccessibleContext() throw ( RuntimeException )
424 {
425 	::osl::MutexGuard aGuard( m_aMutex );
426 
427 	DBG_ASSERT( ( m_pContext && m_xContext.is() ) || ( !m_pContext && !m_xContext.is() ),
428         "accessibility/extended/AccessibleGridControlAccess::getAccessibleContext: inconsistency!" );
429 
430 	// if the context died meanwhile (we're no listener, so it won't tell us explicitily when this happens),
431 	// then reset an re-create.
432 	if ( m_pContext && !m_pContext->isAlive() )
433 		m_xContext = m_pContext = NULL;
434 
435 	if ( !m_xContext.is() )
436 		m_xContext = m_pContext = new AccessibleGridControl( m_xParent, this, m_rTable );
437 
438 	return m_xContext;
439 }
440 
441 // -----------------------------------------------------------------------------
isContextAlive() const442 bool AccessibleGridControlAccess::isContextAlive() const
443 {
444 	return  ( NULL != m_pContext ) && m_pContext->isAlive();
445 }
446 
447 // ============================================================================
448 
449 }   // namespace accessibility
450