android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / core / access / acctable.cxx
blob0e3101c71ceff9fa421935ee042575a899fe0a7d
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& rBox = rLower.GetBox( mrAccMap );
233 if( pLower && rBox.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 ? (rBox.Left() - rTabPos.X())
248 : (rBox.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 ? (rBox.Right() - rTabPos.X())
256 : (rBox.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 "row or column index out of range",
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 SwAccessibleContext( pInitMap, AccessibleRole::TABLE, pTabFrame )
613 const SwFrameFormat* pFrameFormat = pTabFrame->GetFormat();
614 if(pFrameFormat)
615 StartListening(const_cast<SwFrameFormat*>(pFrameFormat)->GetNotifier());
617 SetName( pFrameFormat->GetName() + "-" + OUString::number( pTabFrame->GetPhyPageNum() ) );
619 const OUString sArg1( static_cast< const SwTabFrame * >( GetFrame() )->GetFormat()->GetName() );
620 const OUString sArg2( GetFormattedPageNumber() );
622 m_sDesc = GetResource( STR_ACCESS_TABLE_DESC, &sArg1, &sArg2 );
623 UpdateTableData();
626 SwAccessibleTable::~SwAccessibleTable()
628 SolarMutexGuard aGuard;
630 mpTableData.reset();
633 void SwAccessibleTable::Notify(const SfxHint& rHint)
635 const SwTabFrame* pTabFrame = static_cast<const SwTabFrame*>(GetFrame());
636 if(rHint.GetId() == SfxHintId::Dying)
638 EndListeningAll();
640 else if (rHint.GetId() == SfxHintId::SwNameChanged && pTabFrame)
642 const SwFrameFormat *pFrameFormat = pTabFrame->GetFormat();
643 const OUString sOldName( GetName() );
644 const OUString sNewTabName = pFrameFormat->GetName();
646 SetName( sNewTabName + "-" + OUString::number( pTabFrame->GetPhyPageNum() ) );
648 if( sOldName != GetName() )
650 AccessibleEventObject aEvent;
651 aEvent.EventId = AccessibleEventId::NAME_CHANGED;
652 aEvent.OldValue <<= sOldName;
653 aEvent.NewValue <<= GetName();
654 FireAccessibleEvent( aEvent );
657 const OUString sOldDesc( m_sDesc );
658 const OUString sArg2( GetFormattedPageNumber() );
660 m_sDesc = GetResource( STR_ACCESS_TABLE_DESC, &sNewTabName, &sArg2 );
661 if( m_sDesc != sOldDesc )
663 AccessibleEventObject aEvent;
664 aEvent.EventId = AccessibleEventId::DESCRIPTION_CHANGED;
665 aEvent.OldValue <<= sOldDesc;
666 aEvent.NewValue <<= m_sDesc;
667 FireAccessibleEvent( aEvent );
672 uno::Any SwAccessibleTable::queryInterface( const uno::Type& rType )
674 uno::Any aRet;
675 if ( rType == cppu::UnoType<XAccessibleTable>::get() )
677 uno::Reference<XAccessibleTable> xThis( this );
678 aRet <<= xThis;
680 else if ( rType == cppu::UnoType<XAccessibleSelection>::get() )
682 uno::Reference<XAccessibleSelection> xSelection( this );
683 aRet <<= xSelection;
685 else if ( rType == cppu::UnoType<XAccessibleTableSelection>::get() )
687 uno::Reference<XAccessibleTableSelection> xTableExtent( this );
688 aRet <<= xTableExtent;
690 else
692 aRet = SwAccessibleContext::queryInterface(rType);
695 return aRet;
698 // XTypeProvider
699 uno::Sequence< uno::Type > SAL_CALL SwAccessibleTable::getTypes()
701 return cppu::OTypeCollection(
702 cppu::UnoType<XAccessibleSelection>::get(),
703 cppu::UnoType<XAccessibleTable>::get(),
704 SwAccessibleContext::getTypes() ).getTypes();
707 uno::Sequence< sal_Int8 > SAL_CALL SwAccessibleTable::getImplementationId()
709 return css::uno::Sequence<sal_Int8>();
712 // #i77106#
713 std::unique_ptr<SwAccessibleTableData_Impl> SwAccessibleTable::CreateNewTableData()
715 const SwTabFrame* pTabFrame = static_cast<const SwTabFrame*>( GetFrame() );
716 return std::unique_ptr<SwAccessibleTableData_Impl>(new SwAccessibleTableData_Impl( *GetMap(), pTabFrame, IsInPagePreview() ));
719 void SwAccessibleTable::UpdateTableData()
721 // #i77106# - usage of new method <CreateNewTableData()>
722 mpTableData = CreateNewTableData();
725 void SwAccessibleTable::ClearTableData()
727 mpTableData.reset();
730 OUString SAL_CALL SwAccessibleTable::getAccessibleDescription()
732 SolarMutexGuard aGuard;
734 ThrowIfDisposed();
736 return m_sDesc;
739 sal_Int32 SAL_CALL SwAccessibleTable::getAccessibleRowCount()
741 SolarMutexGuard aGuard;
743 ThrowIfDisposed();
745 return GetTableData().GetRowCount();
748 sal_Int32 SAL_CALL SwAccessibleTable::getAccessibleColumnCount( )
750 SolarMutexGuard aGuard;
752 ThrowIfDisposed();
754 return GetTableData().GetColumnCount();
757 OUString SAL_CALL SwAccessibleTable::getAccessibleRowDescription(
758 sal_Int32 nRow )
760 // #i87532# - determine table cell in <nRow>th row and
761 // in first column of row header table and return its text content.
762 OUString sRowDesc;
764 GetTableData().CheckRowAndCol(nRow, 0, this);
766 uno::Reference< XAccessibleTable > xTableRowHeader = getAccessibleRowHeaders();
767 if ( xTableRowHeader.is() )
769 uno::Reference< XAccessible > xRowHeaderCell =
770 xTableRowHeader->getAccessibleCellAt( nRow, 0 );
771 OSL_ENSURE( xRowHeaderCell.is(),
772 "<SwAccessibleTable::getAccessibleRowDescription(..)> - missing row header cell -> serious issue." );
773 uno::Reference< XAccessibleContext > xRowHeaderCellContext =
774 xRowHeaderCell->getAccessibleContext();
775 const sal_Int64 nCellChildCount( xRowHeaderCellContext->getAccessibleChildCount() );
776 for ( sal_Int64 nChildIndex = 0; nChildIndex < nCellChildCount; ++nChildIndex )
778 uno::Reference< XAccessible > xChild = xRowHeaderCellContext->getAccessibleChild( nChildIndex );
779 uno::Reference< XAccessibleText > xChildText( xChild, uno::UNO_QUERY );
780 if ( xChildText.is() )
782 sRowDesc += xChildText->getText();
787 return sRowDesc;
790 OUString SAL_CALL SwAccessibleTable::getAccessibleColumnDescription(
791 sal_Int32 nColumn )
793 // #i87532# - determine table cell in first row and
794 // in <nColumn>th column of column header table and return its text content.
795 OUString sColumnDesc;
797 GetTableData().CheckRowAndCol(0, nColumn, this);
799 uno::Reference< XAccessibleTable > xTableColumnHeader = getAccessibleColumnHeaders();
800 if ( xTableColumnHeader.is() )
802 uno::Reference< XAccessible > xColumnHeaderCell =
803 xTableColumnHeader->getAccessibleCellAt( 0, nColumn );
804 OSL_ENSURE( xColumnHeaderCell.is(),
805 "<SwAccessibleTable::getAccessibleColumnDescription(..)> - missing column header cell -> serious issue." );
806 uno::Reference< XAccessibleContext > xColumnHeaderCellContext =
807 xColumnHeaderCell->getAccessibleContext();
808 const sal_Int64 nCellChildCount( xColumnHeaderCellContext->getAccessibleChildCount() );
809 for ( sal_Int64 nChildIndex = 0; nChildIndex < nCellChildCount; ++nChildIndex )
811 uno::Reference< XAccessible > xChild = xColumnHeaderCellContext->getAccessibleChild( nChildIndex );
812 uno::Reference< XAccessibleText > xChildText( xChild, uno::UNO_QUERY );
813 if ( xChildText.is() )
815 sColumnDesc += xChildText->getText();
820 return sColumnDesc;
823 sal_Int32 SAL_CALL SwAccessibleTable::getAccessibleRowExtentAt(
824 sal_Int32 nRow, sal_Int32 nColumn )
826 sal_Int32 nExtend = -1;
828 SolarMutexGuard aGuard;
830 ThrowIfDisposed();
832 UpdateTableData();
833 GetTableData().CheckRowAndCol( nRow, nColumn, this );
835 Int32Set_Impl::const_iterator aSttCol(
836 GetTableData().GetColumnIter( nColumn ) );
837 Int32Set_Impl::const_iterator aSttRow(
838 GetTableData().GetRowIter( nRow ) );
839 const SwFrame *pCellFrame = GetTableData().GetCellAtPos( *aSttCol, *aSttRow );
840 if( pCellFrame )
842 sal_Int32 nBottom = pCellFrame->getFrameArea().Bottom();
843 nBottom -= GetFrame()->getFrameArea().Top();
844 Int32Set_Impl::const_iterator aEndRow(
845 GetTableData().GetRows().upper_bound( nBottom ) );
846 nExtend =
847 static_cast< sal_Int32 >( std::distance( aSttRow, aEndRow ) );
850 return nExtend;
853 sal_Int32 SAL_CALL SwAccessibleTable::getAccessibleColumnExtentAt(
854 sal_Int32 nRow, sal_Int32 nColumn )
856 sal_Int32 nExtend = -1;
858 SolarMutexGuard aGuard;
860 ThrowIfDisposed();
861 UpdateTableData();
863 GetTableData().CheckRowAndCol( nRow, nColumn, this );
865 Int32Set_Impl::const_iterator aSttCol(
866 GetTableData().GetColumnIter( nColumn ) );
867 Int32Set_Impl::const_iterator aSttRow(
868 GetTableData().GetRowIter( nRow ) );
869 const SwFrame *pCellFrame = GetTableData().GetCellAtPos( *aSttCol, *aSttRow );
870 if( pCellFrame )
872 sal_Int32 nRight = pCellFrame->getFrameArea().Right();
873 nRight -= GetFrame()->getFrameArea().Left();
874 Int32Set_Impl::const_iterator aEndCol(
875 GetTableData().GetColumns().upper_bound( nRight ) );
876 nExtend =
877 static_cast< sal_Int32 >( std::distance( aSttCol, aEndCol ) );
880 return nExtend;
883 uno::Reference< XAccessibleTable > SAL_CALL
884 SwAccessibleTable::getAccessibleRowHeaders( )
886 // Row headers aren't supported
887 return uno::Reference< XAccessibleTable >();
890 uno::Reference< XAccessibleTable > SAL_CALL
891 SwAccessibleTable::getAccessibleColumnHeaders( )
893 SolarMutexGuard aGuard;
895 // #i87532# - assure that return accessible object is empty,
896 // if no column header exists.
897 rtl::Reference<SwAccessibleTableColHeaders> pTableColHeaders =
898 new SwAccessibleTableColHeaders(GetMap()->shared_from_this(),
899 static_cast<const SwTabFrame *>(GetFrame()));
900 if ( pTableColHeaders->getAccessibleChildCount() <= 0 )
902 return uno::Reference< XAccessibleTable >();
905 return pTableColHeaders;
908 uno::Sequence< sal_Int32 > SAL_CALL SwAccessibleTable::getSelectedAccessibleRows()
910 SolarMutexGuard aGuard;
912 ThrowIfDisposed();
914 const SwSelBoxes *pSelBoxes = GetSelBoxes();
915 if( pSelBoxes )
917 sal_Int32 nRows = GetTableData().GetRowCount();
918 SwAccAllTableSelHandler_Impl aSelRows( nRows );
920 GetTableData().GetSelection( 0, nRows, *pSelBoxes, aSelRows,
921 false );
923 return aSelRows.GetSelSequence();
925 else
927 return uno::Sequence< sal_Int32 >( 0 );
931 uno::Sequence< sal_Int32 > SAL_CALL SwAccessibleTable::getSelectedAccessibleColumns()
933 SolarMutexGuard aGuard;
935 ThrowIfDisposed();
937 const SwSelBoxes *pSelBoxes = GetSelBoxes();
938 if( pSelBoxes )
940 sal_Int32 nCols = GetTableData().GetColumnCount();
941 SwAccAllTableSelHandler_Impl aSelCols( nCols );
943 GetTableData().GetSelection( 0, nCols, *pSelBoxes, aSelCols, true );
945 return aSelCols.GetSelSequence();
947 else
949 return uno::Sequence< sal_Int32 >( 0 );
953 sal_Bool SAL_CALL SwAccessibleTable::isAccessibleRowSelected( sal_Int32 nRow )
955 SolarMutexGuard aGuard;
957 ThrowIfDisposed();
959 GetTableData().CheckRowAndCol( nRow, 0, this );
961 bool bRet;
962 const SwSelBoxes *pSelBoxes = GetSelBoxes();
963 if( pSelBoxes )
965 SwAccSingleTableSelHandler_Impl aSelRow;
966 GetTableData().GetSelection( nRow, nRow+1, *pSelBoxes, aSelRow,
967 false );
968 bRet = aSelRow.IsSelected();
970 else
972 bRet = false;
975 return bRet;
978 sal_Bool SAL_CALL SwAccessibleTable::isAccessibleColumnSelected(
979 sal_Int32 nColumn )
981 SolarMutexGuard aGuard;
983 ThrowIfDisposed();
985 GetTableData().CheckRowAndCol( 0, nColumn, this );
987 bool bRet;
988 const SwSelBoxes *pSelBoxes = GetSelBoxes();
989 if( pSelBoxes )
991 SwAccSingleTableSelHandler_Impl aSelCol;
993 GetTableData().GetSelection( nColumn, nColumn+1, *pSelBoxes, aSelCol,
994 true );
995 bRet = aSelCol.IsSelected();
997 else
999 bRet = false;
1002 return bRet;
1005 uno::Reference< XAccessible > SAL_CALL SwAccessibleTable::getAccessibleCellAt(
1006 sal_Int32 nRow, sal_Int32 nColumn )
1008 uno::Reference< XAccessible > xRet;
1010 SolarMutexGuard aGuard;
1012 ThrowIfDisposed();
1014 const SwFrame *pCellFrame =
1015 GetTableData().GetCell( nRow, nColumn, this );
1016 if( pCellFrame )
1017 xRet = GetMap()->GetContext( pCellFrame );
1019 return xRet;
1022 uno::Reference< XAccessible > SAL_CALL SwAccessibleTable::getAccessibleCaption()
1024 // captions aren't supported
1025 return uno::Reference< XAccessible >();
1028 uno::Reference< XAccessible > SAL_CALL SwAccessibleTable::getAccessibleSummary()
1030 // summaries aren't supported
1031 return uno::Reference< XAccessible >();
1034 sal_Bool SAL_CALL SwAccessibleTable::isAccessibleSelected(
1035 sal_Int32 nRow, sal_Int32 nColumn )
1037 bool bRet = false;
1039 SolarMutexGuard aGuard;
1041 ThrowIfDisposed();
1043 const SwFrame *pFrame =
1044 GetTableData().GetCell( nRow, nColumn, this );
1045 if( pFrame && pFrame->IsCellFrame() )
1047 const SwSelBoxes *pSelBoxes = GetSelBoxes();
1048 if( pSelBoxes )
1050 const SwCellFrame *pCFrame = static_cast < const SwCellFrame * >( pFrame );
1051 SwTableBox *pBox =
1052 const_cast< SwTableBox *>( pCFrame->GetTabBox() );
1053 bRet = pSelBoxes->find( pBox ) != pSelBoxes->end();
1057 return bRet;
1060 sal_Int64 SAL_CALL SwAccessibleTable::getAccessibleIndex(
1061 sal_Int32 nRow, sal_Int32 nColumn )
1063 sal_Int32 nRet = -1;
1065 SolarMutexGuard aGuard;
1067 ThrowIfDisposed();
1069 SwAccessibleChild aCell( GetTableData().GetCell( nRow, nColumn, this ));
1070 if ( aCell.IsValid() )
1072 nRet = GetChildIndex( *(GetMap()), aCell );
1075 return nRet;
1078 sal_Int32 SAL_CALL SwAccessibleTable::getAccessibleRow( sal_Int64 nChildIndex )
1080 sal_Int32 nRet = -1;
1082 SolarMutexGuard aGuard;
1084 ThrowIfDisposed();
1086 // #i77106#
1087 if ( ( nChildIndex < 0 ) ||
1088 ( nChildIndex >= getAccessibleChildCount() ) )
1090 throw lang::IndexOutOfBoundsException();
1093 SwAccessibleChild aCell( GetChild( *(GetMap()), nChildIndex ) );
1094 if ( aCell.GetSwFrame() )
1096 sal_Int32 nTop = aCell.GetSwFrame()->getFrameArea().Top();
1097 nTop -= GetFrame()->getFrameArea().Top();
1098 Int32Set_Impl::const_iterator aRow(
1099 GetTableData().GetRows().lower_bound( nTop ) );
1100 nRet = static_cast< sal_Int32 >( std::distance(
1101 GetTableData().GetRows().begin(), aRow ) );
1103 else
1105 OSL_ENSURE( !aCell.IsValid(), "SwAccessibleTable::getAccessibleColumn:"
1106 "aCell not expected to be valid.");
1108 throw lang::IndexOutOfBoundsException();
1111 return nRet;
1114 sal_Int32 SAL_CALL SwAccessibleTable::getAccessibleColumn(
1115 sal_Int64 nChildIndex )
1117 sal_Int32 nRet = -1;
1119 SolarMutexGuard aGuard;
1121 ThrowIfDisposed();
1123 // #i77106#
1124 if ( ( nChildIndex < 0 ) ||
1125 ( nChildIndex >= getAccessibleChildCount() ) )
1127 throw lang::IndexOutOfBoundsException();
1130 SwAccessibleChild aCell( GetChild( *(GetMap()), nChildIndex ) );
1131 if ( aCell.GetSwFrame() )
1133 sal_Int32 nLeft = aCell.GetSwFrame()->getFrameArea().Left();
1134 nLeft -= GetFrame()->getFrameArea().Left();
1135 Int32Set_Impl::const_iterator aCol(
1136 GetTableData().GetColumns().lower_bound( nLeft ) );
1137 nRet = static_cast< sal_Int32 >( std::distance(
1138 GetTableData().GetColumns().begin(), aCol ) );
1140 else
1142 OSL_ENSURE( !aCell.IsValid(), "SwAccessibleTable::getAccessibleColumn:"
1143 "aCell not expected to be valid.");
1145 throw lang::IndexOutOfBoundsException();
1148 return nRet;
1151 OUString SAL_CALL SwAccessibleTable::getImplementationName()
1153 return "com.sun.star.comp.Writer.SwAccessibleTableView";
1156 sal_Bool SAL_CALL SwAccessibleTable::supportsService(
1157 const OUString& sTestServiceName)
1159 return cppu::supportsService(this, sTestServiceName);
1162 uno::Sequence< OUString > SAL_CALL SwAccessibleTable::getSupportedServiceNames()
1164 return { "com.sun.star.table.AccessibleTableView", sAccessibleServiceName };
1167 void SwAccessibleTable::InvalidatePosOrSize( const SwRect& rOldBox )
1169 SolarMutexGuard aGuard;
1171 //need to update children
1172 std::unique_ptr<SwAccessibleTableData_Impl> pNewTableData = CreateNewTableData();
1173 if( !pNewTableData->CompareExtents( GetTableData() ) )
1175 mpTableData = std::move(pNewTableData);
1176 FireTableChangeEvent(*mpTableData);
1178 if( HasTableData() )
1179 GetTableData().SetTablePos( GetFrame()->getFrameArea().Pos() );
1181 SwAccessibleContext::InvalidatePosOrSize( rOldBox );
1184 void SwAccessibleTable::Dispose(bool bRecursive, bool bCanSkipInvisible)
1186 SolarMutexGuard aGuard;
1187 EndListeningAll();
1188 SwAccessibleContext::Dispose(bRecursive, bCanSkipInvisible);
1191 void SwAccessibleTable::DisposeChild( const SwAccessibleChild& rChildFrameOrObj,
1192 bool bRecursive, bool bCanSkipInvisible )
1194 SolarMutexGuard aGuard;
1196 const SwFrame *pFrame = rChildFrameOrObj.GetSwFrame();
1197 OSL_ENSURE( pFrame, "frame expected" );
1198 if( HasTableData() )
1200 FireTableChangeEvent( GetTableData() );
1201 ClearTableData();
1204 // There are two reason why this method has been called. The first one
1205 // is there is no context for pFrame. The method is then called by
1206 // the map, and we have to call our superclass.
1207 // The other situation is that we have been call by a call to get notified
1208 // about its change. We then must not call the superclass
1209 uno::Reference< XAccessible > xAcc( GetMap()->GetContext( pFrame, false ) );
1210 if( !xAcc.is() )
1211 SwAccessibleContext::DisposeChild( rChildFrameOrObj, bRecursive, bCanSkipInvisible );
1214 void SwAccessibleTable::InvalidateChildPosOrSize( const SwAccessibleChild& rChildFrameOrObj,
1215 const SwRect& rOldBox )
1217 SolarMutexGuard aGuard;
1219 if( HasTableData() )
1221 SAL_WARN_IF( HasTableData() &&
1222 GetFrame()->getFrameArea().Pos() != GetTableData().GetTablePos(),
1223 "sw.a11y", "table has invalid position" );
1224 if( HasTableData() )
1226 std::unique_ptr<SwAccessibleTableData_Impl> pNewTableData = CreateNewTableData(); // #i77106#
1227 if( !pNewTableData->CompareExtents( GetTableData() ) )
1229 if (pNewTableData->GetRowCount() != mpTableData->GetRowCount()
1230 && 1 < GetTableData().GetRowCount())
1232 Int32Set_Impl::const_iterator aSttCol( GetTableData().GetColumnIter( 0 ) );
1233 Int32Set_Impl::const_iterator aSttRow( GetTableData().GetRowIter( 1 ) );
1234 const SwFrame *pCellFrame = GetTableData().GetCellAtPos( *aSttCol, *aSttRow );
1235 Int32Set_Impl::const_iterator aSttCol2( pNewTableData->GetColumnIter( 0 ) );
1236 Int32Set_Impl::const_iterator aSttRow2( pNewTableData->GetRowIter( 0 ) );
1237 const SwFrame *pCellFrame2 = pNewTableData->GetCellAtPos( *aSttCol2, *aSttRow2 );
1239 if(pCellFrame == pCellFrame2)
1241 AccessibleTableModelChange aModelChange;
1242 aModelChange.Type = AccessibleTableModelChangeType::UPDATE;
1243 aModelChange.FirstRow = 0;
1244 aModelChange.LastRow = mpTableData->GetRowCount() - 1;
1245 aModelChange.FirstColumn = 0;
1246 aModelChange.LastColumn = mpTableData->GetColumnCount() - 1;
1248 AccessibleEventObject aEvent;
1249 aEvent.EventId = AccessibleEventId::TABLE_COLUMN_HEADER_CHANGED;
1250 aEvent.NewValue <<= aModelChange;
1252 FireAccessibleEvent( aEvent );
1255 else
1256 FireTableChangeEvent( GetTableData() );
1257 ClearTableData();
1258 mpTableData = std::move(pNewTableData);
1263 // #i013961# - always call super class method
1264 SwAccessibleContext::InvalidateChildPosOrSize( rChildFrameOrObj, rOldBox );
1267 // XAccessibleSelection
1269 void SAL_CALL SwAccessibleTable::selectAccessibleChild(
1270 sal_Int64 nChildIndex )
1272 SolarMutexGuard aGuard;
1274 ThrowIfDisposed();
1276 if( (nChildIndex < 0) || (nChildIndex >= getAccessibleChildCount()) ) // #i77106#
1277 throw lang::IndexOutOfBoundsException();
1279 // preliminaries: get 'our' table box, and get the cursor shell
1280 const SwTableBox* pBox = GetTableBox( nChildIndex );
1281 OSL_ENSURE( pBox != nullptr, "We need the table box." );
1283 SwCursorShell* pCursorShell = GetCursorShell();
1284 if( pCursorShell == nullptr )
1285 return;
1287 // assure, that child, identified by the given index, isn't already selected.
1288 if ( IsChildSelected( nChildIndex ) )
1290 return;
1293 // now we can start to do the work: check whether we already have
1294 // a table selection (in 'our' table). If so, extend the
1295 // selection, else select the current cell.
1297 // if we have a selection in a table, check if it's in the
1298 // same table that we're trying to select in
1299 const SwTableNode* pSelectedTable = pCursorShell->IsCursorInTable();
1300 if( pSelectedTable != nullptr )
1302 // get top-most table line
1303 const SwTableLine* pUpper = pBox->GetUpper();
1304 while( pUpper->GetUpper() != nullptr )
1305 pUpper = pUpper->GetUpper()->GetUpper();
1306 sal_uInt16 nPos =
1307 pSelectedTable->GetTable().GetTabLines().GetPos( pUpper );
1308 if( nPos == USHRT_MAX )
1309 pSelectedTable = nullptr;
1312 // create the new selection
1313 const SwStartNode* pStartNode = pBox->GetSttNd();
1314 if( pSelectedTable == nullptr || !pCursorShell->GetTableCrs() )
1316 pCursorShell->StartAction();
1317 // Set cursor into current cell. This deletes any table cursor.
1318 SwPaM aPaM( *pStartNode );
1319 aPaM.Move( fnMoveForward, GoInNode );
1320 Select( aPaM );
1321 // Move cursor to the end of the table creating a selection and a table
1322 // cursor.
1323 pCursorShell->SetMark();
1324 pCursorShell->MoveTable( GotoCurrTable, fnTableEnd );
1325 // now set the cursor into the cell again.
1326 SwPaM *pPaM = pCursorShell->GetTableCrs() ? pCursorShell->GetTableCrs()
1327 : pCursorShell->GetCursor();
1328 *pPaM->GetPoint() = *pPaM->GetMark();
1329 pCursorShell->EndAction();
1330 // we now have one cell selected!
1332 else
1334 // if the cursor is already in this table,
1335 // expand the current selection (i.e., set
1336 // point to new position; keep mark)
1337 SwPaM aPaM( *pStartNode );
1338 aPaM.Move( fnMoveForward, GoInNode );
1339 aPaM.SetMark();
1340 const SwPaM *pPaM = pCursorShell->GetTableCrs() ? pCursorShell->GetTableCrs()
1341 : pCursorShell->GetCursor();
1342 *(aPaM.GetMark()) = *pPaM->GetMark();
1343 Select( aPaM );
1348 sal_Bool SAL_CALL SwAccessibleTable::isAccessibleChildSelected(
1349 sal_Int64 nChildIndex )
1351 SolarMutexGuard aGuard;
1353 ThrowIfDisposed();
1355 if( (nChildIndex < 0) || (nChildIndex >= getAccessibleChildCount()) ) // #i77106#
1356 throw lang::IndexOutOfBoundsException();
1358 return IsChildSelected( nChildIndex );
1361 void SAL_CALL SwAccessibleTable::clearAccessibleSelection( )
1363 SolarMutexGuard aGuard;
1365 ThrowIfDisposed();
1367 SwCursorShell* pCursorShell = GetCursorShell();
1368 if( pCursorShell != nullptr )
1370 pCursorShell->StartAction();
1371 pCursorShell->ClearMark();
1372 pCursorShell->EndAction();
1376 void SAL_CALL SwAccessibleTable::selectAllAccessibleChildren( )
1378 // first clear selection, then select first and last child
1379 clearAccessibleSelection();
1380 selectAccessibleChild( 0 );
1381 selectAccessibleChild( getAccessibleChildCount()-1 ); // #i77106#
1384 sal_Int64 SAL_CALL SwAccessibleTable::getSelectedAccessibleChildCount( )
1386 SolarMutexGuard aGuard;
1388 ThrowIfDisposed();
1390 // iterate over all children and count isAccessibleChildSelected()
1391 sal_Int64 nCount = 0;
1393 sal_Int64 nChildren = getAccessibleChildCount(); // #i71106#
1394 for( sal_Int64 n = 0; n < nChildren; n++ )
1395 if( IsChildSelected( n ) )
1396 nCount++;
1398 return nCount;
1401 uno::Reference<XAccessible> SAL_CALL SwAccessibleTable::getSelectedAccessibleChild(
1402 sal_Int64 nSelectedChildIndex )
1404 SolarMutexGuard aGuard;
1406 ThrowIfDisposed();
1408 // parameter checking (part 1): index lower 0
1409 if( nSelectedChildIndex < 0 )
1410 throw lang::IndexOutOfBoundsException();
1412 sal_Int64 nChildIndex = GetIndexOfSelectedChild( nSelectedChildIndex );
1414 // parameter checking (part 2): index higher than selected children?
1415 if( nChildIndex < 0 )
1416 throw lang::IndexOutOfBoundsException();
1418 // #i77106#
1419 if ( nChildIndex >= getAccessibleChildCount() )
1421 throw lang::IndexOutOfBoundsException();
1424 return getAccessibleChild( nChildIndex );
1427 // index has to be treated as global child index.
1428 void SAL_CALL SwAccessibleTable::deselectAccessibleChild(
1429 sal_Int64 nChildIndex )
1431 SolarMutexGuard aGuard;
1433 ThrowIfDisposed();
1435 SwCursorShell* pCursorShell = GetCursorShell();
1437 // index has to be treated as global child index
1438 if ( !pCursorShell )
1439 throw lang::IndexOutOfBoundsException();
1441 // assure, that given child index is in bounds.
1442 if ( nChildIndex < 0 || nChildIndex >= getAccessibleChildCount() ) // #i77106#
1443 throw lang::IndexOutOfBoundsException();
1445 // assure, that child, identified by the given index, is selected.
1446 if ( !IsChildSelected( nChildIndex ) )
1447 return;
1449 const SwTableBox* pBox = GetTableBox( nChildIndex );
1450 OSL_ENSURE( pBox != nullptr, "We need the table box." );
1452 // If we unselect point, then set cursor to mark. If we clear another
1453 // selected box, then set cursor to point.
1454 // reduce selection to mark.
1455 SwPaM *pPaM = pCursorShell->GetTableCrs() ? pCursorShell->GetTableCrs()
1456 : pCursorShell->GetCursor();
1457 bool bDeselectPoint =
1458 pBox->GetSttNd() ==
1459 pPaM->GetPoint()->GetNode().FindTableBoxStartNode();
1461 SwPaM aPaM( bDeselectPoint ? *pPaM->GetMark() : *pPaM->GetPoint() );
1463 pCursorShell->StartAction();
1465 // Set cursor into either point or mark
1466 Select( aPaM );
1467 // Move cursor to the end of the table creating a selection and a table
1468 // cursor.
1469 pCursorShell->SetMark();
1470 pCursorShell->MoveTable( GotoCurrTable, fnTableEnd );
1471 // now set the cursor into the cell again.
1472 pPaM = pCursorShell->GetTableCrs() ? pCursorShell->GetTableCrs()
1473 : pCursorShell->GetCursor();
1474 *pPaM->GetPoint() = *pPaM->GetMark();
1475 pCursorShell->EndAction();
1478 sal_Int32 SAL_CALL SwAccessibleTable::getBackground()
1480 const SvxBrushItem &rBack = GetFrame()->GetAttrSet()->GetBackground();
1481 Color crBack = rBack.GetColor();
1483 if (COL_AUTO == crBack)
1485 uno::Reference<XAccessible> xAccDoc = getAccessibleParent();
1486 if (xAccDoc.is())
1488 uno::Reference<XAccessibleComponent> xComponentDoc(xAccDoc,uno::UNO_QUERY);
1489 if (xComponentDoc.is())
1491 crBack = Color(ColorTransparency, xComponentDoc->getBackground());
1495 return sal_Int32(crBack);
1498 void SwAccessibleTable::FireSelectionEvent( )
1500 AccessibleEventObject aEvent;
1502 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_REMOVE;
1504 for (const auto& rCell : m_vecCellRemove)
1506 // fdo#57197: check if the object is still alive
1507 uno::Reference<XAccessible> const xAcc(rCell.second);
1508 if (xAcc.is())
1510 SwAccessibleContext *const pAccCell(rCell.first);
1511 assert(pAccCell);
1512 pAccCell->FireAccessibleEvent(aEvent);
1516 if (m_vecCellAdd.size() <= SELECTION_WITH_NUM)
1518 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_ADD;
1519 for (const auto& rCell : m_vecCellAdd)
1521 // fdo#57197: check if the object is still alive
1522 uno::Reference<XAccessible> const xAcc(rCell.second);
1523 if (xAcc.is())
1525 SwAccessibleContext *const pAccCell(rCell.first);
1526 assert(pAccCell);
1527 pAccCell->FireAccessibleEvent(aEvent);
1530 return ;
1532 else
1534 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_WITHIN;
1535 FireAccessibleEvent(aEvent);
1539 void SwAccessibleTable::AddSelectionCell(
1540 SwAccessibleContext *const pAccCell, bool const bAddOrRemove)
1542 uno::Reference<XAccessible> const xTmp(pAccCell);
1543 if (bAddOrRemove)
1545 m_vecCellAdd.emplace_back(pAccCell, xTmp);
1547 else
1549 m_vecCellRemove.emplace_back(pAccCell, xTmp);
1553 // XAccessibleTableSelection
1554 sal_Bool SAL_CALL SwAccessibleTable::selectRow( sal_Int32 row )
1556 SolarMutexGuard g;
1558 if( isAccessibleRowSelected( row ) )
1559 return true;
1561 tools::Long lColumnCount = getAccessibleColumnCount();
1562 for(tools::Long lCol = 0; lCol < lColumnCount; lCol ++)
1564 sal_Int64 nChildIndex = getAccessibleIndex(row, lCol);
1565 selectAccessibleChild(nChildIndex);
1568 return true;
1570 sal_Bool SAL_CALL SwAccessibleTable::selectColumn( sal_Int32 column )
1572 SolarMutexGuard g;
1574 if( isAccessibleColumnSelected( column ) )
1575 return true;
1577 sal_Int32 lRowCount = getAccessibleRowCount();
1579 for(sal_Int32 lRow = 0; lRow < lRowCount; lRow ++)
1581 sal_Int64 nChildIndex = getAccessibleIndex(lRow, column);
1582 selectAccessibleChild(nChildIndex);
1584 return true;
1587 sal_Bool SAL_CALL SwAccessibleTable::unselectRow( sal_Int32 row )
1589 SolarMutexGuard g;
1591 if( isAccessibleSelected( row , 0 ) && isAccessibleSelected( row , getAccessibleColumnCount()-1 ) )
1593 SwCursorShell* pCursorShell = GetCursorShell();
1594 if( pCursorShell != nullptr )
1596 pCursorShell->StartAction();
1597 pCursorShell->ClearMark();
1598 pCursorShell->EndAction();
1599 return true;
1602 return true;
1605 sal_Bool SAL_CALL SwAccessibleTable::unselectColumn( sal_Int32 column )
1607 SolarMutexGuard g;
1609 if( isAccessibleSelected( 0 , column ) && isAccessibleSelected( getAccessibleRowCount()-1,column))
1611 SwCursorShell* pCursorShell = GetCursorShell();
1612 if( pCursorShell != nullptr )
1614 pCursorShell->StartAction();
1615 pCursorShell->ClearMark();
1616 pCursorShell->EndAction();
1617 return true;
1620 return true;
1623 // #i77106# - implementation of class <SwAccessibleTableColHeaders>
1624 SwAccessibleTableColHeaders::SwAccessibleTableColHeaders(
1625 std::shared_ptr<SwAccessibleMap> const& pMap,
1626 const SwTabFrame *const pTabFrame)
1627 : SwAccessibleTable(pMap, pTabFrame)
1629 SolarMutexGuard aGuard;
1631 const SwFrameFormat* pFrameFormat = pTabFrame->GetFormat();
1632 if(pFrameFormat)
1633 StartListening(const_cast<SwFrameFormat*>(pFrameFormat)->GetNotifier());
1634 const OUString aName = pFrameFormat->GetName() + "-ColumnHeaders";
1636 SetName( aName + "-" + OUString::number( pTabFrame->GetPhyPageNum() ) );
1638 const OUString sArg2( GetFormattedPageNumber() );
1640 SetDesc( GetResource( STR_ACCESS_TABLE_DESC, &aName, &sArg2 ) );
1642 NotRegisteredAtAccessibleMap(); // #i85634#
1645 std::unique_ptr<SwAccessibleTableData_Impl> SwAccessibleTableColHeaders::CreateNewTableData()
1647 const SwTabFrame* pTabFrame = static_cast<const SwTabFrame*>( GetFrame() );
1648 return std::unique_ptr<SwAccessibleTableData_Impl>(new SwAccessibleTableData_Impl( *(GetMap()), pTabFrame, IsInPagePreview(), true ));
1651 void SwAccessibleTableColHeaders::Notify(const SfxHint& )
1655 // XInterface
1656 uno::Any SAL_CALL SwAccessibleTableColHeaders::queryInterface( const uno::Type& aType )
1658 return SwAccessibleTable::queryInterface( aType );
1661 // XAccessibleContext
1662 sal_Int64 SAL_CALL SwAccessibleTableColHeaders::getAccessibleChildCount()
1664 SolarMutexGuard aGuard;
1666 ThrowIfDisposed();
1668 sal_Int32 nCount = 0;
1670 const SwTabFrame* pTabFrame = static_cast<const SwTabFrame*>( GetFrame() );
1671 const SwAccessibleChildSList aVisList( GetVisArea(), *pTabFrame, *(GetMap()) );
1672 SwAccessibleChildSList::const_iterator aIter( aVisList.begin() );
1673 while( aIter != aVisList.end() )
1675 const SwAccessibleChild& rLower = *aIter;
1676 if( rLower.IsAccessible( IsInPagePreview() ) )
1678 nCount++;
1680 else if( rLower.GetSwFrame() )
1682 // There are no unaccessible SdrObjects that count
1683 if ( !rLower.GetSwFrame()->IsRowFrame() ||
1684 pTabFrame->IsInHeadline( *(rLower.GetSwFrame()) ) )
1686 nCount += SwAccessibleFrame::GetChildCount( *(GetMap()),
1687 GetVisArea(),
1688 rLower.GetSwFrame(),
1689 IsInPagePreview() );
1692 ++aIter;
1695 return nCount;
1698 uno::Reference< XAccessible> SAL_CALL
1699 SwAccessibleTableColHeaders::getAccessibleChild (sal_Int64 nIndex)
1701 if ( nIndex < 0 || nIndex >= getAccessibleChildCount() )
1703 throw lang::IndexOutOfBoundsException();
1706 return SwAccessibleTable::getAccessibleChild( nIndex );
1709 // XAccessibleTable
1710 uno::Reference< XAccessibleTable >
1711 SAL_CALL SwAccessibleTableColHeaders::getAccessibleRowHeaders()
1713 return uno::Reference< XAccessibleTable >();
1716 uno::Reference< XAccessibleTable >
1717 SAL_CALL SwAccessibleTableColHeaders::getAccessibleColumnHeaders()
1719 return uno::Reference< XAccessibleTable >();
1722 // XServiceInfo
1724 OUString SAL_CALL SwAccessibleTableColHeaders::getImplementationName()
1726 static constexpr OUStringLiteral sImplName
1727 = u"com.sun.star.comp.Writer.SwAccessibleTableColumnHeadersView";
1728 return sImplName;
1731 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */