xref: /trunk/main/accessibility/source/extended/AccessibleGridControl.cxx (revision 9c15e1abd703a7953928d7a80655ae1a76a41f6d)
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 
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 // -----------------------------------------------------------------------------
92 AccessibleGridControl::~AccessibleGridControl()
93 {
94 }
95 // -----------------------------------------------------------------------------
96 
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 
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
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 
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
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 
224 void SAL_CALL AccessibleGridControl::grabFocus()
225 {
226     TCSolarGuard aSolarGuard;
227     ::osl::MutexGuard aGuard( getOslMutex() );
228     ensureIsAlive();
229         m_aTable.GrabFocus();
230 }
231 // -----------------------------------------------------------------------------
232 
233 Any SAL_CALL AccessibleGridControl::getAccessibleKeyBinding()
234 {
235     ensureIsAlive();
236     return Any();
237 }
238 // -----------------------------------------------------------------------------
239 
240 // XServiceInfo ---------------------------------------------------------------
241 
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 
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 
258 Rectangle AccessibleGridControl::implGetBoundingBoxOnScreen()
259 {
260     return m_aTable.GetWindowExtentsRelative( NULL );
261 }
262 // internal helper methods ----------------------------------------------------
263 
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 >
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 >
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 // -----------------------------------------------------------------------------
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 // -----------------------------------------------------------------------------
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 }
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 // ============================================================================
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 // -----------------------------------------------------------------------------
402 AccessibleGridControlAccess::~AccessibleGridControlAccess()
403 {
404 }
405 
406 // -----------------------------------------------------------------------------
407 void AccessibleGridControlAccess::dispose()
408 {
409     ::osl::MutexGuard aGuard( m_aMutex );
410 
411     m_pContext = NULL;
412     ::comphelper::disposeComponent( m_xContext );
413 }
414 
415 // -----------------------------------------------------------------------------
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 // -----------------------------------------------------------------------------
435 bool AccessibleGridControlAccess::isContextAlive() const
436 {
437     return  ( NULL != m_pContext ) && m_pContext->isAlive();
438 }
439 
440 // ============================================================================
441 
442 }   // namespace accessibility
443