ITEM: Refactor ItemType
[LibreOffice.git] / sw / source / core / access / acctable.cxx
blob3602410055594ffc7e355ca6a96dcd56c3c5c749
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/log.hxx>
22 #include <algorithm>
23 #include <vector>
24 #include <com/sun/star/accessibility/AccessibleRole.hpp>
25 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
26 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
27 #include <com/sun/star/accessibility/AccessibleTableModelChange.hpp>
28 #include <com/sun/star/accessibility/AccessibleTableModelChangeType.hpp>
29 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
30 #include <o3tl/safeint.hxx>
31 #include <vcl/svapp.hxx>
32 #include <frmfmt.hxx>
33 #include <tabfrm.hxx>
34 #include <cellfrm.hxx>
35 #include <swtable.hxx>
36 #include <crsrsh.hxx>
37 #include <viscrs.hxx>
38 #include "accfrmobjslist.hxx"
39 #include <accmap.hxx>
40 #include <strings.hrc>
41 #include "acctable.hxx"
43 #include <com/sun/star/accessibility/XAccessibleText.hpp>
45 #include <editeng/brushitem.hxx>
46 #include <swatrset.hxx>
47 #include <frmatr.hxx>
49 #include <cppuhelper/supportsservice.hxx>
50 #include <cppuhelper/typeprovider.hxx>
52 using namespace ::com::sun::star;
53 using namespace ::com::sun::star::accessibility;
54 using namespace ::sw::access;
56 typedef o3tl::sorted_vector< sal_Int32 > Int32Set_Impl;
58 const unsigned int SELECTION_WITH_NUM = 10;
60 namespace {
62 class SwAccTableSelHandler_Impl
64 public:
65 virtual void Unselect( sal_Int32 nRowOrCol, sal_Int32 nExt ) = 0;
67 protected:
68 ~SwAccTableSelHandler_Impl() {}
73 class SwAccessibleTableData_Impl
75 SwAccessibleMap& mrAccMap;
76 Int32Set_Impl maRows;
77 Int32Set_Impl maColumns;
78 Point maTabFramePos;
79 const SwTabFrame *mpTabFrame;
80 bool mbIsInPagePreview;
81 bool mbOnlyTableColumnHeader;
83 void CollectData( const SwFrame *pFrame );
85 bool FindCell( const Point& rPos, const SwFrame *pFrame ,
86 bool bExact, const SwFrame *& rFrame ) const;
88 void GetSelection( const Point& rTabPos, const SwRect& rArea,
89 const SwSelBoxes& rSelBoxes, const SwFrame *pFrame,
90 SwAccTableSelHandler_Impl& rSelHdl,
91 bool bColumns ) const;
93 // #i77106#
94 bool IncludeRow( const SwFrame& rFrame ) const
96 return !mbOnlyTableColumnHeader ||
97 mpTabFrame->IsInHeadline( rFrame );
99 public:
100 // #i77106# - add third optional parameter <bOnlyTableColumnHeader>, default value <false>
101 SwAccessibleTableData_Impl( SwAccessibleMap& rAccMap,
102 const SwTabFrame *pTabFrame,
103 bool bIsInPagePreview,
104 bool bOnlyTableColumnHeader = false );
106 const Int32Set_Impl& GetRows() const { return maRows; }
107 const Int32Set_Impl& GetColumns() const { return maColumns; }
109 inline Int32Set_Impl::const_iterator GetRowIter( sal_Int32 nRow ) const;
110 inline Int32Set_Impl::const_iterator GetColumnIter( sal_Int32 nCol ) const;
112 /// @throws lang::IndexOutOfBoundsException
113 /// @throws uno::RuntimeException
114 const SwFrame *GetCell( sal_Int32 nRow, sal_Int32 nColumn, SwAccessibleTable *pThis ) const;
115 const SwFrame *GetCellAtPos( sal_Int32 nLeft, sal_Int32 nTop ) const;
116 inline sal_Int32 GetRowCount() const;
117 inline sal_Int32 GetColumnCount() const;
118 bool CompareExtents( const SwAccessibleTableData_Impl& r ) const;
120 void GetSelection( sal_Int32 nStart, sal_Int32 nEnd,
121 const SwSelBoxes& rSelBoxes,
122 SwAccTableSelHandler_Impl& rSelHdl,
123 bool bColumns ) const;
125 /// @throws lang::IndexOutOfBoundsException
126 void CheckRowAndCol( sal_Int32 nRow, sal_Int32 nCol,
127 SwAccessibleTable *pThis ) const;
129 const Point& GetTablePos() const { return maTabFramePos; }
130 void SetTablePos( const Point& rPos ) { maTabFramePos = rPos; }
133 void SwAccessibleTableData_Impl::CollectData( const SwFrame *pFrame )
135 const SwAccessibleChildSList aList( *pFrame, mrAccMap );
136 SwAccessibleChildSList::const_iterator aIter( aList.begin() );
137 SwAccessibleChildSList::const_iterator aEndIter( aList.end() );
138 while( aIter != aEndIter )
140 const SwAccessibleChild& rLower = *aIter;
141 const SwFrame *pLower = rLower.GetSwFrame();
142 if( pLower )
144 if( pLower->IsRowFrame() )
146 // #i77106#
147 if ( IncludeRow( *pLower ) )
149 maRows.insert( pLower->getFrameArea().Top() - maTabFramePos.getY() );
150 CollectData( pLower );
153 else if( pLower->IsCellFrame() &&
154 rLower.IsAccessible( mbIsInPagePreview ) )
156 maColumns.insert( pLower->getFrameArea().Left() - maTabFramePos.getX() );
158 else
160 CollectData( pLower );
163 ++aIter;
167 bool SwAccessibleTableData_Impl::FindCell(
168 const Point& rPos, const SwFrame *pFrame, bool bExact,
169 const SwFrame *& rRet ) const
171 bool bFound = false;
173 const SwAccessibleChildSList aList( *pFrame, mrAccMap );
174 SwAccessibleChildSList::const_iterator aIter( aList.begin() );
175 SwAccessibleChildSList::const_iterator aEndIter( aList.end() );
176 while( !bFound && aIter != aEndIter )
178 const SwAccessibleChild& rLower = *aIter;
179 const SwFrame *pLower = rLower.GetSwFrame();
180 OSL_ENSURE( pLower, "child should be a frame" );
181 if( pLower )
183 if( rLower.IsAccessible( mbIsInPagePreview ) )
185 OSL_ENSURE( pLower->IsCellFrame(), "lower is not a cell frame" );
186 const SwRect& rFrame = pLower->getFrameArea();
187 if( rFrame.Right() >= rPos.X() && rFrame.Bottom() >= rPos.Y() )
189 // We have found the cell
190 OSL_ENSURE( rFrame.Left() <= rPos.X() && rFrame.Top() <= rPos.Y(),
191 "find frame moved to far!" );
192 bFound = true;
193 if( !bExact ||
194 (rFrame.Top() == rPos.Y() && rFrame.Left() == rPos.Y() ) )
196 rRet = pLower;
200 else
202 // #i77106#
203 if ( !pLower->IsRowFrame() ||
204 IncludeRow( *pLower ) )
206 bFound = FindCell( rPos, pLower, bExact, rRet );
210 ++aIter;
213 return bFound;
216 void SwAccessibleTableData_Impl::GetSelection(
217 const Point& rTabPos,
218 const SwRect& rArea,
219 const SwSelBoxes& rSelBoxes,
220 const SwFrame *pFrame,
221 SwAccTableSelHandler_Impl& rSelHdl,
222 bool bColumns ) const
224 const SwAccessibleChildSList aList( *pFrame, mrAccMap );
225 SwAccessibleChildSList::const_iterator aIter( aList.begin() );
226 SwAccessibleChildSList::const_iterator aEndIter( aList.end() );
227 while( aIter != aEndIter )
229 const SwAccessibleChild& rLower = *aIter;
230 const SwFrame *pLower = rLower.GetSwFrame();
231 OSL_ENSURE( pLower, "child should be a frame" );
232 const SwRect aBox = rLower.GetBox( mrAccMap );
233 if( pLower && aBox.Overlaps( rArea ) )
235 if( rLower.IsAccessible( mbIsInPagePreview ) )
237 OSL_ENSURE( pLower->IsCellFrame(), "lower is not a cell frame" );
238 const SwCellFrame *pCFrame =
239 static_cast < const SwCellFrame * >( pLower );
240 SwTableBox *pBox =
241 const_cast< SwTableBox *>( pCFrame->GetTabBox() );
242 if( rSelBoxes.find( pBox ) == rSelBoxes.end() )
244 const Int32Set_Impl rRowsOrCols =
245 bColumns ? maColumns : maRows;
247 sal_Int32 nPos = bColumns ? (aBox.Left() - rTabPos.X())
248 : (aBox.Top() - rTabPos.Y());
249 Int32Set_Impl::const_iterator aSttRowOrCol(
250 rRowsOrCols.lower_bound( nPos ) );
251 sal_Int32 nRowOrCol =
252 static_cast< sal_Int32 >( std::distance(
253 rRowsOrCols.begin(), aSttRowOrCol ) );
255 nPos = bColumns ? (aBox.Right() - rTabPos.X())
256 : (aBox.Bottom() - rTabPos.Y());
257 Int32Set_Impl::const_iterator aEndRowOrCol(
258 rRowsOrCols.upper_bound( nPos ) );
259 sal_Int32 nExt =
260 static_cast< sal_Int32 >( std::distance(
261 aSttRowOrCol, aEndRowOrCol ) );
263 rSelHdl.Unselect( nRowOrCol, nExt );
266 else
268 // #i77106#
269 if ( !pLower->IsRowFrame() ||
270 IncludeRow( *pLower ) )
272 GetSelection( rTabPos, rArea, rSelBoxes, pLower, rSelHdl,
273 bColumns );
277 ++aIter;
281 const SwFrame *SwAccessibleTableData_Impl::GetCell(
282 sal_Int32 nRow, sal_Int32 nColumn,
283 SwAccessibleTable *pThis ) const
285 CheckRowAndCol( nRow, nColumn, pThis );
287 Int32Set_Impl::const_iterator aSttCol( GetColumnIter( nColumn ) );
288 Int32Set_Impl::const_iterator aSttRow( GetRowIter( nRow ) );
289 const SwFrame *pCellFrame = GetCellAtPos( *aSttCol, *aSttRow );
291 return pCellFrame;
294 void SwAccessibleTableData_Impl::GetSelection(
295 sal_Int32 nStart, sal_Int32 nEnd,
296 const SwSelBoxes& rSelBoxes,
297 SwAccTableSelHandler_Impl& rSelHdl,
298 bool bColumns ) const
300 SwRect aArea( mpTabFrame->getFrameArea() );
301 Point aPos( aArea.Pos() );
303 const Int32Set_Impl& rRowsOrColumns = bColumns ? maColumns : maRows;
304 if( nStart > 0 )
306 Int32Set_Impl::const_iterator aStt( rRowsOrColumns.begin() );
307 std::advance( aStt,
308 static_cast< Int32Set_Impl::difference_type >( nStart ) );
309 if( bColumns )
310 aArea.Left( *aStt + aPos.getX() );
311 else
312 aArea.Top( *aStt + aPos.getY() );
314 if( nEnd < static_cast< sal_Int32 >( rRowsOrColumns.size() ) )
316 Int32Set_Impl::const_iterator aEnd( rRowsOrColumns.begin() );
317 std::advance( aEnd,
318 static_cast< Int32Set_Impl::difference_type >( nEnd ) );
319 if( bColumns )
320 aArea.Right( *aEnd + aPos.getX() - 1 );
321 else
322 aArea.Bottom( *aEnd + aPos.getY() - 1 );
325 GetSelection( aPos, aArea, rSelBoxes, mpTabFrame, rSelHdl, bColumns );
328 const SwFrame *SwAccessibleTableData_Impl::GetCellAtPos(
329 sal_Int32 nLeft, sal_Int32 nTop ) const
331 Point aPos( mpTabFrame->getFrameArea().Pos() );
332 aPos.Move( nLeft, nTop );
333 const SwFrame *pRet = nullptr;
334 FindCell( aPos, mpTabFrame, false/*bExact*/, pRet );
336 return pRet;
339 inline sal_Int32 SwAccessibleTableData_Impl::GetRowCount() const
341 sal_Int32 count = static_cast< sal_Int32 >( maRows.size() ) ;
342 count = (count <=0)? 1:count;
343 return count;
346 inline sal_Int32 SwAccessibleTableData_Impl::GetColumnCount() const
348 return static_cast< sal_Int32 >( maColumns.size() );
351 bool SwAccessibleTableData_Impl::CompareExtents(
352 const SwAccessibleTableData_Impl& rCmp ) const
354 return maRows == rCmp.maRows
355 && maColumns == rCmp.maColumns;
358 SwAccessibleTableData_Impl::SwAccessibleTableData_Impl( SwAccessibleMap& rAccMap,
359 const SwTabFrame *pTabFrame,
360 bool bIsInPagePreview,
361 bool bOnlyTableColumnHeader )
362 : mrAccMap( rAccMap )
363 , maTabFramePos( pTabFrame->getFrameArea().Pos() )
364 , mpTabFrame( pTabFrame )
365 , mbIsInPagePreview( bIsInPagePreview )
366 , mbOnlyTableColumnHeader( bOnlyTableColumnHeader )
368 CollectData( mpTabFrame );
371 inline Int32Set_Impl::const_iterator SwAccessibleTableData_Impl::GetRowIter(
372 sal_Int32 nRow ) const
374 Int32Set_Impl::const_iterator aCol( GetRows().begin() );
375 if( nRow > 0 )
377 std::advance( aCol,
378 static_cast< Int32Set_Impl::difference_type >( nRow ) );
380 return aCol;
383 inline Int32Set_Impl::const_iterator SwAccessibleTableData_Impl::GetColumnIter(
384 sal_Int32 nColumn ) const
386 Int32Set_Impl::const_iterator aCol = GetColumns().begin();
387 if( nColumn > 0 )
389 std::advance( aCol,
390 static_cast< Int32Set_Impl::difference_type >( nColumn ) );
392 return aCol;
395 void SwAccessibleTableData_Impl::CheckRowAndCol(
396 sal_Int32 nRow, sal_Int32 nCol, SwAccessibleTable *pThis ) const
398 if( ( nRow < 0 || o3tl::make_unsigned(nRow) >= maRows.size() ) ||
399 ( nCol < 0 || o3tl::make_unsigned(nCol) >= maColumns.size() ) )
401 uno::Reference < XAccessibleTable > xThis( pThis );
402 lang::IndexOutOfBoundsException aExcept(
403 u"row or column index out of range"_ustr,
404 xThis );
405 throw aExcept;
409 namespace {
411 class SwAccSingleTableSelHandler_Impl : public SwAccTableSelHandler_Impl
413 bool m_bSelected;
415 public:
417 inline SwAccSingleTableSelHandler_Impl();
419 virtual ~SwAccSingleTableSelHandler_Impl() {}
421 bool IsSelected() const { return m_bSelected; }
423 virtual void Unselect( sal_Int32, sal_Int32 ) override;
428 inline SwAccSingleTableSelHandler_Impl::SwAccSingleTableSelHandler_Impl() :
429 m_bSelected( true )
433 void SwAccSingleTableSelHandler_Impl::Unselect( sal_Int32, sal_Int32 )
435 m_bSelected = false;
438 namespace {
440 class SwAccAllTableSelHandler_Impl : public SwAccTableSelHandler_Impl
443 std::vector< bool > m_aSelected;
444 sal_Int32 m_nCount;
446 public:
447 explicit SwAccAllTableSelHandler_Impl(sal_Int32 nSize)
448 : m_aSelected(nSize, true)
449 , m_nCount(nSize)
453 uno::Sequence < sal_Int32 > GetSelSequence();
455 virtual void Unselect( sal_Int32 nRowOrCol, sal_Int32 nExt ) override;
456 virtual ~SwAccAllTableSelHandler_Impl();
461 SwAccAllTableSelHandler_Impl::~SwAccAllTableSelHandler_Impl()
465 uno::Sequence < sal_Int32 > SwAccAllTableSelHandler_Impl::GetSelSequence()
467 OSL_ENSURE( m_nCount >= 0, "underflow" );
468 uno::Sequence < sal_Int32 > aRet( m_nCount );
469 sal_Int32 *pRet = aRet.getArray();
470 sal_Int32 nPos = 0;
471 size_t nSize = m_aSelected.size();
472 for( size_t i=0; i < nSize && nPos < m_nCount; i++ )
474 if( m_aSelected[i] )
476 *pRet++ = i;
477 nPos++;
481 OSL_ENSURE( nPos == m_nCount, "count is wrong" );
483 return aRet;
486 void SwAccAllTableSelHandler_Impl::Unselect( sal_Int32 nRowOrCol,
487 sal_Int32 nExt )
489 OSL_ENSURE( o3tl::make_unsigned( nRowOrCol ) < m_aSelected.size(),
490 "index too large" );
491 OSL_ENSURE( o3tl::make_unsigned( nRowOrCol+nExt ) <= m_aSelected.size(),
492 "extent too large" );
493 while( nExt )
495 if( m_aSelected[static_cast< size_t >( nRowOrCol )] )
497 m_aSelected[static_cast< size_t >( nRowOrCol )] = false;
498 m_nCount--;
500 nExt--;
501 nRowOrCol++;
505 const SwSelBoxes *SwAccessibleTable::GetSelBoxes() const
507 const SwSelBoxes *pSelBoxes = nullptr;
508 const SwCursorShell *pCSh = GetCursorShell();
509 if( (pCSh != nullptr) && pCSh->IsTableMode() )
511 pSelBoxes = &pCSh->GetTableCursor()->GetSelectedBoxes();
514 return pSelBoxes;
517 void SwAccessibleTable::FireTableChangeEvent(
518 const SwAccessibleTableData_Impl& rTableData )
520 AccessibleTableModelChange aModelChange;
521 aModelChange.Type = AccessibleTableModelChangeType::UPDATE;
522 aModelChange.FirstRow = 0;
523 aModelChange.LastRow = rTableData.GetRowCount() - 1;
524 aModelChange.FirstColumn = 0;
525 aModelChange.LastColumn = rTableData.GetColumnCount() - 1;
527 AccessibleEventObject aEvent;
528 aEvent.EventId = AccessibleEventId::TABLE_MODEL_CHANGED;
529 aEvent.NewValue <<= aModelChange;
531 FireAccessibleEvent( aEvent );
534 const SwTableBox* SwAccessibleTable::GetTableBox( sal_Int64 nChildIndex ) const
536 OSL_ENSURE( nChildIndex >= 0, "Illegal child index." );
537 OSL_ENSURE( nChildIndex < const_cast<SwAccessibleTable*>(this)->getAccessibleChildCount(), "Illegal child index." ); // #i77106#
539 const SwTableBox* pBox = nullptr;
541 // get table box for 'our' table cell
542 SwAccessibleChild aCell( GetChild( *const_cast<SwAccessibleMap*>(GetMap()), nChildIndex ) );
543 if( aCell.GetSwFrame() )
545 const SwFrame* pChildFrame = aCell.GetSwFrame();
546 if( (pChildFrame != nullptr) && pChildFrame->IsCellFrame() )
548 const SwCellFrame* pCellFrame =
549 static_cast<const SwCellFrame*>( pChildFrame );
550 pBox = pCellFrame->GetTabBox();
554 OSL_ENSURE( pBox != nullptr, "We need the table box." );
555 return pBox;
558 bool SwAccessibleTable::IsChildSelected( sal_Int64 nChildIndex ) const
560 bool bRet = false;
561 const SwSelBoxes* pSelBoxes = GetSelBoxes();
562 if( pSelBoxes )
564 const SwTableBox* pBox = GetTableBox( nChildIndex );
565 OSL_ENSURE( pBox != nullptr, "We need the table box." );
566 bRet = pSelBoxes->find( const_cast<SwTableBox*>( pBox ) ) != pSelBoxes->end();
569 return bRet;
572 sal_Int64 SwAccessibleTable::GetIndexOfSelectedChild(
573 sal_Int64 nSelectedChildIndex ) const
575 // iterate over all children to n-th isAccessibleChildSelected()
576 sal_Int64 nChildren = const_cast<SwAccessibleTable*>(this)->getAccessibleChildCount(); // #i77106#
577 if( nSelectedChildIndex >= nChildren )
578 return -1;
580 sal_Int64 n = 0;
581 while( n < nChildren )
583 if( IsChildSelected( n ) )
585 if( 0 == nSelectedChildIndex )
586 break;
587 else
588 --nSelectedChildIndex;
590 ++n;
593 return n < nChildren ? n : -1;
596 void SwAccessibleTable::GetStates( sal_Int64& rStateSet )
598 SwAccessibleContext::GetStates( rStateSet );
599 //Add resizable state to table
600 rStateSet |= AccessibleStateType::RESIZABLE;
601 // MULTISELECTABLE
602 rStateSet |= AccessibleStateType::MULTI_SELECTABLE;
603 SwCursorShell* pCursorShell = GetCursorShell();
604 if( pCursorShell )
605 rStateSet |= AccessibleStateType::MULTI_SELECTABLE;
608 SwAccessibleTable::SwAccessibleTable(
609 std::shared_ptr<SwAccessibleMap> const& pInitMap,
610 const SwTabFrame* pTabFrame ) :
611 SwAccessibleTable_BASE( pInitMap, AccessibleRole::TABLE, pTabFrame )
613 const SwFrameFormat* pFrameFormat = pTabFrame->GetFormat();
614 StartListening(const_cast<SwFrameFormat*>(pFrameFormat)->GetNotifier());
615 SetName( pFrameFormat->GetName() + "-" + OUString::number( pTabFrame->GetPhyPageNum() ) );
617 const OUString sArg1( static_cast< const SwTabFrame * >( GetFrame() )->GetFormat()->GetName() );
618 const OUString sArg2( GetFormattedPageNumber() );
620 m_sDesc = GetResource( STR_ACCESS_TABLE_DESC, &sArg1, &sArg2 );
621 UpdateTableData();
624 SwAccessibleTable::~SwAccessibleTable()
626 SolarMutexGuard aGuard;
628 mpTableData.reset();
631 void SwAccessibleTable::Notify(const SfxHint& rHint)
633 const SwTabFrame* pTabFrame = static_cast<const SwTabFrame*>(GetFrame());
634 if(rHint.GetId() == SfxHintId::Dying)
636 EndListeningAll();
638 else if (rHint.GetId() == SfxHintId::SwNameChanged && pTabFrame)
640 const SwFrameFormat *pFrameFormat = pTabFrame->GetFormat();
641 const OUString sOldName( GetName() );
642 const OUString sNewTabName = pFrameFormat->GetName();
644 SetName( sNewTabName + "-" + OUString::number( pTabFrame->GetPhyPageNum() ) );
646 if( sOldName != GetName() )
648 AccessibleEventObject aEvent;
649 aEvent.EventId = AccessibleEventId::NAME_CHANGED;
650 aEvent.OldValue <<= sOldName;
651 aEvent.NewValue <<= GetName();
652 FireAccessibleEvent( aEvent );
655 const OUString sOldDesc( m_sDesc );
656 const OUString sArg2( GetFormattedPageNumber() );
658 m_sDesc = GetResource( STR_ACCESS_TABLE_DESC, &sNewTabName, &sArg2 );
659 if( m_sDesc != sOldDesc )
661 AccessibleEventObject aEvent;
662 aEvent.EventId = AccessibleEventId::DESCRIPTION_CHANGED;
663 aEvent.OldValue <<= sOldDesc;
664 aEvent.NewValue <<= m_sDesc;
665 FireAccessibleEvent( aEvent );
670 // #i77106#
671 std::unique_ptr<SwAccessibleTableData_Impl> SwAccessibleTable::CreateNewTableData()
673 const SwTabFrame* pTabFrame = static_cast<const SwTabFrame*>( GetFrame() );
674 return std::unique_ptr<SwAccessibleTableData_Impl>(new SwAccessibleTableData_Impl( *GetMap(), pTabFrame, IsInPagePreview() ));
677 void SwAccessibleTable::UpdateTableData()
679 // #i77106# - usage of new method <CreateNewTableData()>
680 mpTableData = CreateNewTableData();
683 void SwAccessibleTable::ClearTableData()
685 mpTableData.reset();
688 OUString SAL_CALL SwAccessibleTable::getAccessibleDescription()
690 SolarMutexGuard aGuard;
692 ThrowIfDisposed();
694 return m_sDesc;
697 sal_Int32 SAL_CALL SwAccessibleTable::getAccessibleRowCount()
699 SolarMutexGuard aGuard;
701 ThrowIfDisposed();
703 return GetTableData().GetRowCount();
706 sal_Int32 SAL_CALL SwAccessibleTable::getAccessibleColumnCount( )
708 SolarMutexGuard aGuard;
710 ThrowIfDisposed();
712 return GetTableData().GetColumnCount();
715 OUString SAL_CALL SwAccessibleTable::getAccessibleRowDescription(
716 sal_Int32 nRow )
718 // #i87532# - determine table cell in <nRow>th row and
719 // in first column of row header table and return its text content.
720 OUString sRowDesc;
722 GetTableData().CheckRowAndCol(nRow, 0, this);
724 uno::Reference< XAccessibleTable > xTableRowHeader = getAccessibleRowHeaders();
725 if ( xTableRowHeader.is() )
727 uno::Reference< XAccessible > xRowHeaderCell =
728 xTableRowHeader->getAccessibleCellAt( nRow, 0 );
729 OSL_ENSURE( xRowHeaderCell.is(),
730 "<SwAccessibleTable::getAccessibleRowDescription(..)> - missing row header cell -> serious issue." );
731 uno::Reference< XAccessibleContext > xRowHeaderCellContext =
732 xRowHeaderCell->getAccessibleContext();
733 const sal_Int64 nCellChildCount( xRowHeaderCellContext->getAccessibleChildCount() );
734 for ( sal_Int64 nChildIndex = 0; nChildIndex < nCellChildCount; ++nChildIndex )
736 uno::Reference< XAccessible > xChild = xRowHeaderCellContext->getAccessibleChild( nChildIndex );
737 uno::Reference< XAccessibleText > xChildText( xChild, uno::UNO_QUERY );
738 if ( xChildText.is() )
740 sRowDesc += xChildText->getText();
745 return sRowDesc;
748 OUString SAL_CALL SwAccessibleTable::getAccessibleColumnDescription(
749 sal_Int32 nColumn )
751 // #i87532# - determine table cell in first row and
752 // in <nColumn>th column of column header table and return its text content.
753 OUString sColumnDesc;
755 GetTableData().CheckRowAndCol(0, nColumn, this);
757 uno::Reference< XAccessibleTable > xTableColumnHeader = getAccessibleColumnHeaders();
758 if ( xTableColumnHeader.is() )
760 uno::Reference< XAccessible > xColumnHeaderCell =
761 xTableColumnHeader->getAccessibleCellAt( 0, nColumn );
762 OSL_ENSURE( xColumnHeaderCell.is(),
763 "<SwAccessibleTable::getAccessibleColumnDescription(..)> - missing column header cell -> serious issue." );
764 uno::Reference< XAccessibleContext > xColumnHeaderCellContext =
765 xColumnHeaderCell->getAccessibleContext();
766 const sal_Int64 nCellChildCount( xColumnHeaderCellContext->getAccessibleChildCount() );
767 for ( sal_Int64 nChildIndex = 0; nChildIndex < nCellChildCount; ++nChildIndex )
769 uno::Reference< XAccessible > xChild = xColumnHeaderCellContext->getAccessibleChild( nChildIndex );
770 uno::Reference< XAccessibleText > xChildText( xChild, uno::UNO_QUERY );
771 if ( xChildText.is() )
773 sColumnDesc += xChildText->getText();
778 return sColumnDesc;
781 sal_Int32 SAL_CALL SwAccessibleTable::getAccessibleRowExtentAt(
782 sal_Int32 nRow, sal_Int32 nColumn )
784 sal_Int32 nExtend = -1;
786 SolarMutexGuard aGuard;
788 ThrowIfDisposed();
790 UpdateTableData();
791 GetTableData().CheckRowAndCol( nRow, nColumn, this );
793 Int32Set_Impl::const_iterator aSttCol(
794 GetTableData().GetColumnIter( nColumn ) );
795 Int32Set_Impl::const_iterator aSttRow(
796 GetTableData().GetRowIter( nRow ) );
797 const SwFrame *pCellFrame = GetTableData().GetCellAtPos( *aSttCol, *aSttRow );
798 if( pCellFrame )
800 sal_Int32 nBottom = pCellFrame->getFrameArea().Bottom();
801 nBottom -= GetFrame()->getFrameArea().Top();
802 Int32Set_Impl::const_iterator aEndRow(
803 GetTableData().GetRows().upper_bound( nBottom ) );
804 nExtend =
805 static_cast< sal_Int32 >( std::distance( aSttRow, aEndRow ) );
808 return nExtend;
811 sal_Int32 SAL_CALL SwAccessibleTable::getAccessibleColumnExtentAt(
812 sal_Int32 nRow, sal_Int32 nColumn )
814 sal_Int32 nExtend = -1;
816 SolarMutexGuard aGuard;
818 ThrowIfDisposed();
819 UpdateTableData();
821 GetTableData().CheckRowAndCol( nRow, nColumn, this );
823 Int32Set_Impl::const_iterator aSttCol(
824 GetTableData().GetColumnIter( nColumn ) );
825 Int32Set_Impl::const_iterator aSttRow(
826 GetTableData().GetRowIter( nRow ) );
827 const SwFrame *pCellFrame = GetTableData().GetCellAtPos( *aSttCol, *aSttRow );
828 if( pCellFrame )
830 sal_Int32 nRight = pCellFrame->getFrameArea().Right();
831 nRight -= GetFrame()->getFrameArea().Left();
832 Int32Set_Impl::const_iterator aEndCol(
833 GetTableData().GetColumns().upper_bound( nRight ) );
834 nExtend =
835 static_cast< sal_Int32 >( std::distance( aSttCol, aEndCol ) );
838 return nExtend;
841 uno::Reference< XAccessibleTable > SAL_CALL
842 SwAccessibleTable::getAccessibleRowHeaders( )
844 // Row headers aren't supported
845 return uno::Reference< XAccessibleTable >();
848 uno::Reference< XAccessibleTable > SAL_CALL
849 SwAccessibleTable::getAccessibleColumnHeaders( )
851 SolarMutexGuard aGuard;
853 // #i87532# - assure that return accessible object is empty,
854 // if no column header exists.
855 rtl::Reference<SwAccessibleTableColHeaders> pTableColHeaders =
856 new SwAccessibleTableColHeaders(GetMap()->shared_from_this(),
857 static_cast<const SwTabFrame *>(GetFrame()));
858 if ( pTableColHeaders->getAccessibleChildCount() <= 0 )
860 return uno::Reference< XAccessibleTable >();
863 return pTableColHeaders;
866 uno::Sequence< sal_Int32 > SAL_CALL SwAccessibleTable::getSelectedAccessibleRows()
868 SolarMutexGuard aGuard;
870 ThrowIfDisposed();
872 const SwSelBoxes *pSelBoxes = GetSelBoxes();
873 if( pSelBoxes )
875 sal_Int32 nRows = GetTableData().GetRowCount();
876 SwAccAllTableSelHandler_Impl aSelRows( nRows );
878 GetTableData().GetSelection( 0, nRows, *pSelBoxes, aSelRows,
879 false );
881 return aSelRows.GetSelSequence();
883 else
885 return uno::Sequence< sal_Int32 >( 0 );
889 uno::Sequence< sal_Int32 > SAL_CALL SwAccessibleTable::getSelectedAccessibleColumns()
891 SolarMutexGuard aGuard;
893 ThrowIfDisposed();
895 const SwSelBoxes *pSelBoxes = GetSelBoxes();
896 if( pSelBoxes )
898 sal_Int32 nCols = GetTableData().GetColumnCount();
899 SwAccAllTableSelHandler_Impl aSelCols( nCols );
901 GetTableData().GetSelection( 0, nCols, *pSelBoxes, aSelCols, true );
903 return aSelCols.GetSelSequence();
905 else
907 return uno::Sequence< sal_Int32 >( 0 );
911 sal_Bool SAL_CALL SwAccessibleTable::isAccessibleRowSelected( sal_Int32 nRow )
913 SolarMutexGuard aGuard;
915 ThrowIfDisposed();
917 GetTableData().CheckRowAndCol( nRow, 0, this );
919 bool bRet;
920 const SwSelBoxes *pSelBoxes = GetSelBoxes();
921 if( pSelBoxes )
923 SwAccSingleTableSelHandler_Impl aSelRow;
924 GetTableData().GetSelection( nRow, nRow+1, *pSelBoxes, aSelRow,
925 false );
926 bRet = aSelRow.IsSelected();
928 else
930 bRet = false;
933 return bRet;
936 sal_Bool SAL_CALL SwAccessibleTable::isAccessibleColumnSelected(
937 sal_Int32 nColumn )
939 SolarMutexGuard aGuard;
941 ThrowIfDisposed();
943 GetTableData().CheckRowAndCol( 0, nColumn, this );
945 bool bRet;
946 const SwSelBoxes *pSelBoxes = GetSelBoxes();
947 if( pSelBoxes )
949 SwAccSingleTableSelHandler_Impl aSelCol;
951 GetTableData().GetSelection( nColumn, nColumn+1, *pSelBoxes, aSelCol,
952 true );
953 bRet = aSelCol.IsSelected();
955 else
957 bRet = false;
960 return bRet;
963 uno::Reference< XAccessible > SAL_CALL SwAccessibleTable::getAccessibleCellAt(
964 sal_Int32 nRow, sal_Int32 nColumn )
966 uno::Reference< XAccessible > xRet;
968 SolarMutexGuard aGuard;
970 ThrowIfDisposed();
972 const SwFrame *pCellFrame =
973 GetTableData().GetCell( nRow, nColumn, this );
974 if( pCellFrame )
975 xRet = GetMap()->GetContext( pCellFrame );
977 return xRet;
980 uno::Reference< XAccessible > SAL_CALL SwAccessibleTable::getAccessibleCaption()
982 // captions aren't supported
983 return uno::Reference< XAccessible >();
986 uno::Reference< XAccessible > SAL_CALL SwAccessibleTable::getAccessibleSummary()
988 // summaries aren't supported
989 return uno::Reference< XAccessible >();
992 sal_Bool SAL_CALL SwAccessibleTable::isAccessibleSelected(
993 sal_Int32 nRow, sal_Int32 nColumn )
995 bool bRet = false;
997 SolarMutexGuard aGuard;
999 ThrowIfDisposed();
1001 const SwFrame *pFrame =
1002 GetTableData().GetCell( nRow, nColumn, this );
1003 if( pFrame && pFrame->IsCellFrame() )
1005 const SwSelBoxes *pSelBoxes = GetSelBoxes();
1006 if( pSelBoxes )
1008 const SwCellFrame *pCFrame = static_cast < const SwCellFrame * >( pFrame );
1009 SwTableBox *pBox =
1010 const_cast< SwTableBox *>( pCFrame->GetTabBox() );
1011 bRet = pSelBoxes->find( pBox ) != pSelBoxes->end();
1015 return bRet;
1018 sal_Int64 SAL_CALL SwAccessibleTable::getAccessibleIndex(
1019 sal_Int32 nRow, sal_Int32 nColumn )
1021 sal_Int32 nRet = -1;
1023 SolarMutexGuard aGuard;
1025 ThrowIfDisposed();
1027 SwAccessibleChild aCell( GetTableData().GetCell( nRow, nColumn, this ));
1028 if ( aCell.IsValid() )
1030 nRet = GetChildIndex( *(GetMap()), aCell );
1033 return nRet;
1036 sal_Int32 SAL_CALL SwAccessibleTable::getAccessibleRow( sal_Int64 nChildIndex )
1038 sal_Int32 nRet = -1;
1040 SolarMutexGuard aGuard;
1042 ThrowIfDisposed();
1044 // #i77106#
1045 if ( ( nChildIndex < 0 ) ||
1046 ( nChildIndex >= getAccessibleChildCount() ) )
1048 throw lang::IndexOutOfBoundsException();
1051 SwAccessibleChild aCell( GetChild( *(GetMap()), nChildIndex ) );
1052 if ( aCell.GetSwFrame() )
1054 sal_Int32 nTop = aCell.GetSwFrame()->getFrameArea().Top();
1055 nTop -= GetFrame()->getFrameArea().Top();
1056 Int32Set_Impl::const_iterator aRow(
1057 GetTableData().GetRows().lower_bound( nTop ) );
1058 nRet = static_cast< sal_Int32 >( std::distance(
1059 GetTableData().GetRows().begin(), aRow ) );
1061 else
1063 OSL_ENSURE( !aCell.IsValid(), "SwAccessibleTable::getAccessibleColumn:"
1064 "aCell not expected to be valid.");
1066 throw lang::IndexOutOfBoundsException();
1069 return nRet;
1072 sal_Int32 SAL_CALL SwAccessibleTable::getAccessibleColumn(
1073 sal_Int64 nChildIndex )
1075 sal_Int32 nRet = -1;
1077 SolarMutexGuard aGuard;
1079 ThrowIfDisposed();
1081 // #i77106#
1082 if ( ( nChildIndex < 0 ) ||
1083 ( nChildIndex >= getAccessibleChildCount() ) )
1085 throw lang::IndexOutOfBoundsException();
1088 SwAccessibleChild aCell( GetChild( *(GetMap()), nChildIndex ) );
1089 if ( aCell.GetSwFrame() )
1091 sal_Int32 nLeft = aCell.GetSwFrame()->getFrameArea().Left();
1092 nLeft -= GetFrame()->getFrameArea().Left();
1093 Int32Set_Impl::const_iterator aCol(
1094 GetTableData().GetColumns().lower_bound( nLeft ) );
1095 nRet = static_cast< sal_Int32 >( std::distance(
1096 GetTableData().GetColumns().begin(), aCol ) );
1098 else
1100 OSL_ENSURE( !aCell.IsValid(), "SwAccessibleTable::getAccessibleColumn:"
1101 "aCell not expected to be valid.");
1103 throw lang::IndexOutOfBoundsException();
1106 return nRet;
1109 OUString SAL_CALL SwAccessibleTable::getImplementationName()
1111 return u"com.sun.star.comp.Writer.SwAccessibleTableView"_ustr;
1114 sal_Bool SAL_CALL SwAccessibleTable::supportsService(
1115 const OUString& sTestServiceName)
1117 return cppu::supportsService(this, sTestServiceName);
1120 uno::Sequence< OUString > SAL_CALL SwAccessibleTable::getSupportedServiceNames()
1122 return { u"com.sun.star.table.AccessibleTableView"_ustr, sAccessibleServiceName };
1125 void SwAccessibleTable::InvalidatePosOrSize( const SwRect& rOldBox )
1127 SolarMutexGuard aGuard;
1129 //need to update children
1130 std::unique_ptr<SwAccessibleTableData_Impl> pNewTableData = CreateNewTableData();
1131 if( !pNewTableData->CompareExtents( GetTableData() ) )
1133 mpTableData = std::move(pNewTableData);
1134 FireTableChangeEvent(*mpTableData);
1136 if( HasTableData() )
1137 GetTableData().SetTablePos( GetFrame()->getFrameArea().Pos() );
1139 SwAccessibleContext::InvalidatePosOrSize( rOldBox );
1142 void SwAccessibleTable::Dispose(bool bRecursive, bool bCanSkipInvisible)
1144 SolarMutexGuard aGuard;
1145 EndListeningAll();
1146 SwAccessibleContext::Dispose(bRecursive, bCanSkipInvisible);
1149 void SwAccessibleTable::DisposeChild( const SwAccessibleChild& rChildFrameOrObj,
1150 bool bRecursive, bool bCanSkipInvisible )
1152 SolarMutexGuard aGuard;
1154 const SwFrame *pFrame = rChildFrameOrObj.GetSwFrame();
1155 OSL_ENSURE( pFrame, "frame expected" );
1156 if( HasTableData() )
1158 FireTableChangeEvent( GetTableData() );
1159 ClearTableData();
1162 // There are two reason why this method has been called. The first one
1163 // is there is no context for pFrame. The method is then called by
1164 // the map, and we have to call our superclass.
1165 // The other situation is that we have been call by a call to get notified
1166 // about its change. We then must not call the superclass
1167 uno::Reference< XAccessible > xAcc( GetMap()->GetContext( pFrame, false ) );
1168 if( !xAcc.is() )
1169 SwAccessibleContext::DisposeChild( rChildFrameOrObj, bRecursive, bCanSkipInvisible );
1172 void SwAccessibleTable::InvalidateChildPosOrSize( const SwAccessibleChild& rChildFrameOrObj,
1173 const SwRect& rOldBox )
1175 SolarMutexGuard aGuard;
1177 if( HasTableData() )
1179 SAL_WARN_IF( HasTableData() &&
1180 GetFrame()->getFrameArea().Pos() != GetTableData().GetTablePos(),
1181 "sw.a11y", "table has invalid position" );
1182 if( HasTableData() )
1184 std::unique_ptr<SwAccessibleTableData_Impl> pNewTableData = CreateNewTableData(); // #i77106#
1185 if( !pNewTableData->CompareExtents( GetTableData() ) )
1187 if (pNewTableData->GetRowCount() != mpTableData->GetRowCount()
1188 && 1 < GetTableData().GetRowCount())
1190 Int32Set_Impl::const_iterator aSttCol( GetTableData().GetColumnIter( 0 ) );
1191 Int32Set_Impl::const_iterator aSttRow( GetTableData().GetRowIter( 1 ) );
1192 const SwFrame *pCellFrame = GetTableData().GetCellAtPos( *aSttCol, *aSttRow );
1193 Int32Set_Impl::const_iterator aSttCol2( pNewTableData->GetColumnIter( 0 ) );
1194 Int32Set_Impl::const_iterator aSttRow2( pNewTableData->GetRowIter( 0 ) );
1195 const SwFrame *pCellFrame2 = pNewTableData->GetCellAtPos( *aSttCol2, *aSttRow2 );
1197 if(pCellFrame == pCellFrame2)
1199 AccessibleTableModelChange aModelChange;
1200 aModelChange.Type = AccessibleTableModelChangeType::UPDATE;
1201 aModelChange.FirstRow = 0;
1202 aModelChange.LastRow = mpTableData->GetRowCount() - 1;
1203 aModelChange.FirstColumn = 0;
1204 aModelChange.LastColumn = mpTableData->GetColumnCount() - 1;
1206 AccessibleEventObject aEvent;
1207 aEvent.EventId = AccessibleEventId::TABLE_COLUMN_HEADER_CHANGED;
1208 aEvent.NewValue <<= aModelChange;
1210 FireAccessibleEvent( aEvent );
1213 else
1214 FireTableChangeEvent( GetTableData() );
1215 ClearTableData();
1216 mpTableData = std::move(pNewTableData);
1221 // #i013961# - always call super class method
1222 SwAccessibleContext::InvalidateChildPosOrSize( rChildFrameOrObj, rOldBox );
1225 // XAccessibleSelection
1227 void SAL_CALL SwAccessibleTable::selectAccessibleChild(
1228 sal_Int64 nChildIndex )
1230 SolarMutexGuard aGuard;
1232 ThrowIfDisposed();
1234 if( (nChildIndex < 0) || (nChildIndex >= getAccessibleChildCount()) ) // #i77106#
1235 throw lang::IndexOutOfBoundsException();
1237 // preliminaries: get 'our' table box, and get the cursor shell
1238 const SwTableBox* pBox = GetTableBox( nChildIndex );
1240 SwCursorShell* pCursorShell = GetCursorShell();
1241 if( pCursorShell == nullptr )
1242 return;
1244 // assure, that child, identified by the given index, isn't already selected.
1245 if ( IsChildSelected( nChildIndex ) )
1246 return;
1248 assert(pBox != nullptr && "We need the table box.");
1250 // now we can start to do the work: check whether we already have
1251 // a table selection (in 'our' table). If so, extend the
1252 // selection, else select the current cell.
1254 // if we have a selection in a table, check if it's in the
1255 // same table that we're trying to select in
1256 const SwTableNode* pSelectedTable = pCursorShell->IsCursorInTable();
1257 if( pSelectedTable != nullptr )
1259 // get top-most table line
1260 const SwTableLine* pUpper = pBox->GetUpper();
1261 while( pUpper->GetUpper() != nullptr )
1262 pUpper = pUpper->GetUpper()->GetUpper();
1263 sal_uInt16 nPos =
1264 pSelectedTable->GetTable().GetTabLines().GetPos( pUpper );
1265 if( nPos == USHRT_MAX )
1266 pSelectedTable = nullptr;
1269 // create the new selection
1270 const SwStartNode* pStartNode = pBox->GetSttNd();
1271 if( pSelectedTable == nullptr || !pCursorShell->GetTableCrs() )
1273 pCursorShell->StartAction();
1274 // Set cursor into current cell. This deletes any table cursor.
1275 SwPaM aPaM( *pStartNode );
1276 aPaM.Move( fnMoveForward, GoInNode );
1277 Select( aPaM );
1278 // Move cursor to the end of the table creating a selection and a table
1279 // cursor.
1280 pCursorShell->SetMark();
1281 pCursorShell->MoveTable( GotoCurrTable, fnTableEnd );
1282 // now set the cursor into the cell again.
1283 SwPaM *pPaM = pCursorShell->GetTableCrs() ? pCursorShell->GetTableCrs()
1284 : pCursorShell->GetCursor();
1285 *pPaM->GetPoint() = *pPaM->GetMark();
1286 pCursorShell->EndAction();
1287 // we now have one cell selected!
1289 else
1291 // if the cursor is already in this table,
1292 // expand the current selection (i.e., set
1293 // point to new position; keep mark)
1294 SwPaM aPaM( *pStartNode );
1295 aPaM.Move( fnMoveForward, GoInNode );
1296 aPaM.SetMark();
1297 const SwPaM *pPaM = pCursorShell->GetTableCrs() ? pCursorShell->GetTableCrs()
1298 : pCursorShell->GetCursor();
1299 *(aPaM.GetMark()) = *pPaM->GetMark();
1300 Select( aPaM );
1305 sal_Bool SAL_CALL SwAccessibleTable::isAccessibleChildSelected(
1306 sal_Int64 nChildIndex )
1308 SolarMutexGuard aGuard;
1310 ThrowIfDisposed();
1312 if( (nChildIndex < 0) || (nChildIndex >= getAccessibleChildCount()) ) // #i77106#
1313 throw lang::IndexOutOfBoundsException();
1315 return IsChildSelected( nChildIndex );
1318 void SAL_CALL SwAccessibleTable::clearAccessibleSelection( )
1320 SolarMutexGuard aGuard;
1322 ThrowIfDisposed();
1324 SwCursorShell* pCursorShell = GetCursorShell();
1325 if( pCursorShell != nullptr )
1327 pCursorShell->StartAction();
1328 pCursorShell->ClearMark();
1329 pCursorShell->EndAction();
1333 void SAL_CALL SwAccessibleTable::selectAllAccessibleChildren( )
1335 // first clear selection, then select first and last child
1336 clearAccessibleSelection();
1337 selectAccessibleChild( 0 );
1338 selectAccessibleChild( getAccessibleChildCount()-1 ); // #i77106#
1341 sal_Int64 SAL_CALL SwAccessibleTable::getSelectedAccessibleChildCount( )
1343 SolarMutexGuard aGuard;
1345 ThrowIfDisposed();
1347 // iterate over all children and count isAccessibleChildSelected()
1348 sal_Int64 nCount = 0;
1350 sal_Int64 nChildren = getAccessibleChildCount(); // #i71106#
1351 for( sal_Int64 n = 0; n < nChildren; n++ )
1352 if( IsChildSelected( n ) )
1353 nCount++;
1355 return nCount;
1358 uno::Reference<XAccessible> SAL_CALL SwAccessibleTable::getSelectedAccessibleChild(
1359 sal_Int64 nSelectedChildIndex )
1361 SolarMutexGuard aGuard;
1363 ThrowIfDisposed();
1365 // parameter checking (part 1): index lower 0
1366 if( nSelectedChildIndex < 0 )
1367 throw lang::IndexOutOfBoundsException();
1369 sal_Int64 nChildIndex = GetIndexOfSelectedChild( nSelectedChildIndex );
1371 // parameter checking (part 2): index higher than selected children?
1372 if( nChildIndex < 0 )
1373 throw lang::IndexOutOfBoundsException();
1375 // #i77106#
1376 if ( nChildIndex >= getAccessibleChildCount() )
1378 throw lang::IndexOutOfBoundsException();
1381 return getAccessibleChild( nChildIndex );
1384 // index has to be treated as global child index.
1385 void SAL_CALL SwAccessibleTable::deselectAccessibleChild(
1386 sal_Int64 nChildIndex )
1388 SolarMutexGuard aGuard;
1390 ThrowIfDisposed();
1392 SwCursorShell* pCursorShell = GetCursorShell();
1394 // index has to be treated as global child index
1395 if ( !pCursorShell )
1396 throw lang::IndexOutOfBoundsException();
1398 // assure, that given child index is in bounds.
1399 if ( nChildIndex < 0 || nChildIndex >= getAccessibleChildCount() ) // #i77106#
1400 throw lang::IndexOutOfBoundsException();
1402 // assure, that child, identified by the given index, is selected.
1403 if ( !IsChildSelected( nChildIndex ) )
1404 return;
1406 const SwTableBox* pBox = GetTableBox( nChildIndex );
1407 assert(pBox != nullptr && "We need the table box.");
1409 // If we unselect point, then set cursor to mark. If we clear another
1410 // selected box, then set cursor to point.
1411 // reduce selection to mark.
1412 SwPaM *pPaM = pCursorShell->GetTableCrs() ? pCursorShell->GetTableCrs()
1413 : pCursorShell->GetCursor();
1414 bool bDeselectPoint =
1415 pBox->GetSttNd() ==
1416 pPaM->GetPoint()->GetNode().FindTableBoxStartNode();
1418 SwPaM aPaM( bDeselectPoint ? *pPaM->GetMark() : *pPaM->GetPoint() );
1420 pCursorShell->StartAction();
1422 // Set cursor into either point or mark
1423 Select( aPaM );
1424 // Move cursor to the end of the table creating a selection and a table
1425 // cursor.
1426 pCursorShell->SetMark();
1427 pCursorShell->MoveTable( GotoCurrTable, fnTableEnd );
1428 // now set the cursor into the cell again.
1429 pPaM = pCursorShell->GetTableCrs() ? pCursorShell->GetTableCrs()
1430 : pCursorShell->GetCursor();
1431 *pPaM->GetPoint() = *pPaM->GetMark();
1432 pCursorShell->EndAction();
1435 sal_Int32 SAL_CALL SwAccessibleTable::getBackground()
1437 const SvxBrushItem &rBack = GetFrame()->GetAttrSet()->GetBackground();
1438 Color crBack = rBack.GetColor();
1440 if (COL_AUTO == crBack)
1442 uno::Reference<XAccessible> xAccDoc = getAccessibleParent();
1443 if (xAccDoc.is())
1445 uno::Reference<XAccessibleComponent> xComponentDoc(xAccDoc,uno::UNO_QUERY);
1446 if (xComponentDoc.is())
1448 crBack = Color(ColorTransparency, xComponentDoc->getBackground());
1452 return sal_Int32(crBack);
1455 void SwAccessibleTable::FireSelectionEvent( )
1457 AccessibleEventObject aEvent;
1459 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_REMOVE;
1461 for (const unotools::WeakReference<SwAccessibleContext>& rxCell : m_vecCellRemove)
1463 // fdo#57197: check if the object is still alive
1464 rtl::Reference<SwAccessibleContext> const pAccCell(rxCell);
1465 if (pAccCell)
1467 aEvent.NewValue <<= uno::Reference<XAccessible>(pAccCell);
1468 FireAccessibleEvent(aEvent);
1472 if (m_vecCellAdd.size() <= SELECTION_WITH_NUM)
1474 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_ADD;
1475 for (const unotools::WeakReference<SwAccessibleContext>& rxCell : m_vecCellAdd)
1477 // fdo#57197: check if the object is still alive
1478 rtl::Reference<SwAccessibleContext> const pAccCell(rxCell);
1479 if (pAccCell)
1481 aEvent.NewValue <<= uno::Reference<XAccessible>(pAccCell);
1482 FireAccessibleEvent(aEvent);
1486 else
1488 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_WITHIN;
1489 FireAccessibleEvent(aEvent);
1492 m_vecCellRemove.clear();
1493 m_vecCellAdd.clear();
1496 void SwAccessibleTable::AddSelectionCell(
1497 SwAccessibleContext *const pAccCell, bool const bAddOrRemove)
1499 if (bAddOrRemove)
1501 m_vecCellAdd.emplace_back(pAccCell);
1503 else
1505 m_vecCellRemove.emplace_back(pAccCell);
1509 // XAccessibleTableSelection
1510 sal_Bool SAL_CALL SwAccessibleTable::selectRow( sal_Int32 row )
1512 SolarMutexGuard g;
1514 if( isAccessibleRowSelected( row ) )
1515 return true;
1517 tools::Long lColumnCount = getAccessibleColumnCount();
1518 for(tools::Long lCol = 0; lCol < lColumnCount; lCol ++)
1520 sal_Int64 nChildIndex = getAccessibleIndex(row, lCol);
1521 selectAccessibleChild(nChildIndex);
1524 return true;
1526 sal_Bool SAL_CALL SwAccessibleTable::selectColumn( sal_Int32 column )
1528 SolarMutexGuard g;
1530 if( isAccessibleColumnSelected( column ) )
1531 return true;
1533 sal_Int32 lRowCount = getAccessibleRowCount();
1535 for(sal_Int32 lRow = 0; lRow < lRowCount; lRow ++)
1537 sal_Int64 nChildIndex = getAccessibleIndex(lRow, column);
1538 selectAccessibleChild(nChildIndex);
1540 return true;
1543 sal_Bool SAL_CALL SwAccessibleTable::unselectRow( sal_Int32 row )
1545 SolarMutexGuard g;
1547 if( isAccessibleSelected( row , 0 ) && isAccessibleSelected( row , getAccessibleColumnCount()-1 ) )
1549 SwCursorShell* pCursorShell = GetCursorShell();
1550 if( pCursorShell != nullptr )
1552 pCursorShell->StartAction();
1553 pCursorShell->ClearMark();
1554 pCursorShell->EndAction();
1555 return true;
1558 return true;
1561 sal_Bool SAL_CALL SwAccessibleTable::unselectColumn( sal_Int32 column )
1563 SolarMutexGuard g;
1565 if( isAccessibleSelected( 0 , column ) && isAccessibleSelected( getAccessibleRowCount()-1,column))
1567 SwCursorShell* pCursorShell = GetCursorShell();
1568 if( pCursorShell != nullptr )
1570 pCursorShell->StartAction();
1571 pCursorShell->ClearMark();
1572 pCursorShell->EndAction();
1573 return true;
1576 return true;
1579 // #i77106# - implementation of class <SwAccessibleTableColHeaders>
1580 SwAccessibleTableColHeaders::SwAccessibleTableColHeaders(
1581 std::shared_ptr<SwAccessibleMap> const& pMap,
1582 const SwTabFrame *const pTabFrame)
1583 : SwAccessibleTable(pMap, pTabFrame)
1585 SolarMutexGuard aGuard;
1587 const SwFrameFormat* pFrameFormat = pTabFrame->GetFormat();
1588 StartListening(const_cast<SwFrameFormat*>(pFrameFormat)->GetNotifier());
1589 const OUString aName = pFrameFormat->GetName() + "-ColumnHeaders";
1591 SetName( aName + "-" + OUString::number( pTabFrame->GetPhyPageNum() ) );
1593 const OUString sArg2( GetFormattedPageNumber() );
1595 SetDesc( GetResource( STR_ACCESS_TABLE_DESC, &aName, &sArg2 ) );
1597 NotRegisteredAtAccessibleMap(); // #i85634#
1600 std::unique_ptr<SwAccessibleTableData_Impl> SwAccessibleTableColHeaders::CreateNewTableData()
1602 const SwTabFrame* pTabFrame = static_cast<const SwTabFrame*>( GetFrame() );
1603 return std::unique_ptr<SwAccessibleTableData_Impl>(new SwAccessibleTableData_Impl( *(GetMap()), pTabFrame, IsInPagePreview(), true ));
1606 void SwAccessibleTableColHeaders::Notify(const SfxHint& )
1610 // XAccessibleContext
1611 sal_Int64 SAL_CALL SwAccessibleTableColHeaders::getAccessibleChildCount()
1613 SolarMutexGuard aGuard;
1615 ThrowIfDisposed();
1617 sal_Int32 nCount = 0;
1619 const SwTabFrame* pTabFrame = static_cast<const SwTabFrame*>( GetFrame() );
1620 const SwAccessibleChildSList aVisList( GetVisArea(), *pTabFrame, *(GetMap()) );
1621 SwAccessibleChildSList::const_iterator aIter( aVisList.begin() );
1622 while( aIter != aVisList.end() )
1624 const SwAccessibleChild& rLower = *aIter;
1625 if( rLower.IsAccessible( IsInPagePreview() ) )
1627 nCount++;
1629 else if( rLower.GetSwFrame() )
1631 // There are no unaccessible SdrObjects that count
1632 if ( !rLower.GetSwFrame()->IsRowFrame() ||
1633 pTabFrame->IsInHeadline( *(rLower.GetSwFrame()) ) )
1635 nCount += SwAccessibleFrame::GetChildCount( *(GetMap()),
1636 GetVisArea(),
1637 rLower.GetSwFrame(),
1638 IsInPagePreview() );
1641 ++aIter;
1644 return nCount;
1647 uno::Reference< XAccessible> SAL_CALL
1648 SwAccessibleTableColHeaders::getAccessibleChild (sal_Int64 nIndex)
1650 if ( nIndex < 0 || nIndex >= getAccessibleChildCount() )
1652 throw lang::IndexOutOfBoundsException();
1655 return SwAccessibleTable::getAccessibleChild( nIndex );
1658 // XAccessibleTable
1659 uno::Reference< XAccessibleTable >
1660 SAL_CALL SwAccessibleTableColHeaders::getAccessibleRowHeaders()
1662 return uno::Reference< XAccessibleTable >();
1665 uno::Reference< XAccessibleTable >
1666 SAL_CALL SwAccessibleTableColHeaders::getAccessibleColumnHeaders()
1668 return uno::Reference< XAccessibleTable >();
1671 // XServiceInfo
1673 OUString SAL_CALL SwAccessibleTableColHeaders::getImplementationName()
1675 static constexpr OUStringLiteral sImplName
1676 = u"com.sun.star.comp.Writer.SwAccessibleTableColumnHeadersView";
1677 return sImplName;
1680 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */