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