xref: /trunk/main/svx/source/table/accessibletableshape.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_svx.hxx"
30 
31 #include <com/sun/star/table/XMergeableCell.hpp>
32 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
33 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
34 
35 #include <comphelper/accessiblewrapper.hxx>
36 #include <vos/mutex.hxx>
37 #include <tools/debug.hxx>
38 #include <vcl/svapp.hxx>
39 
40 #include <svx/AccessibleTableShape.hxx>
41 #include "tablecontroller.hxx"
42 #include "accessiblecell.hxx"
43 
44 #include <algorithm>
45 
46 #include <cppuhelper/implbase1.hxx>
47 
48 using ::rtl::OUString;
49 
50 using namespace ::accessibility;
51 using namespace ::sdr::table;
52 using namespace ::com::sun::star::accessibility;
53 using namespace ::com::sun::star::uno;
54 using namespace ::com::sun::star::beans;
55 using namespace ::com::sun::star::util;
56 using namespace ::com::sun::star::lang;
57 using namespace ::com::sun::star::drawing;
58 using namespace ::com::sun::star::table;
59 using namespace ::com::sun::star::container;
60 
61 #define C2U(x) OUString(RTL_CONSTASCII_USTRINGPARAM(x))
62 
63 namespace accessibility
64 {
65 
66 struct hash
67 {
68     std::size_t operator()( const Reference< XCell >& xCell ) const
69     {
70         return std::size_t( xCell.get() );
71     }
72 };
73 
74 typedef std::hash_map< Reference< XCell >, rtl::Reference< AccessibleCell >, hash > AccessibleCellMap;
75 
76 //-----------------------------------------------------------------------------
77 // AccessibleTableShapeImpl
78 //-----------------------------------------------------------------------------
79 
80 class AccessibleTableShapeImpl : public cppu::WeakImplHelper1< XModifyListener >
81 {
82 public:
83     AccessibleTableShapeImpl( AccessibleShapeTreeInfo& rShapeTreeInfo );
84 
85     void init( const Reference< XAccessible>& xAccessible, const Reference< XTable >& xTable );
86     void dispose();
87 
88     Reference< XAccessible > getAccessibleChild( sal_Int32 i ) throw(IndexOutOfBoundsException);
89     void getColumnAndRow( sal_Int32 nChildIndex, sal_Int32& rnColumn, sal_Int32& rnRow ) throw (IndexOutOfBoundsException );
90 
91     // XModifyListener
92     virtual void SAL_CALL modified( const EventObject& aEvent ) throw (RuntimeException);
93 
94     // XEventListener
95     virtual void SAL_CALL disposing( const EventObject& Source ) throw (RuntimeException);
96 
97     AccessibleShapeTreeInfo& mrShapeTreeInfo;
98     Reference< XTable > mxTable;
99     AccessibleCellMap maChildMap;
100     Reference< XAccessible> mxAccessible;
101 };
102 
103 //-----------------------------------------------------------------------------
104 
105 AccessibleTableShapeImpl::AccessibleTableShapeImpl( AccessibleShapeTreeInfo& rShapeTreeInfo )
106 : mrShapeTreeInfo( rShapeTreeInfo )
107 {
108 }
109 
110 //-----------------------------------------------------------------------------
111 
112 void AccessibleTableShapeImpl::init( const Reference< XAccessible>& xAccessible, const Reference< XTable >& xTable )
113 {
114     mxAccessible = xAccessible;
115     mxTable = xTable;
116 
117     if( mxTable.is() )
118     {
119         Reference< XModifyListener > xListener( this );
120         mxTable->addModifyListener( xListener );
121     }
122 }
123 
124 //-----------------------------------------------------------------------------
125 
126 void AccessibleTableShapeImpl::dispose()
127 {
128     if( mxTable.is() )
129     {
130         Reference< XModifyListener > xListener( this );
131         mxTable->removeModifyListener( xListener );
132         mxTable.clear();
133     }
134     mxAccessible.clear();
135 }
136 
137 //-----------------------------------------------------------------------------
138 
139 Reference< XAccessible > AccessibleTableShapeImpl::getAccessibleChild( sal_Int32 nChildIndex ) throw(IndexOutOfBoundsException)
140 {
141     sal_Int32 nColumn = 0, nRow = 0;
142     getColumnAndRow( nChildIndex, nColumn, nRow );
143 
144     Reference< XCell > xCell( mxTable->getCellByPosition( nColumn, nRow ) );
145     AccessibleCellMap::iterator iter( maChildMap.find( xCell ) );
146 
147     if( iter != maChildMap.end() )
148     {
149         Reference< XAccessible > xChild( (*iter).second.get() );
150         return xChild;
151     }
152     else
153     {
154         CellRef xCellRef( dynamic_cast< Cell* >( xCell.get() ) );
155 
156         rtl::Reference< AccessibleCell > xAccessibleCell( new AccessibleCell( mxAccessible, xCellRef, nChildIndex, mrShapeTreeInfo ) );
157 
158         maChildMap[xCell] = xAccessibleCell;
159 
160         xAccessibleCell->Init();
161 
162         Reference< XAccessible > xChild( xAccessibleCell.get() );
163         return xChild;
164     }
165 }
166 
167 //-----------------------------------------------------------------------------
168 
169 void AccessibleTableShapeImpl::getColumnAndRow( sal_Int32 nChildIndex, sal_Int32& rnColumn, sal_Int32& rnRow ) throw (IndexOutOfBoundsException )
170 {
171     rnRow = 0;
172     rnColumn = nChildIndex;
173 
174     if( mxTable.is() )
175     {
176         const sal_Int32 nColumnCount = mxTable->getColumnCount();
177         while( rnColumn >= nColumnCount )
178         {
179             rnRow++;
180             rnColumn -= nColumnCount;
181         }
182 
183         if( rnRow < mxTable->getRowCount() )
184             return;
185     }
186 
187     throw IndexOutOfBoundsException();
188 }
189 
190 // XModifyListener
191 void SAL_CALL AccessibleTableShapeImpl::modified( const EventObject& /*aEvent*/ ) throw (RuntimeException)
192 {
193     if( mxTable.is() ) try
194     {
195         // structural changes may have happened to the table, validate all accessible cell instances
196         AccessibleCellMap aTempChildMap;
197         aTempChildMap.swap( maChildMap );
198 
199         // first move all still existing cells to maChildMap again and update their index
200 
201         const sal_Int32 nRowCount = mxTable->getRowCount();
202         const sal_Int32 nColCount = mxTable->getColumnCount();
203 
204         sal_Int32 nChildIndex = 0;
205 
206         for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
207         {
208             for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
209             {
210                 Reference< XCell > xCell( mxTable->getCellByPosition( nCol, nRow ) );
211                 AccessibleCellMap::iterator iter( aTempChildMap.find( xCell ) );
212 
213                 if( iter != aTempChildMap.end() )
214                 {
215                     rtl::Reference< AccessibleCell > xAccessibleCell( (*iter).second );
216                     xAccessibleCell->setIndexInParent( nChildIndex );
217                     xAccessibleCell->CommitChange(AccessibleEventId::VISIBLE_DATA_CHANGED, Any(), Any());
218 
219                     // move still existing cell from temporary child map to our child map
220                     maChildMap[xCell] = xAccessibleCell;
221                     aTempChildMap.erase( iter );
222                 }
223 
224                 ++nChildIndex;
225             }
226         }
227 
228         // all accessible cell instances still left in aTempChildMap must be disposed
229         // as they are no longer part of the table
230 
231         for( AccessibleCellMap::iterator iter( aTempChildMap.begin() ); iter != aTempChildMap.end(); iter++ )
232         {
233             (*iter).second->dispose();
234         }
235     }
236     catch( Exception& )
237     {
238         DBG_ERROR("svx::AccessibleTableShape::modified(), exception caught!");
239     }
240 }
241 
242 // XEventListener
243 void SAL_CALL AccessibleTableShapeImpl::disposing( const EventObject& /*Source*/ ) throw (RuntimeException)
244 {
245 }
246 
247 //-----------------------------------------------------------------------------
248 // AccessibleTableShape
249 //-----------------------------------------------------------------------------
250 
251 //-----------------------------------------------------------------------------
252 
253 AccessibleTableShape::AccessibleTableShape( const AccessibleShapeInfo& rShapeInfo, const AccessibleShapeTreeInfo& rShapeTreeInfo)
254 : AccessibleTableShape_Base(rShapeInfo, rShapeTreeInfo)
255 , mxImpl( new AccessibleTableShapeImpl( maShapeTreeInfo ) )
256 {
257 }
258 
259 //-----------------------------------------------------------------------------
260 
261 AccessibleTableShape::~AccessibleTableShape (void)
262 {
263 }
264 
265 //-----------------------------------------------------------------------------
266 
267 void AccessibleTableShape::Init()
268 {
269     try
270     {
271 
272         Reference< XPropertySet > xSet( mxShape, UNO_QUERY_THROW );
273         Reference< XTable > xTable( xSet->getPropertyValue(C2U("Model")), UNO_QUERY_THROW );
274 
275         mxImpl->init( this, xTable );
276     }
277     catch( Exception& )
278     {
279         DBG_ERROR("AccessibleTableShape::init(), exception caught?");
280     }
281 
282     AccessibleTableShape_Base::Init();
283 }
284 
285 //-----------------------------------------------------------------------------
286 
287 SvxTableController* AccessibleTableShape::getTableController()
288 {
289     SdrView* pView = maShapeTreeInfo.GetSdrView ();
290     if( pView )
291         return dynamic_cast< SvxTableController* >( pView->getSelectionController().get() );
292     else
293         return 0;
294 }
295 
296 //-----------------------------------------------------------------------------
297 // XInterface
298 //-----------------------------------------------------------------------------
299 
300 Any SAL_CALL AccessibleTableShape::queryInterface( const Type& aType ) throw (RuntimeException)
301 {
302     return AccessibleTableShape_Base::queryInterface( aType );
303 }
304 
305 //-----------------------------------------------------------------------------
306 
307 void SAL_CALL AccessibleTableShape::acquire(  ) throw ()
308 {
309     AccessibleTableShape_Base::acquire();
310 }
311 
312 //-----------------------------------------------------------------------------
313 
314 void SAL_CALL AccessibleTableShape::release(  ) throw ()
315 {
316     AccessibleTableShape_Base::release();
317 }
318 
319 //-----------------------------------------------------------------------------
320 // XAccessible
321 //-----------------------------------------------------------------------------
322 
323 Reference< XAccessibleContext > SAL_CALL AccessibleTableShape::getAccessibleContext(void) throw (RuntimeException)
324 {
325     return AccessibleShape::getAccessibleContext ();
326 }
327 
328 //-----------------------------------------------------------------------------
329 OUString SAL_CALL AccessibleTableShape::getImplementationName(void) throw (RuntimeException)
330 {
331     return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.accessibility.AccessibleTableShape" ) );
332 }
333 
334 //-----------------------------------------------------------------------------
335 
336 OUString AccessibleTableShape::CreateAccessibleBaseName(void) throw (RuntimeException)
337 {
338     return OUString (RTL_CONSTASCII_USTRINGPARAM("TableShape"));;
339 }
340 
341 //--------------------------------------------------------------------
342 
343 sal_Int32 SAL_CALL AccessibleTableShape::getAccessibleChildCount( ) throw(RuntimeException)
344 {
345     ::vos::OGuard aSolarGuard(::Application::GetSolarMutex());
346     return mxImpl->mxTable.is() ? mxImpl->mxTable->getRowCount() * mxImpl->mxTable->getColumnCount() : 0;
347 }
348 
349 //--------------------------------------------------------------------
350 Reference< XAccessible > SAL_CALL AccessibleTableShape::getAccessibleChild( sal_Int32 i ) throw(IndexOutOfBoundsException, RuntimeException)
351 {
352     ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
353     ThrowIfDisposed();
354 
355     return mxImpl->getAccessibleChild( i );
356 }
357 
358 //--------------------------------------------------------------------
359 Reference< XAccessibleRelationSet > SAL_CALL AccessibleTableShape::getAccessibleRelationSet(  ) throw (RuntimeException)
360 {
361     return AccessibleShape::getAccessibleRelationSet( );
362 }
363 
364 //--------------------------------------------------------------------
365 
366 sal_Int16 SAL_CALL AccessibleTableShape::getAccessibleRole (void) throw (RuntimeException)
367 {
368     return AccessibleRole::TABLE;
369 }
370 
371 //--------------------------------------------------------------------
372 
373 void SAL_CALL AccessibleTableShape::disposing (void)
374 {
375     mxImpl->dispose();
376 
377     // let the base do it's stuff
378     AccessibleShape::disposing();
379 }
380 
381 //--------------------------------------------------------------------
382 // XAccessibleTable
383 //--------------------------------------------------------------------
384 
385 sal_Int32 SAL_CALL AccessibleTableShape::getAccessibleRowCount() throw (RuntimeException)
386 {
387     ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
388     return mxImpl->mxTable.is() ? mxImpl->mxTable->getRowCount() : 0;
389 }
390 
391 //--------------------------------------------------------------------
392 
393 sal_Int32 SAL_CALL AccessibleTableShape::getAccessibleColumnCount(  ) throw (RuntimeException)
394 {
395     ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
396     return mxImpl->mxTable.is() ? mxImpl->mxTable->getColumnCount() : 0;
397 }
398 
399 //--------------------------------------------------------------------
400 
401 OUString SAL_CALL AccessibleTableShape::getAccessibleRowDescription( sal_Int32 nRow ) throw (IndexOutOfBoundsException, RuntimeException)
402 {
403     checkCellPosition( 0, nRow );
404     return OUString();
405 }
406 
407 //--------------------------------------------------------------------
408 
409 OUString SAL_CALL AccessibleTableShape::getAccessibleColumnDescription( sal_Int32 nColumn ) throw (IndexOutOfBoundsException, RuntimeException)
410 {
411     ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
412     checkCellPosition( nColumn, 0 );
413     return OUString();
414 }
415 
416 //--------------------------------------------------------------------
417 
418 sal_Int32 SAL_CALL AccessibleTableShape::getAccessibleRowExtentAt( sal_Int32 nRow, sal_Int32 nColumn ) throw (IndexOutOfBoundsException, RuntimeException)
419 {
420     ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
421     checkCellPosition( nColumn, nRow );
422     if( mxImpl->mxTable.is() )
423     {
424         Reference< XMergeableCell > xCell( mxImpl->mxTable->getCellByPosition( nColumn, nRow ), UNO_QUERY );
425         if( xCell.is() )
426             return xCell->getRowSpan();
427     }
428     return 1;
429 }
430 
431 //--------------------------------------------------------------------
432 
433 sal_Int32 SAL_CALL AccessibleTableShape::getAccessibleColumnExtentAt( sal_Int32 nRow, sal_Int32 nColumn ) throw (IndexOutOfBoundsException, RuntimeException)
434 {
435     ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
436     checkCellPosition( nColumn, nRow );
437     if( mxImpl->mxTable.is() )
438     {
439         Reference< XMergeableCell > xCell( mxImpl->mxTable->getCellByPosition( nColumn, nRow ), UNO_QUERY );
440         if( xCell.is() )
441             return xCell->getColumnSpan();
442     }
443     return 1;
444 }
445 
446 //--------------------------------------------------------------------
447 
448 Reference< XAccessibleTable > SAL_CALL AccessibleTableShape::getAccessibleRowHeaders(  ) throw (RuntimeException)
449 {
450     Reference< XAccessibleTable > xRet( this ); // todo
451     return xRet;
452 }
453 
454 //--------------------------------------------------------------------
455 
456 Reference< XAccessibleTable > SAL_CALL AccessibleTableShape::getAccessibleColumnHeaders(  ) throw (RuntimeException)
457 {
458     Reference< XAccessibleTable > xRet( this ); // todo
459     return xRet;
460 }
461 
462 //--------------------------------------------------------------------
463 
464 Sequence< sal_Int32 > SAL_CALL AccessibleTableShape::getSelectedAccessibleRows(  ) throw (RuntimeException)
465 {
466     Sequence< sal_Int32 > aRet;
467     return aRet;
468 }
469 
470 //--------------------------------------------------------------------
471 
472 Sequence< sal_Int32 > SAL_CALL AccessibleTableShape::getSelectedAccessibleColumns(  ) throw (RuntimeException)
473 {
474     Sequence< sal_Int32 > aRet;
475     return aRet;
476 }
477 
478 //--------------------------------------------------------------------
479 
480 sal_Bool SAL_CALL AccessibleTableShape::isAccessibleRowSelected( sal_Int32 nRow ) throw (IndexOutOfBoundsException, RuntimeException)
481 {
482     ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
483     checkCellPosition( 0, nRow );
484     return sal_False;
485 }
486 
487 //--------------------------------------------------------------------
488 
489 sal_Bool SAL_CALL AccessibleTableShape::isAccessibleColumnSelected( sal_Int32 nColumn ) throw (IndexOutOfBoundsException, RuntimeException)
490 {
491     ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
492     checkCellPosition( nColumn, 0 );
493     return sal_False;
494 }
495 
496 //--------------------------------------------------------------------
497 
498 Reference< XAccessible > SAL_CALL AccessibleTableShape::getAccessibleCellAt( sal_Int32 nRow, sal_Int32 nColumn ) throw (IndexOutOfBoundsException, RuntimeException)
499 {
500     ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
501     checkCellPosition( nColumn, nRow );
502 
503     sal_Int32 nChildIndex = 0;
504     if( mxImpl->mxTable.is() )
505         nChildIndex = mxImpl->mxTable->getColumnCount() * nRow + nColumn;
506 
507     return getAccessibleChild( nChildIndex );
508 }
509 
510 //--------------------------------------------------------------------
511 
512 Reference< XAccessible > SAL_CALL AccessibleTableShape::getAccessibleCaption(  ) throw (RuntimeException)
513 {
514     Reference< XAccessible > xRet;
515     return xRet;
516 }
517 
518 //--------------------------------------------------------------------
519 
520 Reference< XAccessible > SAL_CALL AccessibleTableShape::getAccessibleSummary(  ) throw (RuntimeException)
521 {
522     Reference< XAccessible > xRet;
523     return xRet;
524 }
525 
526 //--------------------------------------------------------------------
527 
528 sal_Bool SAL_CALL AccessibleTableShape::isAccessibleSelected( sal_Int32 nRow, sal_Int32 nColumn ) throw (IndexOutOfBoundsException, RuntimeException)
529 {
530     ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
531     checkCellPosition( nColumn, nRow );
532 
533     SvxTableController* pController = getTableController();
534     if( pController && pController->hasSelectedCells() )
535     {
536         CellPos aFirstPos, aLastPos;
537         pController->getSelectedCells( aFirstPos, aLastPos );
538         if( (aFirstPos.mnRow <= nRow) && (aFirstPos.mnCol <= nColumn) && (nRow <= aLastPos.mnRow) && (nColumn <= aLastPos.mnCol) )
539             return sal_True;
540     }
541 
542     return sal_False;
543 }
544 
545 //--------------------------------------------------------------------
546 
547 sal_Int32 SAL_CALL AccessibleTableShape::getAccessibleIndex( sal_Int32 nRow, sal_Int32 nColumn ) throw (IndexOutOfBoundsException, RuntimeException)
548 {
549     ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
550     checkCellPosition( nColumn, nRow );
551     return  mxImpl->mxTable.is() ? (nRow * mxImpl->mxTable->getColumnCount() + nColumn) : 0;
552 }
553 
554 //--------------------------------------------------------------------
555 
556 sal_Int32 SAL_CALL AccessibleTableShape::getAccessibleRow( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
557 {
558     ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
559     sal_Int32 nColumn = 0, nRow = 0;
560     mxImpl->getColumnAndRow( nChildIndex, nColumn, nRow );
561     return nRow;
562 }
563 
564 //--------------------------------------------------------------------
565 
566 sal_Int32 SAL_CALL AccessibleTableShape::getAccessibleColumn( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
567 {
568     ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
569     sal_Int32 nColumn = 0, nRow = 0;
570     mxImpl->getColumnAndRow( nChildIndex, nColumn, nRow );
571     return nChildIndex;
572 }
573 
574 //--------------------------------------------------------------------
575 // XAccessibleSelection
576 //--------------------------------------------------------------------
577 
578 void SAL_CALL AccessibleTableShape::selectAccessibleChild( sal_Int32 nChildIndex ) throw ( IndexOutOfBoundsException, RuntimeException )
579 {
580     ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
581     CellPos aPos;
582     mxImpl->getColumnAndRow( nChildIndex, aPos.mnCol, aPos.mnRow );
583 
584     // todo, select table shape?!?
585     SvxTableController* pController = getTableController();
586     if( pController )
587     {
588         CellPos aFirstPos( aPos ), aLastPos( aPos );
589         if( pController->hasSelectedCells() )
590         {
591             pController->getSelectedCells( aFirstPos, aLastPos );
592 
593             aFirstPos.mnRow = std::min( aFirstPos.mnRow, aPos.mnRow );
594             aFirstPos.mnCol = std::min( aFirstPos.mnCol, aPos.mnCol );
595             aLastPos.mnRow = std::max( aLastPos.mnRow, aPos.mnRow );
596             aLastPos.mnCol = std::max( aLastPos.mnCol, aPos.mnCol );
597         }
598         pController->setSelectedCells( aFirstPos, aLastPos );
599     }
600 }
601 
602 //--------------------------------------------------------------------
603 
604 sal_Bool SAL_CALL AccessibleTableShape::isAccessibleChildSelected( sal_Int32 nChildIndex ) throw ( IndexOutOfBoundsException, RuntimeException )
605 {
606     ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
607     CellPos aPos;
608     mxImpl->getColumnAndRow( nChildIndex, aPos.mnCol, aPos.mnRow );
609 
610     return isAccessibleSelected(aPos.mnCol, aPos.mnRow);
611 }
612 
613 //--------------------------------------------------------------------
614 
615 void SAL_CALL AccessibleTableShape::clearAccessibleSelection() throw ( RuntimeException )
616 {
617    ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
618 
619     SvxTableController* pController = getTableController();
620     if( pController )
621         pController->clearSelection();
622 }
623 //--------------------------------------------------------------------
624 
625 void SAL_CALL AccessibleTableShape::selectAllAccessibleChildren() throw ( RuntimeException )
626 {
627    ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
628 
629    // todo: force selection of shape?
630     SvxTableController* pController = getTableController();
631     if( pController )
632         pController->selectAll();
633 }
634 
635 //--------------------------------------------------------------------
636 
637 sal_Int32 SAL_CALL AccessibleTableShape::getSelectedAccessibleChildCount() throw ( RuntimeException )
638 {
639     ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
640 
641     SvxTableController* pController = getTableController();
642     if( pController && pController->hasSelectedCells() )
643     {
644         CellPos aFirstPos, aLastPos;
645         pController->getSelectedCells( aFirstPos, aLastPos );
646 
647         const sal_Int32 nSelectedColumns = std::max( (sal_Int32)0, aLastPos.mnCol - aFirstPos.mnCol ) + 1;
648         const sal_Int32 nSelectedRows = std::max( (sal_Int32)0, aLastPos.mnRow - aFirstPos.mnRow ) + 1;
649         return nSelectedRows * nSelectedColumns;
650     }
651 
652     return 0;
653 }
654 
655 //--------------------------------------------------------------------
656 
657 Reference< XAccessible > SAL_CALL AccessibleTableShape::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) throw ( IndexOutOfBoundsException, RuntimeException)
658 {
659     ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
660 
661     SvxTableController* pController = getTableController();
662     if( pController && pController->hasSelectedCells() )
663     {
664         CellPos aFirstPos, aLastPos;
665         pController->getSelectedCells( aFirstPos, aLastPos );
666 
667         const sal_Int32 nSelectedColumns = std::max( (sal_Int32)0, aLastPos.mnCol - aFirstPos.mnCol ) + 1;
668         const sal_Int32 nSelectedRows = std::max( (sal_Int32)0, aLastPos.mnRow - aFirstPos.mnRow ) + 1;
669 
670         if( nSelectedChildIndex < (nSelectedRows * nSelectedColumns) )
671         {
672             while( nSelectedChildIndex >= nSelectedColumns )
673             {
674                 aFirstPos.mnRow++;
675                 nSelectedChildIndex -= nSelectedColumns;
676             }
677             return getAccessibleCellAt( nSelectedColumns, aFirstPos.mnRow );
678         }
679     }
680 
681     throw IndexOutOfBoundsException();
682 }
683 
684 //--------------------------------------------------------------------
685 
686 void SAL_CALL AccessibleTableShape::deselectAccessibleChild( sal_Int32 nChildIndex )  throw ( IndexOutOfBoundsException, RuntimeException )
687 {
688    ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
689     CellPos aPos;
690     mxImpl->getColumnAndRow( nChildIndex, aPos.mnCol, aPos.mnRow );
691 
692     // todo, select table shape?!?
693     SvxTableController* pController = getTableController();
694     if( pController && pController->hasSelectedCells() )
695     {
696         CellPos aFirstPos, aLastPos;
697         pController->getSelectedCells( aFirstPos, aLastPos );
698 
699         // create a selection where aPos is not part of anymore
700         aFirstPos.mnRow = std::min( aFirstPos.mnRow, aPos.mnRow+1 );
701         aFirstPos.mnCol = std::min( aFirstPos.mnCol, aPos.mnCol+1 );
702         aLastPos.mnRow = std::max( aLastPos.mnRow, aPos.mnRow-1 );
703         aLastPos.mnCol = std::max( aLastPos.mnCol, aPos.mnCol-1 );
704 
705         // new selection may be invalid (child to deselect is not at a border of the selection but in between)
706         if( (aFirstPos.mnRow > aLastPos.mnRow) || (aFirstPos.mnCol > aLastPos.mnCol) )
707             pController->clearSelection(); // if selection is invalid, clear all
708         else
709             pController->setSelectedCells( aFirstPos, aLastPos );
710     }
711 }
712 
713 //--------------------------------------------------------------------
714 
715 void AccessibleTableShape::checkCellPosition( sal_Int32 nCol, sal_Int32 nRow ) throw ( IndexOutOfBoundsException )
716 {
717     if( (nCol >= 0) && (nRow >= 0) && mxImpl->mxTable.is() && (nCol < mxImpl->mxTable->getColumnCount()) && (nRow < mxImpl->mxTable->getRowCount()) )
718         return;
719 
720     throw IndexOutOfBoundsException();
721 }
722 
723 }
724