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