1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20 #include <sal/log.hxx>
21
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 <unotools/accessiblestatesethelper.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 <hints.hxx>
39 #include "accfrmobjslist.hxx"
40 #include <accmap.hxx>
41 #include <strings.hrc>
42 #include "acctable.hxx"
43
44 #include <com/sun/star/accessibility/XAccessibleText.hpp>
45
46 #include <editeng/brushitem.hxx>
47 #include <swatrset.hxx>
48 #include <frmatr.hxx>
49
50 #include <cppuhelper/supportsservice.hxx>
51 #include <cppuhelper/typeprovider.hxx>
52
53 using namespace ::com::sun::star;
54 using namespace ::com::sun::star::accessibility;
55 using namespace ::sw::access;
56
57 typedef o3tl::sorted_vector< sal_Int32 > Int32Set_Impl;
58 typedef std::pair < sal_Int32, sal_Int32 > Int32Pair_Impl;
59
60 const unsigned int SELECTION_WITH_NUM = 10;
61
62 class SwAccTableSelHander_Impl
63 {
64 public:
65 virtual void Unselect( sal_Int32 nRowOrCol, sal_Int32 nExt ) = 0;
66
67 protected:
~SwAccTableSelHander_Impl()68 ~SwAccTableSelHander_Impl() {}
69 };
70
71 class SwAccessibleTableData_Impl
72 {
73 SwAccessibleMap& mrAccMap;
74 Int32Set_Impl maRows;
75 Int32Set_Impl maColumns;
76 Point maTabFramePos;
77 const SwTabFrame *mpTabFrame;
78 bool const mbIsInPagePreview;
79 bool const mbOnlyTableColumnHeader;
80
81 void CollectData( const SwFrame *pFrame );
82
83 bool FindCell( const Point& rPos, const SwFrame *pFrame ,
84 bool bExact, const SwFrame *& rFrame ) const;
85
86 void GetSelection( const Point& rTabPos, const SwRect& rArea,
87 const SwSelBoxes& rSelBoxes, const SwFrame *pFrame,
88 SwAccTableSelHander_Impl& rSelHdl,
89 bool bColumns ) const;
90
91 // #i77106#
IncludeRow(const SwFrame & rFrame) const92 bool IncludeRow( const SwFrame& rFrame ) const
93 {
94 return !mbOnlyTableColumnHeader ||
95 mpTabFrame->IsInHeadline( rFrame );
96 }
97 public:
98 // #i77106# - add third optional parameter <bOnlyTableColumnHeader>, default value <false>
99 SwAccessibleTableData_Impl( SwAccessibleMap& rAccMap,
100 const SwTabFrame *pTabFrame,
101 bool bIsInPagePreview,
102 bool bOnlyTableColumnHeader = false );
103
GetRows() const104 const Int32Set_Impl& GetRows() const { return maRows; }
GetColumns() const105 const Int32Set_Impl& GetColumns() const { return maColumns; }
106
107 inline Int32Set_Impl::const_iterator GetRowIter( sal_Int32 nRow ) const;
108 inline Int32Set_Impl::const_iterator GetColumnIter( sal_Int32 nCol ) const;
109
110 /// @throws lang::IndexOutOfBoundsException
111 /// @throws uno::RuntimeException
112 const SwFrame *GetCell( sal_Int32 nRow, sal_Int32 nColumn, SwAccessibleTable *pThis ) const;
113 const SwFrame *GetCellAtPos( sal_Int32 nLeft, sal_Int32 nTop ) const;
114 inline sal_Int32 GetRowCount() const;
115 inline sal_Int32 GetColumnCount() const;
116 bool CompareExtents( const SwAccessibleTableData_Impl& r ) const;
117
118 void GetSelection( sal_Int32 nStart, sal_Int32 nEnd,
119 const SwSelBoxes& rSelBoxes,
120 SwAccTableSelHander_Impl& rSelHdl,
121 bool bColumns ) const;
122
123 /// @throws lang::IndexOutOfBoundsException
124 void CheckRowAndCol( sal_Int32 nRow, sal_Int32 nCol,
125 SwAccessibleTable *pThis ) const;
126
GetTablePos() const127 const Point& GetTablePos() const { return maTabFramePos; }
SetTablePos(const Point & rPos)128 void SetTablePos( const Point& rPos ) { maTabFramePos = rPos; }
129 };
130
CollectData(const SwFrame * pFrame)131 void SwAccessibleTableData_Impl::CollectData( const SwFrame *pFrame )
132 {
133 const SwAccessibleChildSList aList( *pFrame, mrAccMap );
134 SwAccessibleChildSList::const_iterator aIter( aList.begin() );
135 SwAccessibleChildSList::const_iterator aEndIter( aList.end() );
136 while( aIter != aEndIter )
137 {
138 const SwAccessibleChild& rLower = *aIter;
139 const SwFrame *pLower = rLower.GetSwFrame();
140 if( pLower )
141 {
142 if( pLower->IsRowFrame() )
143 {
144 // #i77106#
145 if ( IncludeRow( *pLower ) )
146 {
147 maRows.insert( pLower->getFrameArea().Top() - maTabFramePos.getY() );
148 CollectData( pLower );
149 }
150 }
151 else if( pLower->IsCellFrame() &&
152 rLower.IsAccessible( mbIsInPagePreview ) )
153 {
154 maColumns.insert( pLower->getFrameArea().Left() - maTabFramePos.getX() );
155 }
156 else
157 {
158 CollectData( pLower );
159 }
160 }
161 ++aIter;
162 }
163 }
164
FindCell(const Point & rPos,const SwFrame * pFrame,bool bExact,const SwFrame * & rRet) const165 bool SwAccessibleTableData_Impl::FindCell(
166 const Point& rPos, const SwFrame *pFrame, bool bExact,
167 const SwFrame *& rRet ) const
168 {
169 bool bFound = false;
170
171 const SwAccessibleChildSList aList( *pFrame, mrAccMap );
172 SwAccessibleChildSList::const_iterator aIter( aList.begin() );
173 SwAccessibleChildSList::const_iterator aEndIter( aList.end() );
174 while( !bFound && aIter != aEndIter )
175 {
176 const SwAccessibleChild& rLower = *aIter;
177 const SwFrame *pLower = rLower.GetSwFrame();
178 OSL_ENSURE( pLower, "child should be a frame" );
179 if( pLower )
180 {
181 if( rLower.IsAccessible( mbIsInPagePreview ) )
182 {
183 OSL_ENSURE( pLower->IsCellFrame(), "lower is not a cell frame" );
184 const SwRect& rFrame = pLower->getFrameArea();
185 if( rFrame.Right() >= rPos.X() && rFrame.Bottom() >= rPos.Y() )
186 {
187 // We have found the cell
188 OSL_ENSURE( rFrame.Left() <= rPos.X() && rFrame.Top() <= rPos.Y(),
189 "find frame moved to far!" );
190 bFound = true;
191 if( !bExact ||
192 (rFrame.Top() == rPos.Y() && rFrame.Left() == rPos.Y() ) )
193 {
194 rRet = pLower;
195 }
196 }
197 }
198 else
199 {
200 // #i77106#
201 if ( !pLower->IsRowFrame() ||
202 IncludeRow( *pLower ) )
203 {
204 bFound = FindCell( rPos, pLower, bExact, rRet );
205 }
206 }
207 }
208 ++aIter;
209 }
210
211 return bFound;
212 }
213
GetSelection(const Point & rTabPos,const SwRect & rArea,const SwSelBoxes & rSelBoxes,const SwFrame * pFrame,SwAccTableSelHander_Impl & rSelHdl,bool bColumns) const214 void SwAccessibleTableData_Impl::GetSelection(
215 const Point& rTabPos,
216 const SwRect& rArea,
217 const SwSelBoxes& rSelBoxes,
218 const SwFrame *pFrame,
219 SwAccTableSelHander_Impl& rSelHdl,
220 bool bColumns ) const
221 {
222 const SwAccessibleChildSList aList( *pFrame, mrAccMap );
223 SwAccessibleChildSList::const_iterator aIter( aList.begin() );
224 SwAccessibleChildSList::const_iterator aEndIter( aList.end() );
225 while( aIter != aEndIter )
226 {
227 const SwAccessibleChild& rLower = *aIter;
228 const SwFrame *pLower = rLower.GetSwFrame();
229 OSL_ENSURE( pLower, "child should be a frame" );
230 const SwRect& rBox = rLower.GetBox( mrAccMap );
231 if( pLower && rBox.IsOver( rArea ) )
232 {
233 if( rLower.IsAccessible( mbIsInPagePreview ) )
234 {
235 OSL_ENSURE( pLower->IsCellFrame(), "lower is not a cell frame" );
236 const SwCellFrame *pCFrame =
237 static_cast < const SwCellFrame * >( pLower );
238 SwTableBox *pBox =
239 const_cast< SwTableBox *>( pCFrame->GetTabBox() );
240 if( rSelBoxes.find( pBox ) == rSelBoxes.end() )
241 {
242 const Int32Set_Impl rRowsOrCols =
243 bColumns ? maColumns : maRows;
244
245 sal_Int32 nPos = bColumns ? (rBox.Left() - rTabPos.X())
246 : (rBox.Top() - rTabPos.Y());
247 Int32Set_Impl::const_iterator aSttRowOrCol(
248 rRowsOrCols.lower_bound( nPos ) );
249 sal_Int32 nRowOrCol =
250 static_cast< sal_Int32 >( std::distance(
251 rRowsOrCols.begin(), aSttRowOrCol ) );
252
253 nPos = bColumns ? (rBox.Right() - rTabPos.X())
254 : (rBox.Bottom() - rTabPos.Y());
255 Int32Set_Impl::const_iterator aEndRowOrCol(
256 rRowsOrCols.upper_bound( nPos ) );
257 sal_Int32 nExt =
258 static_cast< sal_Int32 >( std::distance(
259 aSttRowOrCol, aEndRowOrCol ) );
260
261 rSelHdl.Unselect( nRowOrCol, nExt );
262 }
263 }
264 else
265 {
266 // #i77106#
267 if ( !pLower->IsRowFrame() ||
268 IncludeRow( *pLower ) )
269 {
270 GetSelection( rTabPos, rArea, rSelBoxes, pLower, rSelHdl,
271 bColumns );
272 }
273 }
274 }
275 ++aIter;
276 }
277 }
278
GetCell(sal_Int32 nRow,sal_Int32 nColumn,SwAccessibleTable * pThis) const279 const SwFrame *SwAccessibleTableData_Impl::GetCell(
280 sal_Int32 nRow, sal_Int32 nColumn,
281 SwAccessibleTable *pThis ) const
282 {
283 CheckRowAndCol( nRow, nColumn, pThis );
284
285 Int32Set_Impl::const_iterator aSttCol( GetColumnIter( nColumn ) );
286 Int32Set_Impl::const_iterator aSttRow( GetRowIter( nRow ) );
287 const SwFrame *pCellFrame = GetCellAtPos( *aSttCol, *aSttRow );
288
289 return pCellFrame;
290 }
291
GetSelection(sal_Int32 nStart,sal_Int32 nEnd,const SwSelBoxes & rSelBoxes,SwAccTableSelHander_Impl & rSelHdl,bool bColumns) const292 void SwAccessibleTableData_Impl::GetSelection(
293 sal_Int32 nStart, sal_Int32 nEnd,
294 const SwSelBoxes& rSelBoxes,
295 SwAccTableSelHander_Impl& rSelHdl,
296 bool bColumns ) const
297 {
298 SwRect aArea( mpTabFrame->getFrameArea() );
299 Point aPos( aArea.Pos() );
300
301 const Int32Set_Impl& rRowsOrColumns = bColumns ? maColumns : maRows;
302 if( nStart > 0 )
303 {
304 Int32Set_Impl::const_iterator aStt( rRowsOrColumns.begin() );
305 std::advance( aStt,
306 static_cast< Int32Set_Impl::difference_type >( nStart ) );
307 if( bColumns )
308 aArea.Left( *aStt + aPos.getX() );
309 else
310 aArea.Top( *aStt + aPos.getY() );
311 }
312 if( nEnd < static_cast< sal_Int32 >( rRowsOrColumns.size() ) )
313 {
314 Int32Set_Impl::const_iterator aEnd( rRowsOrColumns.begin() );
315 std::advance( aEnd,
316 static_cast< Int32Set_Impl::difference_type >( nEnd ) );
317 if( bColumns )
318 aArea.Right( *aEnd + aPos.getX() - 1 );
319 else
320 aArea.Bottom( *aEnd + aPos.getY() - 1 );
321 }
322
323 GetSelection( aPos, aArea, rSelBoxes, mpTabFrame, rSelHdl, bColumns );
324 }
325
GetCellAtPos(sal_Int32 nLeft,sal_Int32 nTop) const326 const SwFrame *SwAccessibleTableData_Impl::GetCellAtPos(
327 sal_Int32 nLeft, sal_Int32 nTop ) const
328 {
329 Point aPos( mpTabFrame->getFrameArea().Pos() );
330 aPos.Move( nLeft, nTop );
331 const SwFrame *pRet = nullptr;
332 FindCell( aPos, mpTabFrame, false/*bExact*/, pRet );
333
334 return pRet;
335 }
336
GetRowCount() const337 inline sal_Int32 SwAccessibleTableData_Impl::GetRowCount() const
338 {
339 sal_Int32 count = static_cast< sal_Int32 >( maRows.size() ) ;
340 count = (count <=0)? 1:count;
341 return count;
342 }
343
GetColumnCount() const344 inline sal_Int32 SwAccessibleTableData_Impl::GetColumnCount() const
345 {
346 return static_cast< sal_Int32 >( maColumns.size() );
347 }
348
CompareExtents(const SwAccessibleTableData_Impl & rCmp) const349 bool SwAccessibleTableData_Impl::CompareExtents(
350 const SwAccessibleTableData_Impl& rCmp ) const
351 {
352 return maRows == rCmp.maRows
353 && maColumns == rCmp.maColumns;
354 }
355
SwAccessibleTableData_Impl(SwAccessibleMap & rAccMap,const SwTabFrame * pTabFrame,bool bIsInPagePreview,bool bOnlyTableColumnHeader)356 SwAccessibleTableData_Impl::SwAccessibleTableData_Impl( SwAccessibleMap& rAccMap,
357 const SwTabFrame *pTabFrame,
358 bool bIsInPagePreview,
359 bool bOnlyTableColumnHeader )
360 : mrAccMap( rAccMap )
361 , maTabFramePos( pTabFrame->getFrameArea().Pos() )
362 , mpTabFrame( pTabFrame )
363 , mbIsInPagePreview( bIsInPagePreview )
364 , mbOnlyTableColumnHeader( bOnlyTableColumnHeader )
365 {
366 CollectData( mpTabFrame );
367 }
368
GetRowIter(sal_Int32 nRow) const369 inline Int32Set_Impl::const_iterator SwAccessibleTableData_Impl::GetRowIter(
370 sal_Int32 nRow ) const
371 {
372 Int32Set_Impl::const_iterator aCol( GetRows().begin() );
373 if( nRow > 0 )
374 {
375 std::advance( aCol,
376 static_cast< Int32Set_Impl::difference_type >( nRow ) );
377 }
378 return aCol;
379 }
380
GetColumnIter(sal_Int32 nColumn) const381 inline Int32Set_Impl::const_iterator SwAccessibleTableData_Impl::GetColumnIter(
382 sal_Int32 nColumn ) const
383 {
384 Int32Set_Impl::const_iterator aCol = GetColumns().begin();
385 if( nColumn > 0 )
386 {
387 std::advance( aCol,
388 static_cast< Int32Set_Impl::difference_type >( nColumn ) );
389 }
390 return aCol;
391 }
392
CheckRowAndCol(sal_Int32 nRow,sal_Int32 nCol,SwAccessibleTable * pThis) const393 void SwAccessibleTableData_Impl::CheckRowAndCol(
394 sal_Int32 nRow, sal_Int32 nCol, SwAccessibleTable *pThis ) const
395 {
396 if( ( nRow < 0 || nRow >= static_cast< sal_Int32 >( maRows.size() ) ) ||
397 ( nCol < 0 || nCol >= static_cast< sal_Int32 >( maColumns.size() ) ) )
398 {
399 uno::Reference < XAccessibleTable > xThis( pThis );
400 lang::IndexOutOfBoundsException aExcept(
401 "row or column index out of range",
402 xThis );
403 throw aExcept;
404 }
405 }
406
407 class SwAccSingleTableSelHander_Impl : public SwAccTableSelHander_Impl
408 {
409 bool m_bSelected;
410
411 public:
412
413 inline SwAccSingleTableSelHander_Impl();
414
~SwAccSingleTableSelHander_Impl()415 virtual ~SwAccSingleTableSelHander_Impl() {}
416
IsSelected() const417 bool IsSelected() const { return m_bSelected; }
418
419 virtual void Unselect( sal_Int32, sal_Int32 ) override;
420 };
421
SwAccSingleTableSelHander_Impl()422 inline SwAccSingleTableSelHander_Impl::SwAccSingleTableSelHander_Impl() :
423 m_bSelected( true )
424 {
425 }
426
Unselect(sal_Int32,sal_Int32)427 void SwAccSingleTableSelHander_Impl::Unselect( sal_Int32, sal_Int32 )
428 {
429 m_bSelected = false;
430 }
431
432 class SwAccAllTableSelHander_Impl : public SwAccTableSelHander_Impl
433
434 {
435 std::vector< bool > m_aSelected;
436 sal_Int32 m_nCount;
437
438 public:
SwAccAllTableSelHander_Impl(sal_Int32 nSize)439 explicit SwAccAllTableSelHander_Impl(sal_Int32 nSize)
440 : m_aSelected(nSize, true)
441 , m_nCount(nSize)
442 {
443 }
444
445 uno::Sequence < sal_Int32 > GetSelSequence();
446
447 virtual void Unselect( sal_Int32 nRowOrCol, sal_Int32 nExt ) override;
448 virtual ~SwAccAllTableSelHander_Impl();
449 };
450
~SwAccAllTableSelHander_Impl()451 SwAccAllTableSelHander_Impl::~SwAccAllTableSelHander_Impl()
452 {
453 }
454
GetSelSequence()455 uno::Sequence < sal_Int32 > SwAccAllTableSelHander_Impl::GetSelSequence()
456 {
457 OSL_ENSURE( m_nCount >= 0, "underflow" );
458 uno::Sequence < sal_Int32 > aRet( m_nCount );
459 sal_Int32 *pRet = aRet.getArray();
460 sal_Int32 nPos = 0;
461 size_t nSize = m_aSelected.size();
462 for( size_t i=0; i < nSize && nPos < m_nCount; i++ )
463 {
464 if( m_aSelected[i] )
465 {
466 *pRet++ = i;
467 nPos++;
468 }
469 }
470
471 OSL_ENSURE( nPos == m_nCount, "count is wrong" );
472
473 return aRet;
474 }
475
Unselect(sal_Int32 nRowOrCol,sal_Int32 nExt)476 void SwAccAllTableSelHander_Impl::Unselect( sal_Int32 nRowOrCol,
477 sal_Int32 nExt )
478 {
479 OSL_ENSURE( static_cast< size_t >( nRowOrCol ) < m_aSelected.size(),
480 "index too large" );
481 OSL_ENSURE( static_cast< size_t >( nRowOrCol+nExt ) <= m_aSelected.size(),
482 "extent too large" );
483 while( nExt )
484 {
485 if( m_aSelected[static_cast< size_t >( nRowOrCol )] )
486 {
487 m_aSelected[static_cast< size_t >( nRowOrCol )] = false;
488 m_nCount--;
489 }
490 nExt--;
491 nRowOrCol++;
492 }
493 }
494
GetSelBoxes() const495 const SwSelBoxes *SwAccessibleTable::GetSelBoxes() const
496 {
497 const SwSelBoxes *pSelBoxes = nullptr;
498 const SwCursorShell *pCSh = GetCursorShell();
499 if( (pCSh != nullptr) && pCSh->IsTableMode() )
500 {
501 pSelBoxes = &pCSh->GetTableCursor()->GetSelectedBoxes();
502 }
503
504 return pSelBoxes;
505 }
506
FireTableChangeEvent(const SwAccessibleTableData_Impl & rTableData)507 void SwAccessibleTable::FireTableChangeEvent(
508 const SwAccessibleTableData_Impl& rTableData )
509 {
510 AccessibleTableModelChange aModelChange;
511 aModelChange.Type = AccessibleTableModelChangeType::UPDATE;
512 aModelChange.FirstRow = 0;
513 aModelChange.LastRow = rTableData.GetRowCount() - 1;
514 aModelChange.FirstColumn = 0;
515 aModelChange.LastColumn = rTableData.GetColumnCount() - 1;
516
517 AccessibleEventObject aEvent;
518 aEvent.EventId = AccessibleEventId::TABLE_MODEL_CHANGED;
519 aEvent.NewValue <<= aModelChange;
520
521 FireAccessibleEvent( aEvent );
522 }
523
GetTableBox(sal_Int32 nChildIndex) const524 const SwTableBox* SwAccessibleTable::GetTableBox( sal_Int32 nChildIndex ) const
525 {
526 OSL_ENSURE( nChildIndex >= 0, "Illegal child index." );
527 OSL_ENSURE( nChildIndex < const_cast<SwAccessibleTable*>(this)->getAccessibleChildCount(), "Illegal child index." ); // #i77106#
528
529 const SwTableBox* pBox = nullptr;
530
531 // get table box for 'our' table cell
532 SwAccessibleChild aCell( GetChild( *const_cast<SwAccessibleMap*>(GetMap()), nChildIndex ) );
533 if( aCell.GetSwFrame() )
534 {
535 const SwFrame* pChildFrame = aCell.GetSwFrame();
536 if( (pChildFrame != nullptr) && pChildFrame->IsCellFrame() )
537 {
538 const SwCellFrame* pCellFrame =
539 static_cast<const SwCellFrame*>( pChildFrame );
540 pBox = pCellFrame->GetTabBox();
541 }
542 }
543
544 OSL_ENSURE( pBox != nullptr, "We need the table box." );
545 return pBox;
546 }
547
IsChildSelected(sal_Int32 nChildIndex) const548 bool SwAccessibleTable::IsChildSelected( sal_Int32 nChildIndex ) const
549 {
550 bool bRet = false;
551 const SwSelBoxes* pSelBoxes = GetSelBoxes();
552 if( pSelBoxes )
553 {
554 const SwTableBox* pBox = GetTableBox( nChildIndex );
555 OSL_ENSURE( pBox != nullptr, "We need the table box." );
556 bRet = pSelBoxes->find( const_cast<SwTableBox*>( pBox ) ) != pSelBoxes->end();
557 }
558
559 return bRet;
560 }
561
GetIndexOfSelectedChild(sal_Int32 nSelectedChildIndex) const562 sal_Int32 SwAccessibleTable::GetIndexOfSelectedChild(
563 sal_Int32 nSelectedChildIndex ) const
564 {
565 // iterate over all children to n-th isAccessibleChildSelected()
566 sal_Int32 nChildren = const_cast<SwAccessibleTable*>(this)->getAccessibleChildCount(); // #i77106#
567 if( nSelectedChildIndex >= nChildren )
568 return -1;
569
570 sal_Int32 n = 0;
571 while( n < nChildren )
572 {
573 if( IsChildSelected( n ) )
574 {
575 if( 0 == nSelectedChildIndex )
576 break;
577 else
578 --nSelectedChildIndex;
579 }
580 ++n;
581 }
582
583 return n < nChildren ? n : -1;
584 }
585
GetStates(::utl::AccessibleStateSetHelper & rStateSet)586 void SwAccessibleTable::GetStates(
587 ::utl::AccessibleStateSetHelper& rStateSet )
588 {
589 SwAccessibleContext::GetStates( rStateSet );
590 //Add resizable state to table
591 rStateSet.AddState( AccessibleStateType::RESIZABLE );
592 // MULTISELECTABLE
593 rStateSet.AddState( AccessibleStateType::MULTI_SELECTABLE );
594 SwCursorShell* pCursorShell = GetCursorShell();
595 if( pCursorShell )
596 rStateSet.AddState( AccessibleStateType::MULTI_SELECTABLE );
597 }
598
SwAccessibleTable(std::shared_ptr<SwAccessibleMap> const & pInitMap,const SwTabFrame * pTabFrame)599 SwAccessibleTable::SwAccessibleTable(
600 std::shared_ptr<SwAccessibleMap> const& pInitMap,
601 const SwTabFrame* pTabFrame ) :
602 SwAccessibleContext( pInitMap, AccessibleRole::TABLE, pTabFrame )
603 {
604 const SwFrameFormat* pFrameFormat = pTabFrame->GetFormat();
605 if(pFrameFormat)
606 StartListening(const_cast<SwFrameFormat*>(pFrameFormat)->GetNotifier());
607
608 SetName( pFrameFormat->GetName() + "-" + OUString::number( pTabFrame->GetPhyPageNum() ) );
609
610 const OUString sArg1( static_cast< const SwTabFrame * >( GetFrame() )->GetFormat()->GetName() );
611 const OUString sArg2( GetFormattedPageNumber() );
612
613 m_sDesc = GetResource( STR_ACCESS_TABLE_DESC, &sArg1, &sArg2 );
614 UpdateTableData();
615 }
616
~SwAccessibleTable()617 SwAccessibleTable::~SwAccessibleTable()
618 {
619 SolarMutexGuard aGuard;
620
621 mpTableData.reset();
622 }
623
Notify(const SfxHint & rHint)624 void SwAccessibleTable::Notify(const SfxHint& rHint)
625 {
626 if(rHint.GetId() == SfxHintId::Dying)
627 {
628 EndListeningAll();
629 }
630 else if(auto pLegacyHint = dynamic_cast<const sw::LegacyModifyHint*>(&rHint))
631 {
632 sal_uInt16 nWhich = pLegacyHint->m_pOld ? pLegacyHint->m_pOld->Which() : pLegacyHint->m_pNew ? pLegacyHint->m_pNew->Which() : 0;
633 const SwTabFrame* pTabFrame = static_cast<const SwTabFrame*>(GetFrame());
634 if(nWhich == RES_NAME_CHANGED && pTabFrame)
635 {
636 const SwFrameFormat *pFrameFormat = pTabFrame->GetFormat();
637
638 const OUString sOldName( GetName() );
639 const OUString sNewTabName = pFrameFormat->GetName();
640
641 SetName( sNewTabName + "-" + OUString::number( pTabFrame->GetPhyPageNum() ) );
642
643 if( sOldName != GetName() )
644 {
645 AccessibleEventObject aEvent;
646 aEvent.EventId = AccessibleEventId::NAME_CHANGED;
647 aEvent.OldValue <<= sOldName;
648 aEvent.NewValue <<= GetName();
649 FireAccessibleEvent( aEvent );
650 }
651
652 const OUString sOldDesc( m_sDesc );
653 const OUString sArg2( GetFormattedPageNumber() );
654
655 m_sDesc = GetResource( STR_ACCESS_TABLE_DESC, &sNewTabName, &sArg2 );
656 if( m_sDesc != sOldDesc )
657 {
658 AccessibleEventObject aEvent;
659 aEvent.EventId = AccessibleEventId::DESCRIPTION_CHANGED;
660 aEvent.OldValue <<= sOldDesc;
661 aEvent.NewValue <<= m_sDesc;
662 FireAccessibleEvent( aEvent );
663 }
664 }
665 }
666 }
667
queryInterface(const uno::Type & rType)668 uno::Any SwAccessibleTable::queryInterface( const uno::Type& rType )
669 {
670 uno::Any aRet;
671 if ( rType == cppu::UnoType<XAccessibleTable>::get() )
672 {
673 uno::Reference<XAccessibleTable> xThis( this );
674 aRet <<= xThis;
675 }
676 else if ( rType == cppu::UnoType<XAccessibleSelection>::get() )
677 {
678 uno::Reference<XAccessibleSelection> xSelection( this );
679 aRet <<= xSelection;
680 }
681 else if ( rType == cppu::UnoType<XAccessibleTableSelection>::get() )
682 {
683 uno::Reference<XAccessibleTableSelection> xTableExtent( this );
684 aRet <<= xTableExtent;
685 }
686 else
687 {
688 aRet = SwAccessibleContext::queryInterface(rType);
689 }
690
691 return aRet;
692 }
693
694 // XTypeProvider
getTypes()695 uno::Sequence< uno::Type > SAL_CALL SwAccessibleTable::getTypes()
696 {
697 return cppu::OTypeCollection(
698 cppu::UnoType<XAccessibleSelection>::get(),
699 cppu::UnoType<XAccessibleTable>::get(),
700 SwAccessibleContext::getTypes() ).getTypes();
701 }
702
getImplementationId()703 uno::Sequence< sal_Int8 > SAL_CALL SwAccessibleTable::getImplementationId()
704 {
705 return css::uno::Sequence<sal_Int8>();
706 }
707
708 // #i77106#
CreateNewTableData()709 std::unique_ptr<SwAccessibleTableData_Impl> SwAccessibleTable::CreateNewTableData()
710 {
711 const SwTabFrame* pTabFrame = static_cast<const SwTabFrame*>( GetFrame() );
712 return std::unique_ptr<SwAccessibleTableData_Impl>(new SwAccessibleTableData_Impl( *GetMap(), pTabFrame, IsInPagePreview() ));
713 }
714
UpdateTableData()715 void SwAccessibleTable::UpdateTableData()
716 {
717 // #i77106# - usage of new method <CreateNewTableData()>
718 mpTableData = CreateNewTableData();
719 }
720
ClearTableData()721 void SwAccessibleTable::ClearTableData()
722 {
723 mpTableData.reset();
724 }
725
getAccessibleDescription()726 OUString SAL_CALL SwAccessibleTable::getAccessibleDescription()
727 {
728 SolarMutexGuard aGuard;
729
730 ThrowIfDisposed();
731
732 return m_sDesc;
733 }
734
getAccessibleRowCount()735 sal_Int32 SAL_CALL SwAccessibleTable::getAccessibleRowCount()
736 {
737 SolarMutexGuard aGuard;
738
739 ThrowIfDisposed();
740
741 return GetTableData().GetRowCount();
742 }
743
getAccessibleColumnCount()744 sal_Int32 SAL_CALL SwAccessibleTable::getAccessibleColumnCount( )
745 {
746 SolarMutexGuard aGuard;
747
748 ThrowIfDisposed();
749
750 return GetTableData().GetColumnCount();
751 }
752
getAccessibleRowDescription(sal_Int32 nRow)753 OUString SAL_CALL SwAccessibleTable::getAccessibleRowDescription(
754 sal_Int32 nRow )
755 {
756 // #i87532# - determine table cell in <nRow>th row and
757 // in first column of row header table and return its text content.
758 OUString sRowDesc;
759
760 GetTableData().CheckRowAndCol(nRow, 0, this);
761
762 uno::Reference< XAccessibleTable > xTableRowHeader = getAccessibleRowHeaders();
763 if ( xTableRowHeader.is() )
764 {
765 uno::Reference< XAccessible > xRowHeaderCell =
766 xTableRowHeader->getAccessibleCellAt( nRow, 0 );
767 OSL_ENSURE( xRowHeaderCell.is(),
768 "<SwAccessibleTable::getAccessibleRowDescription(..)> - missing row header cell -> serious issue." );
769 uno::Reference< XAccessibleContext > xRowHeaderCellContext =
770 xRowHeaderCell->getAccessibleContext();
771 const sal_Int32 nCellChildCount( xRowHeaderCellContext->getAccessibleChildCount() );
772 for ( sal_Int32 nChildIndex = 0; nChildIndex < nCellChildCount; ++nChildIndex )
773 {
774 uno::Reference< XAccessible > xChild = xRowHeaderCellContext->getAccessibleChild( nChildIndex );
775 uno::Reference< XAccessibleText > xChildText( xChild, uno::UNO_QUERY );
776 if ( xChildText.is() )
777 {
778 sRowDesc += xChildText->getText();
779 }
780 }
781 }
782
783 return sRowDesc;
784 }
785
getAccessibleColumnDescription(sal_Int32 nColumn)786 OUString SAL_CALL SwAccessibleTable::getAccessibleColumnDescription(
787 sal_Int32 nColumn )
788 {
789 // #i87532# - determine table cell in first row and
790 // in <nColumn>th column of column header table and return its text content.
791 OUString sColumnDesc;
792
793 GetTableData().CheckRowAndCol(0, nColumn, this);
794
795 uno::Reference< XAccessibleTable > xTableColumnHeader = getAccessibleColumnHeaders();
796 if ( xTableColumnHeader.is() )
797 {
798 uno::Reference< XAccessible > xColumnHeaderCell =
799 xTableColumnHeader->getAccessibleCellAt( 0, nColumn );
800 OSL_ENSURE( xColumnHeaderCell.is(),
801 "<SwAccessibleTable::getAccessibleColumnDescription(..)> - missing column header cell -> serious issue." );
802 uno::Reference< XAccessibleContext > xColumnHeaderCellContext =
803 xColumnHeaderCell->getAccessibleContext();
804 const sal_Int32 nCellChildCount( xColumnHeaderCellContext->getAccessibleChildCount() );
805 for ( sal_Int32 nChildIndex = 0; nChildIndex < nCellChildCount; ++nChildIndex )
806 {
807 uno::Reference< XAccessible > xChild = xColumnHeaderCellContext->getAccessibleChild( nChildIndex );
808 uno::Reference< XAccessibleText > xChildText( xChild, uno::UNO_QUERY );
809 if ( xChildText.is() )
810 {
811 sColumnDesc += xChildText->getText();
812 }
813 }
814 }
815
816 return sColumnDesc;
817 }
818
getAccessibleRowExtentAt(sal_Int32 nRow,sal_Int32 nColumn)819 sal_Int32 SAL_CALL SwAccessibleTable::getAccessibleRowExtentAt(
820 sal_Int32 nRow, sal_Int32 nColumn )
821 {
822 sal_Int32 nExtend = -1;
823
824 SolarMutexGuard aGuard;
825
826 ThrowIfDisposed();
827
828 UpdateTableData();
829 GetTableData().CheckRowAndCol( nRow, nColumn, this );
830
831 Int32Set_Impl::const_iterator aSttCol(
832 GetTableData().GetColumnIter( nColumn ) );
833 Int32Set_Impl::const_iterator aSttRow(
834 GetTableData().GetRowIter( nRow ) );
835 const SwFrame *pCellFrame = GetTableData().GetCellAtPos( *aSttCol, *aSttRow );
836 if( pCellFrame )
837 {
838 sal_Int32 nBottom = pCellFrame->getFrameArea().Bottom();
839 nBottom -= GetFrame()->getFrameArea().Top();
840 Int32Set_Impl::const_iterator aEndRow(
841 GetTableData().GetRows().upper_bound( nBottom ) );
842 nExtend =
843 static_cast< sal_Int32 >( std::distance( aSttRow, aEndRow ) );
844 }
845
846 return nExtend;
847 }
848
getAccessibleColumnExtentAt(sal_Int32 nRow,sal_Int32 nColumn)849 sal_Int32 SAL_CALL SwAccessibleTable::getAccessibleColumnExtentAt(
850 sal_Int32 nRow, sal_Int32 nColumn )
851 {
852 sal_Int32 nExtend = -1;
853
854 SolarMutexGuard aGuard;
855
856 ThrowIfDisposed();
857 UpdateTableData();
858
859 GetTableData().CheckRowAndCol( nRow, nColumn, this );
860
861 Int32Set_Impl::const_iterator aSttCol(
862 GetTableData().GetColumnIter( nColumn ) );
863 Int32Set_Impl::const_iterator aSttRow(
864 GetTableData().GetRowIter( nRow ) );
865 const SwFrame *pCellFrame = GetTableData().GetCellAtPos( *aSttCol, *aSttRow );
866 if( pCellFrame )
867 {
868 sal_Int32 nRight = pCellFrame->getFrameArea().Right();
869 nRight -= GetFrame()->getFrameArea().Left();
870 Int32Set_Impl::const_iterator aEndCol(
871 GetTableData().GetColumns().upper_bound( nRight ) );
872 nExtend =
873 static_cast< sal_Int32 >( std::distance( aSttCol, aEndCol ) );
874 }
875
876 return nExtend;
877 }
878
879 uno::Reference< XAccessibleTable > SAL_CALL
getAccessibleRowHeaders()880 SwAccessibleTable::getAccessibleRowHeaders( )
881 {
882 // Row headers aren't supported
883 return uno::Reference< XAccessibleTable >();
884 }
885
886 uno::Reference< XAccessibleTable > SAL_CALL
getAccessibleColumnHeaders()887 SwAccessibleTable::getAccessibleColumnHeaders( )
888 {
889 SolarMutexGuard aGuard;
890
891 // #i87532# - assure that return accessible object is empty,
892 // if no column header exists.
893 SwAccessibleTableColHeaders* pTableColHeaders =
894 new SwAccessibleTableColHeaders(GetMap()->shared_from_this(),
895 static_cast<const SwTabFrame *>(GetFrame()));
896 uno::Reference< XAccessibleTable > xTableColumnHeaders( pTableColHeaders );
897 if ( pTableColHeaders->getAccessibleChildCount() <= 0 )
898 {
899 return uno::Reference< XAccessibleTable >();
900 }
901
902 return xTableColumnHeaders;
903 }
904
getSelectedAccessibleRows()905 uno::Sequence< sal_Int32 > SAL_CALL SwAccessibleTable::getSelectedAccessibleRows()
906 {
907 SolarMutexGuard aGuard;
908
909 ThrowIfDisposed();
910
911 const SwSelBoxes *pSelBoxes = GetSelBoxes();
912 if( pSelBoxes )
913 {
914 sal_Int32 nRows = GetTableData().GetRowCount();
915 SwAccAllTableSelHander_Impl aSelRows( nRows );
916
917 GetTableData().GetSelection( 0, nRows, *pSelBoxes, aSelRows,
918 false );
919
920 return aSelRows.GetSelSequence();
921 }
922 else
923 {
924 return uno::Sequence< sal_Int32 >( 0 );
925 }
926 }
927
getSelectedAccessibleColumns()928 uno::Sequence< sal_Int32 > SAL_CALL SwAccessibleTable::getSelectedAccessibleColumns()
929 {
930 SolarMutexGuard aGuard;
931
932 ThrowIfDisposed();
933
934 const SwSelBoxes *pSelBoxes = GetSelBoxes();
935 if( pSelBoxes )
936 {
937 sal_Int32 nCols = GetTableData().GetColumnCount();
938 SwAccAllTableSelHander_Impl aSelCols( nCols );
939
940 GetTableData().GetSelection( 0, nCols, *pSelBoxes, aSelCols, true );
941
942 return aSelCols.GetSelSequence();
943 }
944 else
945 {
946 return uno::Sequence< sal_Int32 >( 0 );
947 }
948 }
949
isAccessibleRowSelected(sal_Int32 nRow)950 sal_Bool SAL_CALL SwAccessibleTable::isAccessibleRowSelected( sal_Int32 nRow )
951 {
952 SolarMutexGuard aGuard;
953
954 ThrowIfDisposed();
955
956 GetTableData().CheckRowAndCol( nRow, 0, this );
957
958 bool bRet;
959 const SwSelBoxes *pSelBoxes = GetSelBoxes();
960 if( pSelBoxes )
961 {
962 SwAccSingleTableSelHander_Impl aSelRow;
963 GetTableData().GetSelection( nRow, nRow+1, *pSelBoxes, aSelRow,
964 false );
965 bRet = aSelRow.IsSelected();
966 }
967 else
968 {
969 bRet = false;
970 }
971
972 return bRet;
973 }
974
isAccessibleColumnSelected(sal_Int32 nColumn)975 sal_Bool SAL_CALL SwAccessibleTable::isAccessibleColumnSelected(
976 sal_Int32 nColumn )
977 {
978 SolarMutexGuard aGuard;
979
980 ThrowIfDisposed();
981
982 GetTableData().CheckRowAndCol( 0, nColumn, this );
983
984 bool bRet;
985 const SwSelBoxes *pSelBoxes = GetSelBoxes();
986 if( pSelBoxes )
987 {
988 SwAccSingleTableSelHander_Impl aSelCol;
989
990 GetTableData().GetSelection( nColumn, nColumn+1, *pSelBoxes, aSelCol,
991 true );
992 bRet = aSelCol.IsSelected();
993 }
994 else
995 {
996 bRet = false;
997 }
998
999 return bRet;
1000 }
1001
getAccessibleCellAt(sal_Int32 nRow,sal_Int32 nColumn)1002 uno::Reference< XAccessible > SAL_CALL SwAccessibleTable::getAccessibleCellAt(
1003 sal_Int32 nRow, sal_Int32 nColumn )
1004 {
1005 uno::Reference< XAccessible > xRet;
1006
1007 SolarMutexGuard aGuard;
1008
1009 ThrowIfDisposed();
1010
1011 const SwFrame *pCellFrame =
1012 GetTableData().GetCell( nRow, nColumn, this );
1013 if( pCellFrame )
1014 xRet = GetMap()->GetContext( pCellFrame );
1015
1016 return xRet;
1017 }
1018
getAccessibleCaption()1019 uno::Reference< XAccessible > SAL_CALL SwAccessibleTable::getAccessibleCaption()
1020 {
1021 // captions aren't supported
1022 return uno::Reference< XAccessible >();
1023 }
1024
getAccessibleSummary()1025 uno::Reference< XAccessible > SAL_CALL SwAccessibleTable::getAccessibleSummary()
1026 {
1027 // summaries aren't supported
1028 return uno::Reference< XAccessible >();
1029 }
1030
isAccessibleSelected(sal_Int32 nRow,sal_Int32 nColumn)1031 sal_Bool SAL_CALL SwAccessibleTable::isAccessibleSelected(
1032 sal_Int32 nRow, sal_Int32 nColumn )
1033 {
1034 bool bRet = false;
1035
1036 SolarMutexGuard aGuard;
1037
1038 ThrowIfDisposed();
1039
1040 const SwFrame *pFrame =
1041 GetTableData().GetCell( nRow, nColumn, this );
1042 if( pFrame && pFrame->IsCellFrame() )
1043 {
1044 const SwSelBoxes *pSelBoxes = GetSelBoxes();
1045 if( pSelBoxes )
1046 {
1047 const SwCellFrame *pCFrame = static_cast < const SwCellFrame * >( pFrame );
1048 SwTableBox *pBox =
1049 const_cast< SwTableBox *>( pCFrame->GetTabBox() );
1050 bRet = pSelBoxes->find( pBox ) != pSelBoxes->end();
1051 }
1052 }
1053
1054 return bRet;
1055 }
1056
getAccessibleIndex(sal_Int32 nRow,sal_Int32 nColumn)1057 sal_Int32 SAL_CALL SwAccessibleTable::getAccessibleIndex(
1058 sal_Int32 nRow, sal_Int32 nColumn )
1059 {
1060 sal_Int32 nRet = -1;
1061
1062 SolarMutexGuard aGuard;
1063
1064 ThrowIfDisposed();
1065
1066 SwAccessibleChild aCell( GetTableData().GetCell( nRow, nColumn, this ));
1067 if ( aCell.IsValid() )
1068 {
1069 nRet = GetChildIndex( *(GetMap()), aCell );
1070 }
1071
1072 return nRet;
1073 }
1074
getAccessibleRow(sal_Int32 nChildIndex)1075 sal_Int32 SAL_CALL SwAccessibleTable::getAccessibleRow( sal_Int32 nChildIndex )
1076 {
1077 sal_Int32 nRet = -1;
1078
1079 SolarMutexGuard aGuard;
1080
1081 ThrowIfDisposed();
1082
1083 // #i77106#
1084 if ( ( nChildIndex < 0 ) ||
1085 ( nChildIndex >= getAccessibleChildCount() ) )
1086 {
1087 throw lang::IndexOutOfBoundsException();
1088 }
1089
1090 SwAccessibleChild aCell( GetChild( *(GetMap()), nChildIndex ) );
1091 if ( aCell.GetSwFrame() )
1092 {
1093 sal_Int32 nTop = aCell.GetSwFrame()->getFrameArea().Top();
1094 nTop -= GetFrame()->getFrameArea().Top();
1095 Int32Set_Impl::const_iterator aRow(
1096 GetTableData().GetRows().lower_bound( nTop ) );
1097 nRet = static_cast< sal_Int32 >( std::distance(
1098 GetTableData().GetRows().begin(), aRow ) );
1099 }
1100 else
1101 {
1102 OSL_ENSURE( !aCell.IsValid(), "SwAccessibleTable::getAccessibleColumn:"
1103 "aCell not expected to be valid.");
1104
1105 throw lang::IndexOutOfBoundsException();
1106 }
1107
1108 return nRet;
1109 }
1110
getAccessibleColumn(sal_Int32 nChildIndex)1111 sal_Int32 SAL_CALL SwAccessibleTable::getAccessibleColumn(
1112 sal_Int32 nChildIndex )
1113 {
1114 sal_Int32 nRet = -1;
1115
1116 SolarMutexGuard aGuard;
1117
1118 ThrowIfDisposed();
1119
1120 // #i77106#
1121 if ( ( nChildIndex < 0 ) ||
1122 ( nChildIndex >= getAccessibleChildCount() ) )
1123 {
1124 throw lang::IndexOutOfBoundsException();
1125 }
1126
1127 SwAccessibleChild aCell( GetChild( *(GetMap()), nChildIndex ) );
1128 if ( aCell.GetSwFrame() )
1129 {
1130 sal_Int32 nLeft = aCell.GetSwFrame()->getFrameArea().Left();
1131 nLeft -= GetFrame()->getFrameArea().Left();
1132 Int32Set_Impl::const_iterator aCol(
1133 GetTableData().GetColumns().lower_bound( nLeft ) );
1134 nRet = static_cast< sal_Int32 >( std::distance(
1135 GetTableData().GetColumns().begin(), aCol ) );
1136 }
1137 else
1138 {
1139 OSL_ENSURE( !aCell.IsValid(), "SwAccessibleTable::getAccessibleColumn:"
1140 "aCell not expected to be valid.");
1141
1142 throw lang::IndexOutOfBoundsException();
1143 }
1144
1145 return nRet;
1146 }
1147
getImplementationName()1148 OUString SAL_CALL SwAccessibleTable::getImplementationName()
1149 {
1150 return "com.sun.star.comp.Writer.SwAccessibleTableView";
1151 }
1152
supportsService(const OUString & sTestServiceName)1153 sal_Bool SAL_CALL SwAccessibleTable::supportsService(
1154 const OUString& sTestServiceName)
1155 {
1156 return cppu::supportsService(this, sTestServiceName);
1157 }
1158
getSupportedServiceNames()1159 uno::Sequence< OUString > SAL_CALL SwAccessibleTable::getSupportedServiceNames()
1160 {
1161 return { "com.sun.star.table.AccessibleTableView", sAccessibleServiceName };
1162 }
1163
InvalidatePosOrSize(const SwRect & rOldBox)1164 void SwAccessibleTable::InvalidatePosOrSize( const SwRect& rOldBox )
1165 {
1166 SolarMutexGuard aGuard;
1167
1168 //need to update children
1169 std::unique_ptr<SwAccessibleTableData_Impl> pNewTableData = CreateNewTableData();
1170 if( !pNewTableData->CompareExtents( GetTableData() ) )
1171 {
1172 mpTableData = std::move(pNewTableData);
1173 FireTableChangeEvent(*mpTableData);
1174 }
1175 if( HasTableData() )
1176 GetTableData().SetTablePos( GetFrame()->getFrameArea().Pos() );
1177
1178 SwAccessibleContext::InvalidatePosOrSize( rOldBox );
1179 }
1180
Dispose(bool bRecursive,bool bCanSkipInvisible)1181 void SwAccessibleTable::Dispose(bool bRecursive, bool bCanSkipInvisible)
1182 {
1183 SolarMutexGuard aGuard;
1184 EndListeningAll();
1185 SwAccessibleContext::Dispose(bRecursive, bCanSkipInvisible);
1186 }
1187
DisposeChild(const SwAccessibleChild & rChildFrameOrObj,bool bRecursive,bool bCanSkipInvisible)1188 void SwAccessibleTable::DisposeChild( const SwAccessibleChild& rChildFrameOrObj,
1189 bool bRecursive, bool bCanSkipInvisible )
1190 {
1191 SolarMutexGuard aGuard;
1192
1193 const SwFrame *pFrame = rChildFrameOrObj.GetSwFrame();
1194 OSL_ENSURE( pFrame, "frame expected" );
1195 if( HasTableData() )
1196 {
1197 FireTableChangeEvent( GetTableData() );
1198 ClearTableData();
1199 }
1200
1201 // There are two reason why this method has been called. The first one
1202 // is there is no context for pFrame. The method is then called by
1203 // the map, and we have to call our superclass.
1204 // The other situation is that we have been call by a call to get notified
1205 // about its change. We then must not call the superclass
1206 uno::Reference< XAccessible > xAcc( GetMap()->GetContext( pFrame, false ) );
1207 if( !xAcc.is() )
1208 SwAccessibleContext::DisposeChild( rChildFrameOrObj, bRecursive, bCanSkipInvisible );
1209 }
1210
InvalidateChildPosOrSize(const SwAccessibleChild & rChildFrameOrObj,const SwRect & rOldBox)1211 void SwAccessibleTable::InvalidateChildPosOrSize( const SwAccessibleChild& rChildFrameOrObj,
1212 const SwRect& rOldBox )
1213 {
1214 SolarMutexGuard aGuard;
1215
1216 if( HasTableData() )
1217 {
1218 SAL_WARN_IF( HasTableData() &&
1219 GetFrame()->getFrameArea().Pos() != GetTableData().GetTablePos(),
1220 "sw.a11y", "table has invalid position" );
1221 if( HasTableData() )
1222 {
1223 std::unique_ptr<SwAccessibleTableData_Impl> pNewTableData = CreateNewTableData(); // #i77106#
1224 if( !pNewTableData->CompareExtents( GetTableData() ) )
1225 {
1226 if (pNewTableData->GetRowCount() != mpTableData->GetRowCount()
1227 && 1 < GetTableData().GetRowCount())
1228 {
1229 Int32Set_Impl::const_iterator aSttCol( GetTableData().GetColumnIter( 0 ) );
1230 Int32Set_Impl::const_iterator aSttRow( GetTableData().GetRowIter( 1 ) );
1231 const SwFrame *pCellFrame = GetTableData().GetCellAtPos( *aSttCol, *aSttRow );
1232 Int32Set_Impl::const_iterator aSttCol2( pNewTableData->GetColumnIter( 0 ) );
1233 Int32Set_Impl::const_iterator aSttRow2( pNewTableData->GetRowIter( 0 ) );
1234 const SwFrame *pCellFrame2 = pNewTableData->GetCellAtPos( *aSttCol2, *aSttRow2 );
1235
1236 if(pCellFrame == pCellFrame2)
1237 {
1238 AccessibleTableModelChange aModelChange;
1239 aModelChange.Type = AccessibleTableModelChangeType::UPDATE;
1240 aModelChange.FirstRow = 0;
1241 aModelChange.LastRow = mpTableData->GetRowCount() - 1;
1242 aModelChange.FirstColumn = 0;
1243 aModelChange.LastColumn = mpTableData->GetColumnCount() - 1;
1244
1245 AccessibleEventObject aEvent;
1246 aEvent.EventId = AccessibleEventId::TABLE_COLUMN_HEADER_CHANGED;
1247 aEvent.NewValue <<= aModelChange;
1248
1249 FireAccessibleEvent( aEvent );
1250 }
1251 }
1252 else
1253 FireTableChangeEvent( GetTableData() );
1254 ClearTableData();
1255 mpTableData = std::move(pNewTableData);
1256 }
1257 }
1258 }
1259
1260 // #i013961# - always call super class method
1261 SwAccessibleContext::InvalidateChildPosOrSize( rChildFrameOrObj, rOldBox );
1262 }
1263
1264 // XAccessibleSelection
1265
selectAccessibleChild(sal_Int32 nChildIndex)1266 void SAL_CALL SwAccessibleTable::selectAccessibleChild(
1267 sal_Int32 nChildIndex )
1268 {
1269 SolarMutexGuard aGuard;
1270
1271 ThrowIfDisposed();
1272
1273 if( (nChildIndex < 0) || (nChildIndex >= getAccessibleChildCount()) ) // #i77106#
1274 throw lang::IndexOutOfBoundsException();
1275
1276 // preliminaries: get 'our' table box, and get the cursor shell
1277 const SwTableBox* pBox = GetTableBox( nChildIndex );
1278 OSL_ENSURE( pBox != nullptr, "We need the table box." );
1279
1280 SwCursorShell* pCursorShell = GetCursorShell();
1281 if( pCursorShell == nullptr )
1282 return;
1283
1284 // assure, that child, identified by the given index, isn't already selected.
1285 if ( IsChildSelected( nChildIndex ) )
1286 {
1287 return;
1288 }
1289
1290 // now we can start to do the work: check whether we already have
1291 // a table selection (in 'our' table). If so, extend the
1292 // selection, else select the current cell.
1293
1294 // if we have a selection in a table, check if it's in the
1295 // same table that we're trying to select in
1296 const SwTableNode* pSelectedTable = pCursorShell->IsCursorInTable();
1297 if( pSelectedTable != nullptr )
1298 {
1299 // get top-most table line
1300 const SwTableLine* pUpper = pBox->GetUpper();
1301 while( pUpper->GetUpper() != nullptr )
1302 pUpper = pUpper->GetUpper()->GetUpper();
1303 sal_uInt16 nPos =
1304 pSelectedTable->GetTable().GetTabLines().GetPos( pUpper );
1305 if( nPos == USHRT_MAX )
1306 pSelectedTable = nullptr;
1307 }
1308
1309 // create the new selection
1310 const SwStartNode* pStartNode = pBox->GetSttNd();
1311 if( pSelectedTable == nullptr || !pCursorShell->GetTableCrs() )
1312 {
1313 pCursorShell->StartAction();
1314 // Set cursor into current cell. This deletes any table cursor.
1315 SwPaM aPaM( *pStartNode );
1316 aPaM.Move( fnMoveForward, GoInNode );
1317 Select( aPaM );
1318 // Move cursor to the end of the table creating a selection and a table
1319 // cursor.
1320 pCursorShell->SetMark();
1321 pCursorShell->MoveTable( GotoCurrTable, fnTableEnd );
1322 // now set the cursor into the cell again.
1323 SwPaM *pPaM = pCursorShell->GetTableCrs() ? pCursorShell->GetTableCrs()
1324 : pCursorShell->GetCursor();
1325 *pPaM->GetPoint() = *pPaM->GetMark();
1326 pCursorShell->EndAction();
1327 // we now have one cell selected!
1328 }
1329 else
1330 {
1331 // if the cursor is already in this table,
1332 // expand the current selection (i.e., set
1333 // point to new position; keep mark)
1334 SwPaM aPaM( *pStartNode );
1335 aPaM.Move( fnMoveForward, GoInNode );
1336 aPaM.SetMark();
1337 const SwPaM *pPaM = pCursorShell->GetTableCrs() ? pCursorShell->GetTableCrs()
1338 : pCursorShell->GetCursor();
1339 *(aPaM.GetMark()) = *pPaM->GetMark();
1340 Select( aPaM );
1341
1342 }
1343 }
1344
isAccessibleChildSelected(sal_Int32 nChildIndex)1345 sal_Bool SAL_CALL SwAccessibleTable::isAccessibleChildSelected(
1346 sal_Int32 nChildIndex )
1347 {
1348 SolarMutexGuard aGuard;
1349
1350 ThrowIfDisposed();
1351
1352 if( (nChildIndex < 0) || (nChildIndex >= getAccessibleChildCount()) ) // #i77106#
1353 throw lang::IndexOutOfBoundsException();
1354
1355 return IsChildSelected( nChildIndex );
1356 }
1357
clearAccessibleSelection()1358 void SAL_CALL SwAccessibleTable::clearAccessibleSelection( )
1359 {
1360 SolarMutexGuard aGuard;
1361
1362 ThrowIfDisposed();
1363
1364 SwCursorShell* pCursorShell = GetCursorShell();
1365 if( pCursorShell != nullptr )
1366 {
1367 pCursorShell->StartAction();
1368 pCursorShell->ClearMark();
1369 pCursorShell->EndAction();
1370 }
1371 }
1372
selectAllAccessibleChildren()1373 void SAL_CALL SwAccessibleTable::selectAllAccessibleChildren( )
1374 {
1375 // first clear selection, then select first and last child
1376 clearAccessibleSelection();
1377 selectAccessibleChild( 0 );
1378 selectAccessibleChild( getAccessibleChildCount()-1 ); // #i77106#
1379 }
1380
getSelectedAccessibleChildCount()1381 sal_Int32 SAL_CALL SwAccessibleTable::getSelectedAccessibleChildCount( )
1382 {
1383 SolarMutexGuard aGuard;
1384
1385 ThrowIfDisposed();
1386
1387 // iterate over all children and count isAccessibleChildSelected()
1388 sal_Int32 nCount = 0;
1389
1390 sal_Int32 nChildren = getAccessibleChildCount(); // #i71106#
1391 for( sal_Int32 n = 0; n < nChildren; n++ )
1392 if( IsChildSelected( n ) )
1393 nCount++;
1394
1395 return nCount;
1396 }
1397
getSelectedAccessibleChild(sal_Int32 nSelectedChildIndex)1398 uno::Reference<XAccessible> SAL_CALL SwAccessibleTable::getSelectedAccessibleChild(
1399 sal_Int32 nSelectedChildIndex )
1400 {
1401 SolarMutexGuard aGuard;
1402
1403 ThrowIfDisposed();
1404
1405 // parameter checking (part 1): index lower 0
1406 if( nSelectedChildIndex < 0 )
1407 throw lang::IndexOutOfBoundsException();
1408
1409 sal_Int32 nChildIndex = GetIndexOfSelectedChild( nSelectedChildIndex );
1410
1411 // parameter checking (part 2): index higher than selected children?
1412 if( nChildIndex < 0 )
1413 throw lang::IndexOutOfBoundsException();
1414
1415 // #i77106#
1416 if ( nChildIndex >= getAccessibleChildCount() )
1417 {
1418 throw lang::IndexOutOfBoundsException();
1419 }
1420
1421 return getAccessibleChild( nChildIndex );
1422 }
1423
1424 // index has to be treated as global child index.
deselectAccessibleChild(sal_Int32 nChildIndex)1425 void SAL_CALL SwAccessibleTable::deselectAccessibleChild(
1426 sal_Int32 nChildIndex )
1427 {
1428 SolarMutexGuard aGuard;
1429
1430 ThrowIfDisposed();
1431
1432 SwCursorShell* pCursorShell = GetCursorShell();
1433
1434 // index has to be treated as global child index
1435 if ( !pCursorShell )
1436 throw lang::IndexOutOfBoundsException();
1437
1438 // assure, that given child index is in bounds.
1439 if ( nChildIndex < 0 || nChildIndex >= getAccessibleChildCount() ) // #i77106#
1440 throw lang::IndexOutOfBoundsException();
1441
1442 // assure, that child, identified by the given index, is selected.
1443 if ( !IsChildSelected( nChildIndex ) )
1444 return;
1445
1446 const SwTableBox* pBox = GetTableBox( nChildIndex );
1447 OSL_ENSURE( pBox != nullptr, "We need the table box." );
1448
1449 // If we unselect point, then set cursor to mark. If we clear another
1450 // selected box, then set cursor to point.
1451 // reduce selection to mark.
1452 SwPaM *pPaM = pCursorShell->GetTableCrs() ? pCursorShell->GetTableCrs()
1453 : pCursorShell->GetCursor();
1454 bool bDeselectPoint =
1455 pBox->GetSttNd() ==
1456 pPaM->GetPoint()->nNode.GetNode().FindTableBoxStartNode();
1457
1458 SwPaM aPaM( bDeselectPoint ? *pPaM->GetMark() : *pPaM->GetPoint() );
1459
1460 pCursorShell->StartAction();
1461
1462 // Set cursor into either point or mark
1463 Select( aPaM );
1464 // Move cursor to the end of the table creating a selection and a table
1465 // cursor.
1466 pCursorShell->SetMark();
1467 pCursorShell->MoveTable( GotoCurrTable, fnTableEnd );
1468 // now set the cursor into the cell again.
1469 pPaM = pCursorShell->GetTableCrs() ? pCursorShell->GetTableCrs()
1470 : pCursorShell->GetCursor();
1471 *pPaM->GetPoint() = *pPaM->GetMark();
1472 pCursorShell->EndAction();
1473 }
1474
getBackground()1475 sal_Int32 SAL_CALL SwAccessibleTable::getBackground()
1476 {
1477 const SvxBrushItem &rBack = GetFrame()->GetAttrSet()->GetBackground();
1478 Color crBack = rBack.GetColor();
1479
1480 if (COL_AUTO == crBack)
1481 {
1482 uno::Reference<XAccessible> xAccDoc = getAccessibleParent();
1483 if (xAccDoc.is())
1484 {
1485 uno::Reference<XAccessibleComponent> xComponentDoc(xAccDoc,uno::UNO_QUERY);
1486 if (xComponentDoc.is())
1487 {
1488 crBack = Color(xComponentDoc->getBackground());
1489 }
1490 }
1491 }
1492 return sal_Int32(crBack);
1493 }
1494
FireSelectionEvent()1495 void SwAccessibleTable::FireSelectionEvent( )
1496 {
1497 AccessibleEventObject aEvent;
1498
1499 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_REMOVE;
1500
1501 for (const auto& rCell : m_vecCellRemove)
1502 {
1503 // fdo#57197: check if the object is still alive
1504 uno::Reference<XAccessible> const xAcc(rCell.second);
1505 if (xAcc.is())
1506 {
1507 SwAccessibleContext *const pAccCell(rCell.first);
1508 assert(pAccCell);
1509 pAccCell->FireAccessibleEvent(aEvent);
1510 }
1511 }
1512
1513 if (m_vecCellAdd.size() <= SELECTION_WITH_NUM)
1514 {
1515 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_ADD;
1516 for (const auto& rCell : m_vecCellAdd)
1517 {
1518 // fdo#57197: check if the object is still alive
1519 uno::Reference<XAccessible> const xAcc(rCell.second);
1520 if (xAcc.is())
1521 {
1522 SwAccessibleContext *const pAccCell(rCell.first);
1523 assert(pAccCell);
1524 pAccCell->FireAccessibleEvent(aEvent);
1525 }
1526 }
1527 return ;
1528 }
1529 else
1530 {
1531 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_WITHIN;
1532 FireAccessibleEvent(aEvent);
1533 }
1534 }
1535
AddSelectionCell(SwAccessibleContext * const pAccCell,bool const bAddOrRemove)1536 void SwAccessibleTable::AddSelectionCell(
1537 SwAccessibleContext *const pAccCell, bool const bAddOrRemove)
1538 {
1539 uno::Reference<XAccessible> const xTmp(pAccCell);
1540 if (bAddOrRemove)
1541 {
1542 m_vecCellAdd.emplace_back(pAccCell, xTmp);
1543 }
1544 else
1545 {
1546 m_vecCellRemove.emplace_back(pAccCell, xTmp);
1547 }
1548 }
1549
1550 // XAccessibleTableSelection
selectRow(sal_Int32 row)1551 sal_Bool SAL_CALL SwAccessibleTable::selectRow( sal_Int32 row )
1552 {
1553 SolarMutexGuard g;
1554
1555 if( isAccessibleColumnSelected( row ) )
1556 return true;
1557
1558 long lColumnCount = getAccessibleColumnCount();
1559 for(long lCol = 0; lCol < lColumnCount; lCol ++)
1560 {
1561 long lChildIndex = getAccessibleIndex(row, lCol);
1562 selectAccessibleChild(lChildIndex);
1563 }
1564
1565 return true;
1566 }
selectColumn(sal_Int32 column)1567 sal_Bool SAL_CALL SwAccessibleTable::selectColumn( sal_Int32 column )
1568 {
1569 SolarMutexGuard g;
1570
1571 if( isAccessibleColumnSelected( column ) )
1572 return true;
1573
1574 long lRowCount = getAccessibleRowCount();
1575
1576 for(long lRow = 0; lRow < lRowCount; lRow ++)
1577 {
1578 long lChildIndex = getAccessibleIndex(lRow, column);
1579 selectAccessibleChild(lChildIndex);
1580 }
1581 return true;
1582 }
1583
unselectRow(sal_Int32 row)1584 sal_Bool SAL_CALL SwAccessibleTable::unselectRow( sal_Int32 row )
1585 {
1586 SolarMutexGuard g;
1587
1588 if( isAccessibleSelected( row , 0 ) && isAccessibleSelected( row , getAccessibleColumnCount()-1 ) )
1589 {
1590 SwCursorShell* pCursorShell = GetCursorShell();
1591 if( pCursorShell != nullptr )
1592 {
1593 pCursorShell->StartAction();
1594 pCursorShell->ClearMark();
1595 pCursorShell->EndAction();
1596 return true;
1597 }
1598 }
1599 return true;
1600 }
1601
unselectColumn(sal_Int32 column)1602 sal_Bool SAL_CALL SwAccessibleTable::unselectColumn( sal_Int32 column )
1603 {
1604 SolarMutexGuard g;
1605
1606 if( isAccessibleSelected( 0 , column ) && isAccessibleSelected( getAccessibleRowCount()-1,column))
1607 {
1608 SwCursorShell* pCursorShell = GetCursorShell();
1609 if( pCursorShell != nullptr )
1610 {
1611 pCursorShell->StartAction();
1612 pCursorShell->ClearMark();
1613 pCursorShell->EndAction();
1614 return true;
1615 }
1616 }
1617 return true;
1618 }
1619
1620 // #i77106# - implementation of class <SwAccessibleTableColHeaders>
SwAccessibleTableColHeaders(std::shared_ptr<SwAccessibleMap> const & pMap,const SwTabFrame * const pTabFrame)1621 SwAccessibleTableColHeaders::SwAccessibleTableColHeaders(
1622 std::shared_ptr<SwAccessibleMap> const& pMap,
1623 const SwTabFrame *const pTabFrame)
1624 : SwAccessibleTable(pMap, pTabFrame)
1625 {
1626 SolarMutexGuard aGuard;
1627
1628 const SwFrameFormat* pFrameFormat = pTabFrame->GetFormat();
1629 if(pFrameFormat)
1630 StartListening(const_cast<SwFrameFormat*>(pFrameFormat)->GetNotifier());
1631 const OUString aName = pFrameFormat->GetName() + "-ColumnHeaders";
1632
1633 SetName( aName + "-" + OUString::number( pTabFrame->GetPhyPageNum() ) );
1634
1635 const OUString sArg2( GetFormattedPageNumber() );
1636
1637 SetDesc( GetResource( STR_ACCESS_TABLE_DESC, &aName, &sArg2 ) );
1638
1639 NotRegisteredAtAccessibleMap(); // #i85634#
1640 }
1641
CreateNewTableData()1642 std::unique_ptr<SwAccessibleTableData_Impl> SwAccessibleTableColHeaders::CreateNewTableData()
1643 {
1644 const SwTabFrame* pTabFrame = static_cast<const SwTabFrame*>( GetFrame() );
1645 return std::unique_ptr<SwAccessibleTableData_Impl>(new SwAccessibleTableData_Impl( *(GetMap()), pTabFrame, IsInPagePreview(), true ));
1646 }
1647
Notify(const SfxHint &)1648 void SwAccessibleTableColHeaders::Notify(const SfxHint& )
1649 {
1650 }
1651
1652 // XInterface
queryInterface(const uno::Type & aType)1653 uno::Any SAL_CALL SwAccessibleTableColHeaders::queryInterface( const uno::Type& aType )
1654 {
1655 return SwAccessibleTable::queryInterface( aType );
1656 }
1657
1658 // XAccessibleContext
getAccessibleChildCount()1659 sal_Int32 SAL_CALL SwAccessibleTableColHeaders::getAccessibleChildCount()
1660 {
1661 SolarMutexGuard aGuard;
1662
1663 ThrowIfDisposed();
1664
1665 sal_Int32 nCount = 0;
1666
1667 const SwTabFrame* pTabFrame = static_cast<const SwTabFrame*>( GetFrame() );
1668 const SwAccessibleChildSList aVisList( GetVisArea(), *pTabFrame, *(GetMap()) );
1669 SwAccessibleChildSList::const_iterator aIter( aVisList.begin() );
1670 while( aIter != aVisList.end() )
1671 {
1672 const SwAccessibleChild& rLower = *aIter;
1673 if( rLower.IsAccessible( IsInPagePreview() ) )
1674 {
1675 nCount++;
1676 }
1677 else if( rLower.GetSwFrame() )
1678 {
1679 // There are no unaccessible SdrObjects that count
1680 if ( !rLower.GetSwFrame()->IsRowFrame() ||
1681 pTabFrame->IsInHeadline( *(rLower.GetSwFrame()) ) )
1682 {
1683 nCount += SwAccessibleFrame::GetChildCount( *(GetMap()),
1684 GetVisArea(),
1685 rLower.GetSwFrame(),
1686 IsInPagePreview() );
1687 }
1688 }
1689 ++aIter;
1690 }
1691
1692 return nCount;
1693 }
1694
1695 uno::Reference< XAccessible> SAL_CALL
getAccessibleChild(sal_Int32 nIndex)1696 SwAccessibleTableColHeaders::getAccessibleChild (sal_Int32 nIndex)
1697 {
1698 if ( nIndex < 0 || nIndex >= getAccessibleChildCount() )
1699 {
1700 throw lang::IndexOutOfBoundsException();
1701 }
1702
1703 return SwAccessibleTable::getAccessibleChild( nIndex );
1704 }
1705
1706 // XAccessibleTable
1707 uno::Reference< XAccessibleTable >
getAccessibleRowHeaders()1708 SAL_CALL SwAccessibleTableColHeaders::getAccessibleRowHeaders()
1709 {
1710 return uno::Reference< XAccessibleTable >();
1711 }
1712
1713 uno::Reference< XAccessibleTable >
getAccessibleColumnHeaders()1714 SAL_CALL SwAccessibleTableColHeaders::getAccessibleColumnHeaders()
1715 {
1716 return uno::Reference< XAccessibleTable >();
1717 }
1718
1719 // XServiceInfo
1720
getImplementationName()1721 OUString SAL_CALL SwAccessibleTableColHeaders::getImplementationName()
1722 {
1723 static const sal_Char sImplName[] = "com.sun.star.comp.Writer.SwAccessibleTableColumnHeadersView";
1724 return sImplName;
1725 }
1726
1727 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1728