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