xref: /trunk/main/accessibility/source/extended/AccessibleGridControl.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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