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 <vcl/svtaccessiblefactory.hxx>
21 #include <vcl/accessiblefactory.hxx>
22 #include <vcl/toolkit/svtabbx.hxx>
23 #include <vcl/headbar.hxx>
24 #include <vcl/toolkit/svlbitm.hxx>
25 #include <vcl/toolkit/treelistentry.hxx>
26 #include <unotools/accessiblestatesethelper.hxx>
27 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
28 #include <rtl/ustrbuf.hxx>
29 #include <sal/log.hxx>
30 #include <o3tl/safeint.hxx>
31 #include <osl/diagnose.h>
32 #include <strings.hrc>
33 #include <svdata.hxx>
34 #include <memory>
35 #include <tools/json_writer.hxx>
36 
37 using namespace ::com::sun::star::uno;
38 using namespace ::com::sun::star::accessibility;
39 
40 constexpr SvLBoxTabFlags MYTABMASK =
41     SvLBoxTabFlags::ADJUST_RIGHT | SvLBoxTabFlags::ADJUST_LEFT | SvLBoxTabFlags::ADJUST_CENTER | SvLBoxTabFlags::FORCE;
42 
lcl_DumpEntryAndSiblings(tools::JsonWriter & rJsonWriter,SvTreeListEntry * pEntry,SvTabListBox * pTabListBox,bool bCheckButtons)43 static void lcl_DumpEntryAndSiblings(tools::JsonWriter& rJsonWriter,
44                                      SvTreeListEntry* pEntry,
45                                      SvTabListBox* pTabListBox,
46                                      bool bCheckButtons)
47 {
48     while (pEntry)
49     {
50         auto aNode = rJsonWriter.startStruct();
51 
52         // simple listbox value
53         const SvLBoxItem* pIt = pEntry->GetFirstItem(SvLBoxItemType::String);
54         if (pIt)
55             rJsonWriter.put("text", static_cast<const SvLBoxString*>(pIt)->GetText());
56 
57         // column based data
58         {
59             auto aColumns = rJsonWriter.startArray("columns");
60 
61             for (size_t i = 0; i < pEntry->ItemCount(); i++)
62             {
63                 SvLBoxItem& rItem = pEntry->GetItem(i);
64                 if (rItem.GetType() == SvLBoxItemType::String)
65                 {
66                     const SvLBoxString* pStringItem = dynamic_cast<const SvLBoxString*>(&rItem);
67                     if (pStringItem)
68                     {
69                         auto aColumn = rJsonWriter.startStruct();
70                         rJsonWriter.put("text", pStringItem->GetText());
71                     }
72                 }
73             }
74         }
75 
76         // SalInstanceTreeView does not use the flag CHILDREN_ON_DEMAND
77         // and it creates a dummy child
78         const SvTreeListEntries& rChildren = pEntry->GetChildEntries();
79         if (rChildren.size() == 1)
80         {
81             auto& rChild = rChildren[0];
82             if (const SvLBoxItem* pChild = rChild->GetFirstItem(SvLBoxItemType::String))
83             {
84                 if (static_cast<const SvLBoxString*>(pChild)->GetText() == "<dummy>")
85                     rJsonWriter.put("ondemand", "true");
86             }
87         }
88 
89         if (bCheckButtons)
90         {
91             SvButtonState eCheckState = pTabListBox->GetCheckButtonState(pEntry);
92             if (eCheckState == SvButtonState::Unchecked)
93                 rJsonWriter.put("state", "false");
94             else if (eCheckState == SvButtonState::Checked)
95                 rJsonWriter.put("state", "true");
96         }
97 
98         if (pTabListBox->IsSelected(pEntry))
99             rJsonWriter.put("selected", "true");
100 
101         rJsonWriter.put("row", OString::number(pTabListBox->GetModel()->GetAbsPos(pEntry)).getStr());
102 
103         SvTreeListEntry* pChild = pTabListBox->FirstChild(pEntry);
104         if (pChild)
105         {
106             auto childrenNode = rJsonWriter.startArray("children");
107             lcl_DumpEntryAndSiblings(rJsonWriter, pChild, pTabListBox, bCheckButtons);
108         }
109 
110         pEntry = pEntry->NextSibling();
111     }
112 }
113 
DumpAsPropertyTree(tools::JsonWriter & rJsonWriter)114 void SvTabListBox::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter)
115 {
116     SvTreeListBox::DumpAsPropertyTree(rJsonWriter);
117 
118     rJsonWriter.put("singleclickactivate", GetActivateOnSingleClick());
119 
120     bool bCheckButtons = static_cast<int>(nTreeFlags & SvTreeFlags::CHKBTN);
121 
122     auto entriesNode = rJsonWriter.startArray("entries");
123     lcl_DumpEntryAndSiblings(rJsonWriter, First(), this, bCheckButtons);
124 }
125 
126 // SvTreeListBox callback
127 
SetTabs()128 void SvTabListBox::SetTabs()
129 {
130     SvTreeListBox::SetTabs();
131     if( mvTabList.empty() )
132         return;
133 
134     DBG_ASSERT(!mvTabList.empty(),"TabList ?");
135 
136     // The tree listbox has now inserted its tabs into the list. Now we
137     // fluff up the list with additional tabs and adjust the rightmost tab
138     // of the tree listbox.
139 
140     // Picking the rightmost tab.
141     // HACK for the explorer! If ViewParent != 0, the first tab of the tree
142     // listbox is calculated by the tree listbox itself! This behavior is
143     // necessary for ButtonsOnRoot, as the explorer does not know in this
144     // case, which additional offset it needs to add to the tabs in this mode
145     // -- the tree listbox knows that, though!
146     /*
147     if( !pViewParent )
148     {
149     SvLBoxTab* pFirstTab = (SvLBoxTab*)aTabs.GetObject( aTabs.Count()-1 );
150     pFirstTab->SetPos( pTabList[0].GetPos() );
151     pFirstTab->nFlags &= ~MYTABMASK;
152     pFirstTab->nFlags |= pTabList[0].nFlags;
153     }
154     */
155 
156     // append all other tabs to the list
157     for( sal_uInt16 nCurTab = 1; nCurTab < sal_uInt16(mvTabList.size()); nCurTab++ )
158     {
159         SvLBoxTab& rTab = mvTabList[nCurTab];
160         AddTab( rTab.GetPos(), rTab.nFlags );
161     }
162 }
163 
InitEntry(SvTreeListEntry * pEntry,const OUString & rStr,const Image & rColl,const Image & rExp)164 void SvTabListBox::InitEntry(SvTreeListEntry* pEntry, const OUString& rStr,
165     const Image& rColl, const Image& rExp)
166 {
167     SvTreeListBox::InitEntry(pEntry, rStr, rColl, rExp);
168 
169     sal_Int32 nIndex = 0;
170     // TODO: verify if nTabCount is always >0 here!
171     const sal_uInt16 nCount = mvTabList.size() - 1;
172     for( sal_uInt16 nToken = 0; nToken < nCount; nToken++ )
173     {
174         const OUString aToken = GetToken(aCurEntry, nIndex);
175         pEntry->AddItem(std::make_unique<SvLBoxString>(aToken));
176     }
177 }
178 
SvTabListBox(vcl::Window * pParent,WinBits nBits)179 SvTabListBox::SvTabListBox( vcl::Window* pParent, WinBits nBits )
180     : SvTreeListBox( pParent, nBits )
181 {
182     SetHighlightRange();    // select full width
183 }
184 
~SvTabListBox()185 SvTabListBox::~SvTabListBox()
186 {
187     disposeOnce();
188 }
189 
dispose()190 void SvTabListBox::dispose()
191 {
192     mvTabList.clear();
193     SvTreeListBox::dispose();
194 }
195 
SetTabs(sal_uInt16 nTabs,tools::Long const pTabPositions[],MapUnit eMapUnit)196 void SvTabListBox::SetTabs(sal_uInt16 nTabs, tools::Long const pTabPositions[], MapUnit eMapUnit)
197 {
198     mvTabList.resize(nTabs);
199 
200     MapMode aMMSource( eMapUnit );
201     MapMode aMMDest( MapUnit::MapPixel );
202 
203     for( sal_uInt16 nIdx = 0; nIdx < sal_uInt16(mvTabList.size()); nIdx++, pTabPositions++ )
204     {
205         Size aSize( *pTabPositions, 0 );
206         aSize = LogicToLogic( aSize, &aMMSource, &aMMDest );
207         tools::Long nNewTab = aSize.Width();
208         mvTabList[nIdx].SetPos( nNewTab );
209         mvTabList[nIdx].nFlags &= MYTABMASK;
210     }
211     SvTreeListBox::nTreeFlags |= SvTreeFlags::RECALCTABS;
212     if( IsUpdateMode() )
213         Invalidate();
214 }
215 
InsertEntry(const OUString & rText,SvTreeListEntry * pParent,bool,sal_uInt32 nPos,void * pUserData)216 SvTreeListEntry* SvTabListBox::InsertEntry( const OUString& rText, SvTreeListEntry* pParent,
217                                         bool /*bChildrenOnDemand*/,
218                                         sal_uInt32 nPos, void* pUserData )
219 {
220     return InsertEntryToColumn( rText, pParent, nPos, 0xffff, pUserData );
221 }
222 
InsertEntry(const OUString & rText,const Image & rExpandedEntryBmp,const Image & rCollapsedEntryBmp,SvTreeListEntry * pParent,bool,sal_uInt32 nPos,void * pUserData)223 SvTreeListEntry* SvTabListBox::InsertEntry( const OUString& rText,
224                                         const Image& rExpandedEntryBmp,
225                                         const Image& rCollapsedEntryBmp,
226                                         SvTreeListEntry* pParent,
227                                         bool /*bChildrenOnDemand*/,
228                                         sal_uInt32 nPos, void* pUserData )
229 {
230     return InsertEntryToColumn( rText, rExpandedEntryBmp, rCollapsedEntryBmp,
231                                 pParent, nPos, 0xffff, pUserData );
232 }
233 
InsertEntryToColumn(const OUString & rStr,SvTreeListEntry * pParent,sal_uInt32 nPos,sal_uInt16 nCol,void * pUser)234 SvTreeListEntry* SvTabListBox::InsertEntryToColumn(const OUString& rStr,SvTreeListEntry* pParent,sal_uInt32 nPos,sal_uInt16 nCol,
235     void* pUser )
236 {
237     OUString aStr;
238     if( nCol != 0xffff )
239     {
240         while( nCol )
241         {
242             aStr += "\t";
243             nCol--;
244         }
245     }
246     aStr += rStr;
247     OUString aFirstStr( aStr );
248     sal_Int32 nEnd = aFirstStr.indexOf( '\t' );
249     if( nEnd != -1 )
250     {
251         aFirstStr = aFirstStr.copy(0, nEnd);
252         aCurEntry = aStr.copy(++nEnd);
253     }
254     else
255         aCurEntry.clear();
256     return SvTreeListBox::InsertEntry( aFirstStr, pParent, false, nPos, pUser );
257 }
258 
InsertEntryToColumn(const OUString & rStr,const Image & rExpandedEntryBmp,const Image & rCollapsedEntryBmp,SvTreeListEntry * pParent,sal_uInt32 nPos,sal_uInt16 nCol,void * pUser)259 SvTreeListEntry* SvTabListBox::InsertEntryToColumn( const OUString& rStr,
260     const Image& rExpandedEntryBmp, const Image& rCollapsedEntryBmp,
261     SvTreeListEntry* pParent,sal_uInt32 nPos,sal_uInt16 nCol, void* pUser )
262 {
263     OUString aStr;
264     if( nCol != 0xffff )
265     {
266         while( nCol )
267         {
268             aStr += "\t";
269             nCol--;
270         }
271     }
272     aStr += rStr;
273     OUString aFirstStr( aStr );
274     sal_Int32 nEnd = aFirstStr.indexOf('\t');
275     if (nEnd != -1)
276     {
277         aFirstStr = aFirstStr.copy(0, nEnd);
278         aCurEntry = aStr.copy(++nEnd);
279     }
280     else
281         aCurEntry.clear();
282 
283     return SvTreeListBox::InsertEntry(
284         aFirstStr,
285         rExpandedEntryBmp, rCollapsedEntryBmp,
286         pParent, false, nPos, pUser );
287 }
288 
GetEntryText(SvTreeListEntry * pEntry) const289 OUString SvTabListBox::GetEntryText( SvTreeListEntry* pEntry ) const
290 {
291     return GetEntryText( pEntry, 0xffff );
292 }
293 
GetEntryText(const SvTreeListEntry * pEntry,sal_uInt16 nCol)294 OUString SvTabListBox::GetEntryText( const SvTreeListEntry* pEntry, sal_uInt16 nCol )
295 {
296     DBG_ASSERT(pEntry,"GetEntryText:Invalid Entry");
297     OUStringBuffer aResult;
298     if( pEntry )
299     {
300         sal_uInt16 nCount = pEntry->ItemCount();
301         sal_uInt16 nCur = 0;
302         while( nCur < nCount )
303         {
304             const SvLBoxItem& rStr = pEntry->GetItem( nCur );
305             if (rStr.GetType() == SvLBoxItemType::String)
306             {
307                 if( nCol == 0xffff )
308                 {
309                     if (!aResult.isEmpty())
310                         aResult.append("\t");
311                     aResult.append(static_cast<const SvLBoxString&>(rStr).GetText());
312                 }
313                 else
314                 {
315                     if( nCol == 0 )
316                         return static_cast<const SvLBoxString&>(rStr).GetText();
317                     nCol--;
318                 }
319             }
320             nCur++;
321         }
322     }
323     return aResult.makeStringAndClear();
324 }
325 
GetEntryText(sal_uInt32 nPos,sal_uInt16 nCol) const326 OUString SvTabListBox::GetEntryText( sal_uInt32 nPos, sal_uInt16 nCol ) const
327 {
328     SvTreeListEntry* pEntry = GetEntryOnPos( nPos );
329     return GetEntryText( pEntry, nCol );
330 }
331 
GetCellText(sal_uInt32 nPos,sal_uInt16 nCol) const332 OUString SvTabListBox::GetCellText( sal_uInt32 nPos, sal_uInt16 nCol ) const
333 {
334     SvTreeListEntry* pEntry = GetEntryOnPos( nPos );
335     DBG_ASSERT( pEntry, "SvTabListBox::GetCellText(): Invalid Entry" );
336     OUString aResult;
337     if (pEntry && pEntry->ItemCount() > o3tl::make_unsigned(nCol+1))
338     {
339         const SvLBoxItem& rStr = pEntry->GetItem( nCol + 1 );
340         if (rStr.GetType() == SvLBoxItemType::String)
341             aResult = static_cast<const SvLBoxString&>(rStr).GetText();
342     }
343     return aResult;
344 }
345 
GetEntryPos(const SvTreeListEntry * pEntry) const346 sal_uInt32 SvTabListBox::GetEntryPos( const SvTreeListEntry* pEntry ) const
347 {
348     sal_uInt32 nPos = 0;
349     SvTreeListEntry* pTmpEntry = First();
350     while( pTmpEntry )
351     {
352         if ( pTmpEntry == pEntry )
353             return nPos;
354         pTmpEntry = Next( pTmpEntry );
355         ++nPos;
356     }
357     return 0xffffffff;
358 }
359 
360 // static
GetToken(const OUString & sStr,sal_Int32 & nIndex)361 OUString SvTabListBox::GetToken( const OUString &sStr, sal_Int32& nIndex )
362 {
363     return sStr.getToken(0, '\t', nIndex);
364 }
365 
GetTabEntryText(sal_uInt32 nPos,sal_uInt16 nCol) const366 OUString SvTabListBox::GetTabEntryText( sal_uInt32 nPos, sal_uInt16 nCol ) const
367 {
368     SvTreeListEntry* pEntry = SvTreeListBox::GetEntry( nPos );
369     DBG_ASSERT( pEntry, "GetTabEntryText(): Invalid entry " );
370     OUStringBuffer aResult;
371     if ( pEntry )
372     {
373         sal_uInt16 nCount = pEntry->ItemCount();
374         sal_uInt16 nCur = 0;
375         while( nCur < nCount )
376         {
377             const SvLBoxItem& rBoxItem = pEntry->GetItem( nCur );
378             if (rBoxItem.GetType() == SvLBoxItemType::String)
379             {
380                 if ( nCol == 0xffff )
381                 {
382                     if (!aResult.isEmpty())
383                         aResult.append("\t");
384                     aResult.append(static_cast<const SvLBoxString&>(rBoxItem).GetText());
385                 }
386                 else
387                 {
388                     if ( nCol == 0 )
389                     {
390                         OUString sRet = static_cast<const SvLBoxString&>(rBoxItem).GetText();
391                         if ( sRet.isEmpty() )
392                             sRet = VclResId( STR_SVT_ACC_EMPTY_FIELD );
393                         return sRet;
394                     }
395                     --nCol;
396                 }
397             }
398             ++nCur;
399         }
400     }
401     return aResult.makeStringAndClear();
402 }
403 
GetEntryOnPos(sal_uInt32 _nEntryPos) const404 SvTreeListEntry* SvTabListBox::GetEntryOnPos( sal_uInt32 _nEntryPos ) const
405 {
406     SvTreeListEntry* pEntry = nullptr;
407     sal_uInt32 i, nPos = 0, nCount = GetLevelChildCount( nullptr );
408     for ( i = 0; i < nCount; ++i )
409     {
410         SvTreeListEntry* pParent = GetEntry(i);
411         if ( nPos == _nEntryPos )
412         {
413             pEntry = pParent;
414             break;
415         }
416         else
417         {
418             nPos++;
419             pEntry = GetChildOnPos( pParent, _nEntryPos, nPos );
420             if ( pEntry )
421                 break;
422         }
423     }
424 
425     return pEntry;
426 }
427 
GetChildOnPos(SvTreeListEntry * _pParent,sal_uInt32 _nEntryPos,sal_uInt32 & _rPos) const428 SvTreeListEntry* SvTabListBox::GetChildOnPos( SvTreeListEntry* _pParent, sal_uInt32 _nEntryPos, sal_uInt32& _rPos ) const
429 {
430     sal_uInt32 i, nCount = GetLevelChildCount( _pParent );
431     for ( i = 0; i < nCount; ++i )
432     {
433         SvTreeListEntry* pParent = GetEntry( _pParent, i );
434         if ( _rPos == _nEntryPos )
435             return pParent;
436         else
437         {
438             _rPos++;
439             SvTreeListEntry* pEntry = GetChildOnPos( pParent, _nEntryPos, _rPos );
440             if ( pEntry )
441                 return pEntry;
442         }
443     }
444 
445     return nullptr;
446 }
447 
SetTabJustify(sal_uInt16 nTab,SvTabJustify eJustify)448 void SvTabListBox::SetTabJustify( sal_uInt16 nTab, SvTabJustify eJustify)
449 {
450     DBG_ASSERT(nTab<mvTabList.size(),"GetTabPos:Invalid Tab");
451     if( nTab >= mvTabList.size() )
452         return;
453     SvLBoxTab& rTab = mvTabList[ nTab ];
454     SvLBoxTabFlags nFlags = rTab.nFlags;
455     nFlags &= ~MYTABMASK;
456     // see SvLBoxTab::CalcOffset for force, which only matters for centering
457     nFlags |= static_cast<SvLBoxTabFlags>(eJustify) | SvLBoxTabFlags::FORCE;
458     rTab.nFlags = nFlags;
459     SvTreeListBox::nTreeFlags |= SvTreeFlags::RECALCTABS;
460     if( IsUpdateMode() )
461         Invalidate();
462 }
463 
SetTabEditable(sal_uInt16 nTab,bool bEditable)464 void SvTabListBox::SetTabEditable(sal_uInt16 nTab, bool bEditable)
465 {
466     DBG_ASSERT(nTab<mvTabList.size(),"GetTabPos:Invalid Tab");
467     if( nTab >= mvTabList.size() )
468         return;
469     SvLBoxTab& rTab = mvTabList[ nTab ];
470     if (bEditable)
471         rTab.nFlags |= SvLBoxTabFlags::EDITABLE;
472     else
473         rTab.nFlags &= ~SvLBoxTabFlags::EDITABLE;
474 }
475 
GetLogicTab(sal_uInt16 nTab)476 tools::Long SvTabListBox::GetLogicTab( sal_uInt16 nTab )
477 {
478     if( SvTreeListBox::nTreeFlags & SvTreeFlags::RECALCTABS )
479         SetTabs();
480 
481     DBG_ASSERT(nTab<mvTabList.size(),"GetTabPos:Invalid Tab");
482     return aTabs[ nTab ]->GetPos();
483 }
484 
485 namespace vcl
486 {
487     struct SvHeaderTabListBoxImpl
488     {
489         VclPtr<HeaderBar>       m_pHeaderBar;
490         AccessibleFactoryAccess m_aFactoryAccess;
491 
SvHeaderTabListBoxImplvcl::SvHeaderTabListBoxImpl492         SvHeaderTabListBoxImpl() : m_pHeaderBar( nullptr ) { }
493     };
494 }
495 
SvHeaderTabListBox(vcl::Window * pParent,WinBits nWinStyle)496 SvHeaderTabListBox::SvHeaderTabListBox( vcl::Window* pParent, WinBits nWinStyle )
497     : SvTabListBox(pParent, nWinStyle)
498     , m_bFirstPaint(true)
499     , m_pImpl(new ::vcl::SvHeaderTabListBoxImpl)
500     , m_pAccessible(nullptr)
501 {
502 }
503 
~SvHeaderTabListBox()504 SvHeaderTabListBox::~SvHeaderTabListBox()
505 {
506     disposeOnce();
507 }
508 
dispose()509 void SvHeaderTabListBox::dispose()
510 {
511     m_pImpl.reset();
512     SvTabListBox::dispose();
513 }
514 
Paint(vcl::RenderContext & rRenderContext,const tools::Rectangle & rRect)515 void SvHeaderTabListBox::Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect )
516 {
517     if (m_bFirstPaint)
518     {
519         m_bFirstPaint = false;
520     }
521     SvTabListBox::Paint(rRenderContext, rRect);
522 }
523 
InitHeaderBar(HeaderBar * pHeaderBar)524 void SvHeaderTabListBox::InitHeaderBar( HeaderBar* pHeaderBar )
525 {
526     DBG_ASSERT( !m_pImpl->m_pHeaderBar, "header bar already initialized" );
527     DBG_ASSERT( pHeaderBar, "invalid header bar initialization" );
528     m_pImpl->m_pHeaderBar = pHeaderBar;
529     SetScrolledHdl( LINK( this, SvHeaderTabListBox, ScrollHdl_Impl ) );
530     m_pImpl->m_pHeaderBar->SetCreateAccessibleHdl( LINK( this, SvHeaderTabListBox, CreateAccessibleHdl_Impl ) );
531 }
532 
GetHeaderBar()533 HeaderBar* SvHeaderTabListBox::GetHeaderBar()
534 {
535     return m_pImpl ? m_pImpl->m_pHeaderBar : nullptr;
536 }
537 
IsItemChecked(SvTreeListEntry * pEntry,sal_uInt16 nCol)538 bool SvHeaderTabListBox::IsItemChecked( SvTreeListEntry* pEntry, sal_uInt16 nCol )
539 {
540     SvButtonState eState = SvButtonState::Unchecked;
541     SvLBoxButton& rItem = static_cast<SvLBoxButton&>( pEntry->GetItem( nCol + 1 ) );
542 
543     if (rItem.GetType() == SvLBoxItemType::Button)
544     {
545         SvItemStateFlags nButtonFlags = rItem.GetButtonFlags();
546         eState = SvLBoxButtonData::ConvertToButtonState( nButtonFlags );
547     }
548 
549     return ( eState == SvButtonState::Checked );
550 }
551 
InsertEntryToColumn(const OUString & rStr,SvTreeListEntry * pParent,sal_uInt32 nPos,sal_uInt16 nCol,void * pUserData)552 SvTreeListEntry* SvHeaderTabListBox::InsertEntryToColumn(
553     const OUString& rStr, SvTreeListEntry* pParent, sal_uInt32 nPos, sal_uInt16 nCol, void* pUserData )
554 {
555     SvTreeListEntry* pEntry = SvTabListBox::InsertEntryToColumn( rStr, pParent, nPos, nCol, pUserData );
556     RecalculateAccessibleChildren();
557     return pEntry;
558 }
559 
InsertEntryToColumn(const OUString & rStr,const Image & rExpandedEntryBmp,const Image & rCollapsedEntryBmp,SvTreeListEntry * pParent,sal_uInt32 nPos,sal_uInt16 nCol,void * pUserData)560 SvTreeListEntry* SvHeaderTabListBox::InsertEntryToColumn(
561     const OUString& rStr, const Image& rExpandedEntryBmp, const Image& rCollapsedEntryBmp,
562     SvTreeListEntry* pParent, sal_uInt32 nPos, sal_uInt16 nCol, void* pUserData )
563 {
564     SvTreeListEntry* pEntry = SvTabListBox::InsertEntryToColumn(
565         rStr, rExpandedEntryBmp, rCollapsedEntryBmp, pParent, nPos, nCol, pUserData );
566     RecalculateAccessibleChildren();
567     return pEntry;
568 }
569 
Insert(SvTreeListEntry * pEnt,SvTreeListEntry * pPar,sal_uInt32 nPos)570 sal_uInt32 SvHeaderTabListBox::Insert(
571     SvTreeListEntry* pEnt, SvTreeListEntry* pPar, sal_uInt32 nPos )
572 {
573     sal_uInt32 n = SvTabListBox::Insert( pEnt, pPar, nPos );
574     RecalculateAccessibleChildren();
575     return n;
576 }
577 
Insert(SvTreeListEntry * pEntry,sal_uInt32 nRootPos)578 sal_uInt32 SvHeaderTabListBox::Insert( SvTreeListEntry* pEntry, sal_uInt32 nRootPos )
579 {
580     sal_uInt32 nPos = SvTabListBox::Insert( pEntry, nRootPos );
581     RecalculateAccessibleChildren();
582     return nPos;
583 }
584 
DumpAsPropertyTree(tools::JsonWriter & rJsonWriter)585 void SvHeaderTabListBox::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter)
586 {
587     SvTabListBox::DumpAsPropertyTree(rJsonWriter);
588 
589     auto aHeaders = rJsonWriter.startArray("headers");
590 
591     HeaderBar* pHeaderBar = GetHeaderBar();
592     for(sal_uInt16 i = 0; i < pHeaderBar->GetItemCount(); i++)
593     {
594         auto aNode = rJsonWriter.startStruct();
595         rJsonWriter.put("text", pHeaderBar->GetItemText(pHeaderBar->GetItemId(i)));
596     }
597 }
598 
IMPL_LINK_NOARG(SvHeaderTabListBox,ScrollHdl_Impl,SvTreeListBox *,void)599 IMPL_LINK_NOARG(SvHeaderTabListBox, ScrollHdl_Impl, SvTreeListBox*, void)
600 {
601     m_pImpl->m_pHeaderBar->SetOffset( -GetXOffset() );
602 }
603 
IMPL_LINK_NOARG(SvHeaderTabListBox,CreateAccessibleHdl_Impl,HeaderBar *,void)604 IMPL_LINK_NOARG(SvHeaderTabListBox, CreateAccessibleHdl_Impl, HeaderBar*, void)
605 {
606     vcl::Window* pParent = m_pImpl->m_pHeaderBar->GetAccessibleParentWindow();
607     DBG_ASSERT( pParent, "SvHeaderTabListBox..CreateAccessibleHdl_Impl - accessible parent not found" );
608     if ( pParent )
609     {
610         css::uno::Reference< XAccessible > xAccParent = pParent->GetAccessible();
611         if ( xAccParent.is() )
612         {
613             Reference< XAccessible > xAccessible = m_pImpl->m_aFactoryAccess.getFactory().createAccessibleBrowseBoxHeaderBar(
614                 xAccParent, *this, ::vcl::BBTYPE_COLUMNHEADERBAR );
615             m_pImpl->m_pHeaderBar->SetAccessible( xAccessible );
616         }
617     }
618 }
619 
RecalculateAccessibleChildren()620 void SvHeaderTabListBox::RecalculateAccessibleChildren()
621 {
622     if ( !m_aAccessibleChildren.empty() )
623     {
624         sal_uInt32 nCount = ( GetRowCount() + 1 ) * GetColumnCount();
625         if ( m_aAccessibleChildren.size() < nCount )
626             m_aAccessibleChildren.resize( nCount );
627         else
628         {
629             DBG_ASSERT( m_aAccessibleChildren.size() == nCount, "wrong children count" );
630         }
631     }
632 }
633 
IsCellCheckBox(sal_Int32 _nRow,sal_uInt16 _nColumn,TriState & _rState)634 bool SvHeaderTabListBox::IsCellCheckBox( sal_Int32 _nRow, sal_uInt16 _nColumn, TriState& _rState )
635 {
636     bool bRet = false;
637     SvTreeListEntry* pEntry = GetEntry( _nRow );
638     if ( pEntry )
639     {
640         sal_uInt16 nItemCount = pEntry->ItemCount();
641         if ( nItemCount > ( _nColumn + 1 ) )
642         {
643             SvLBoxItem& rItem = pEntry->GetItem( _nColumn + 1 );
644             if (rItem.GetType() == SvLBoxItemType::Button)
645             {
646                 bRet = true;
647                 _rState = ( ( static_cast<SvLBoxButton&>(rItem).GetButtonFlags() & SvItemStateFlags::UNCHECKED ) == SvItemStateFlags::NONE )
648                             ? TRISTATE_TRUE : TRISTATE_FALSE;
649             }
650         }
651         else
652         {
653             SAL_WARN( "svtools.contnr", "SvHeaderTabListBox::IsCellCheckBox(): column out of range" );
654         }
655     }
656     return bRet;
657 }
GetRowCount() const658 sal_Int32 SvHeaderTabListBox::GetRowCount() const
659 {
660     return GetEntryCount();
661 }
662 
GetColumnCount() const663 sal_uInt16 SvHeaderTabListBox::GetColumnCount() const
664 {
665     return m_pImpl->m_pHeaderBar->GetItemCount();
666 }
667 
GetCurrRow() const668 sal_Int32 SvHeaderTabListBox::GetCurrRow() const
669 {
670     sal_Int32 nRet = -1;
671     SvTreeListEntry* pEntry = GetCurEntry();
672     if ( pEntry )
673     {
674         sal_uInt32 nCount = GetEntryCount();
675         for ( sal_uInt32 i = 0; i < nCount; ++i )
676         {
677             if ( pEntry == GetEntry(i) )
678             {
679                 nRet = i;
680                 break;
681             }
682         }
683     }
684 
685     return nRet;
686 }
687 
GetCurrColumn() const688 sal_uInt16 SvHeaderTabListBox::GetCurrColumn() const
689 {
690     return 0;
691 }
692 
GetRowDescription(sal_Int32 _nRow) const693 OUString SvHeaderTabListBox::GetRowDescription( sal_Int32 _nRow ) const
694 {
695     return GetEntryText( _nRow );
696 }
697 
GetColumnDescription(sal_uInt16 _nColumn) const698 OUString SvHeaderTabListBox::GetColumnDescription( sal_uInt16 _nColumn ) const
699 {
700     return m_pImpl->m_pHeaderBar->GetItemText( m_pImpl->m_pHeaderBar->GetItemId( _nColumn ) );
701 }
702 
HasRowHeader() const703 bool SvHeaderTabListBox::HasRowHeader() const
704 {
705     return false;
706 }
707 
GoToCell(sal_Int32,sal_uInt16)708 bool SvHeaderTabListBox::GoToCell( sal_Int32 /*_nRow*/, sal_uInt16 /*_nColumn*/ )
709 {
710     return false;
711 }
712 
SetNoSelection()713 void SvHeaderTabListBox::SetNoSelection()
714 {
715     SvTreeListBox::SelectAll(false);
716 }
717 
SelectAll()718 void SvHeaderTabListBox::SelectAll()
719 {
720     SvTreeListBox::SelectAll(true);
721 }
722 
SelectRow(sal_Int32 _nRow,bool _bSelect,bool)723 void SvHeaderTabListBox::SelectRow( sal_Int32 _nRow, bool _bSelect, bool )
724 {
725     Select( GetEntry( _nRow ), _bSelect );
726 }
727 
SelectColumn(sal_uInt16,bool)728 void SvHeaderTabListBox::SelectColumn( sal_uInt16, bool )
729 {
730 }
731 
GetSelectedRowCount() const732 sal_Int32 SvHeaderTabListBox::GetSelectedRowCount() const
733 {
734     return GetSelectionCount();
735 }
736 
GetSelectedColumnCount() const737 sal_Int32 SvHeaderTabListBox::GetSelectedColumnCount() const
738 {
739     return 0;
740 }
741 
IsRowSelected(sal_Int32 _nRow) const742 bool SvHeaderTabListBox::IsRowSelected( sal_Int32 _nRow ) const
743 {
744     SvTreeListEntry* pEntry = GetEntry( _nRow );
745     return ( pEntry && IsSelected( pEntry ) );
746 }
747 
IsColumnSelected(sal_Int32) const748 bool SvHeaderTabListBox::IsColumnSelected( sal_Int32 ) const
749 {
750     return false;
751 }
752 
GetAllSelectedRows(css::uno::Sequence<sal_Int32> &) const753 void SvHeaderTabListBox::GetAllSelectedRows( css::uno::Sequence< sal_Int32 >& ) const
754 {
755 }
756 
GetAllSelectedColumns(css::uno::Sequence<sal_Int32> &) const757 void SvHeaderTabListBox::GetAllSelectedColumns( css::uno::Sequence< sal_Int32 >& ) const
758 {
759 }
760 
IsCellVisible(sal_Int32,sal_uInt16) const761 bool SvHeaderTabListBox::IsCellVisible( sal_Int32, sal_uInt16 ) const
762 {
763     return true;
764 }
765 
GetAccessibleCellText(sal_Int32 _nRow,sal_uInt16 _nColumnPos) const766 OUString SvHeaderTabListBox::GetAccessibleCellText( sal_Int32 _nRow, sal_uInt16 _nColumnPos ) const
767 {
768     return GetTabEntryText(_nRow, _nColumnPos);
769 }
770 
calcHeaderRect(bool _bIsColumnBar,bool _bOnScreen)771 tools::Rectangle SvHeaderTabListBox::calcHeaderRect( bool _bIsColumnBar, bool _bOnScreen )
772 {
773     tools::Rectangle aRect;
774     if ( _bIsColumnBar )
775     {
776         vcl::Window* pParent = nullptr;
777         if ( !_bOnScreen )
778             pParent = m_pImpl->m_pHeaderBar->GetAccessibleParentWindow();
779 
780         aRect = m_pImpl->m_pHeaderBar->GetWindowExtentsRelative( pParent );
781     }
782     return aRect;
783 }
784 
calcTableRect(bool _bOnScreen)785 tools::Rectangle SvHeaderTabListBox::calcTableRect( bool _bOnScreen )
786 {
787     vcl::Window* pParent = nullptr;
788     if ( !_bOnScreen )
789         pParent = GetAccessibleParentWindow();
790 
791     tools::Rectangle aRect( GetWindowExtentsRelative( pParent ) );
792     return aRect;
793 }
794 
GetFieldRectPixelAbs(sal_Int32 _nRow,sal_uInt16 _nColumn,bool _bIsHeader,bool _bOnScreen)795 tools::Rectangle SvHeaderTabListBox::GetFieldRectPixelAbs( sal_Int32 _nRow, sal_uInt16 _nColumn, bool _bIsHeader, bool _bOnScreen )
796 {
797     DBG_ASSERT( !_bIsHeader || 0 == _nRow, "invalid parameters" );
798     tools::Rectangle aRect;
799     SvTreeListEntry* pEntry = GetEntry( _nRow );
800     if ( pEntry )
801     {
802         aRect = _bIsHeader ? calcHeaderRect( true, false ) : GetBoundingRect( pEntry );
803         Point aTopLeft = aRect.TopLeft();
804         DBG_ASSERT( m_pImpl->m_pHeaderBar->GetItemCount() > _nColumn, "invalid column" );
805         tools::Rectangle aItemRect = m_pImpl->m_pHeaderBar->GetItemRect( m_pImpl->m_pHeaderBar->GetItemId( _nColumn ) );
806         aTopLeft.setX( aItemRect.Left() );
807         Size aSize = aItemRect.GetSize();
808         aRect = tools::Rectangle( aTopLeft, aSize );
809         vcl::Window* pParent = nullptr;
810         if ( !_bOnScreen )
811             pParent = GetAccessibleParentWindow();
812         aTopLeft = aRect.TopLeft();
813         aTopLeft += GetWindowExtentsRelative( pParent ).TopLeft();
814         aRect = tools::Rectangle( aTopLeft, aRect.GetSize() );
815     }
816 
817     return aRect;
818 }
819 
CreateAccessibleCell(sal_Int32 _nRow,sal_uInt16 _nColumnPos)820 Reference< XAccessible > SvHeaderTabListBox::CreateAccessibleCell( sal_Int32 _nRow, sal_uInt16 _nColumnPos )
821 {
822     OSL_ENSURE( m_pAccessible, "Invalid call: Accessible is null" );
823 
824     Reference< XAccessible > xChild;
825 
826     TriState eState = TRISTATE_INDET;
827     bool bIsCheckBox = IsCellCheckBox( _nRow, _nColumnPos, eState );
828     if ( bIsCheckBox )
829         xChild = m_pImpl->m_aFactoryAccess.getFactory().createAccessibleCheckBoxCell(
830                 m_pAccessible->getHeaderBar(), *this, nullptr, _nRow, _nColumnPos, eState, false );
831     else
832         xChild = m_pImpl->m_aFactoryAccess.getFactory().createAccessibleBrowseBoxTableCell(
833                 m_pAccessible->getHeaderBar(), *this, nullptr, _nRow, _nColumnPos, OFFSET_NONE );
834 
835     return xChild;
836 }
837 
CreateAccessibleRowHeader(sal_Int32)838 Reference< XAccessible > SvHeaderTabListBox::CreateAccessibleRowHeader( sal_Int32 )
839 {
840     Reference< XAccessible > xHeader;
841     return xHeader;
842 }
843 
CreateAccessibleColumnHeader(sal_uInt16 _nColumn)844 Reference< XAccessible > SvHeaderTabListBox::CreateAccessibleColumnHeader( sal_uInt16 _nColumn )
845 {
846     // first call? -> initial list
847     if ( m_aAccessibleChildren.empty() )
848     {
849         const sal_uInt16 nColumnCount = GetColumnCount();
850         m_aAccessibleChildren.assign( nColumnCount, Reference< XAccessible >() );
851     }
852 
853     // get header
854     Reference< XAccessible > xChild = m_aAccessibleChildren[ _nColumn ];
855     // already exists?
856     if ( !xChild.is() && m_pAccessible )
857     {
858         // no -> create new header cell
859         xChild = m_pImpl->m_aFactoryAccess.getFactory().createAccessibleBrowseBoxHeaderCell(
860             _nColumn, m_pAccessible->getHeaderBar(),
861             *this, nullptr, ::vcl::BBTYPE_COLUMNHEADERCELL
862         );
863 
864         // insert into list
865         m_aAccessibleChildren[ _nColumn ] = xChild;
866     }
867     return xChild;
868 }
869 
GetAccessibleControlCount() const870 sal_Int32 SvHeaderTabListBox::GetAccessibleControlCount() const
871 {
872     return -1;
873 }
874 
CreateAccessibleControl(sal_Int32)875 Reference< XAccessible > SvHeaderTabListBox::CreateAccessibleControl( sal_Int32 )
876 {
877     Reference< XAccessible > xControl;
878     return xControl;
879 }
880 
ConvertPointToControlIndex(sal_Int32 &,const Point &)881 bool SvHeaderTabListBox::ConvertPointToControlIndex( sal_Int32&, const Point& )
882 {
883     return false;
884 }
885 
ConvertPointToCellAddress(sal_Int32 &,sal_uInt16 &,const Point &)886 bool SvHeaderTabListBox::ConvertPointToCellAddress( sal_Int32&, sal_uInt16&, const Point& )
887 {
888     return false;
889 }
890 
ConvertPointToRowHeader(sal_Int32 &,const Point &)891 bool SvHeaderTabListBox::ConvertPointToRowHeader( sal_Int32&, const Point& )
892 {
893     return false;
894 }
895 
ConvertPointToColumnHeader(sal_uInt16 &,const Point &)896 bool SvHeaderTabListBox::ConvertPointToColumnHeader( sal_uInt16&, const Point& )
897 {
898     return false;
899 }
900 
GetAccessibleObjectName(::vcl::AccessibleBrowseBoxObjType _eType,sal_Int32 _nPos) const901 OUString SvHeaderTabListBox::GetAccessibleObjectName( ::vcl::AccessibleBrowseBoxObjType _eType, sal_Int32 _nPos ) const
902 {
903     OUString aRetText;
904     switch( _eType )
905     {
906         case ::vcl::BBTYPE_BROWSEBOX:
907         case ::vcl::BBTYPE_TABLE:
908         case ::vcl::BBTYPE_COLUMNHEADERBAR:
909             // should be empty now (see #i63983)
910             aRetText.clear();
911             break;
912 
913         case ::vcl::BBTYPE_TABLECELL:
914         {
915             // here we need a valid pos, we can not handle -1
916             if ( _nPos >= 0 )
917             {
918                 sal_uInt16 nColumnCount = GetColumnCount();
919                 if (nColumnCount > 0)
920                 {
921                     sal_Int32 nRow = _nPos / nColumnCount;
922                     sal_uInt16 nColumn  = static_cast< sal_uInt16 >( _nPos % nColumnCount );
923                     aRetText = GetCellText( nRow, nColumn );
924                 }
925             }
926             break;
927         }
928         case ::vcl::BBTYPE_CHECKBOXCELL:
929         {
930             break; // checkbox cells have no name
931         }
932         case ::vcl::BBTYPE_COLUMNHEADERCELL:
933         {
934             aRetText = m_pImpl->m_pHeaderBar->GetItemText( m_pImpl->m_pHeaderBar->GetItemId( static_cast<sal_uInt16>(_nPos) ) );
935             break;
936         }
937 
938         case ::vcl::BBTYPE_ROWHEADERBAR:
939         case ::vcl::BBTYPE_ROWHEADERCELL:
940             aRetText = "error";
941             break;
942 
943         default:
944             OSL_FAIL("BrowseBox::GetAccessibleName: invalid enum!");
945     }
946     return aRetText;
947 }
948 
GetAccessibleObjectDescription(::vcl::AccessibleBrowseBoxObjType _eType,sal_Int32 _nPos) const949 OUString SvHeaderTabListBox::GetAccessibleObjectDescription( ::vcl::AccessibleBrowseBoxObjType _eType, sal_Int32 _nPos ) const
950 {
951     OUString aRetText;
952 
953     if( _eType == ::vcl::BBTYPE_TABLECELL && _nPos != -1 )
954     {
955         sal_uInt16 nColumnCount = GetColumnCount();
956         if (nColumnCount > 0)
957         {
958             sal_Int32 nRow = _nPos / nColumnCount;
959             sal_uInt16 nColumn  = static_cast< sal_uInt16 >( _nPos % nColumnCount );
960 
961             OUString aText( VclResId(STR_SVT_ACC_DESC_TABLISTBOX) );
962             aText = aText.replaceFirst( "%1", OUString::number( nRow ) );
963             OUString sColHeader = m_pImpl->m_pHeaderBar->GetItemText( m_pImpl->m_pHeaderBar->GetItemId( nColumn ) );
964             if ( sColHeader.isEmpty() )
965                 sColHeader = OUString::number( nColumn );
966             aText = aText.replaceFirst( "%2", sColHeader );
967             aRetText = aText;
968         }
969     }
970 
971     return aRetText;
972 }
973 
FillAccessibleStateSet(::utl::AccessibleStateSetHelper & _rStateSet,::vcl::AccessibleBrowseBoxObjType _eType) const974 void SvHeaderTabListBox::FillAccessibleStateSet( ::utl::AccessibleStateSetHelper& _rStateSet, ::vcl::AccessibleBrowseBoxObjType _eType ) const
975 {
976     switch( _eType )
977     {
978         case ::vcl::BBTYPE_BROWSEBOX:
979         case ::vcl::BBTYPE_TABLE:
980         {
981             _rStateSet.AddState( AccessibleStateType::FOCUSABLE );
982             if ( HasFocus() )
983                 _rStateSet.AddState( AccessibleStateType::FOCUSED );
984             if ( IsActive() )
985                 _rStateSet.AddState( AccessibleStateType::ACTIVE );
986             if ( IsEnabled() )
987             {
988                 _rStateSet.AddState( AccessibleStateType::ENABLED );
989                 _rStateSet.AddState( AccessibleStateType::SENSITIVE );
990             }
991             if ( IsReallyVisible() )
992                 _rStateSet.AddState( AccessibleStateType::VISIBLE );
993             if ( _eType == ::vcl::BBTYPE_TABLE )
994             {
995 
996                 _rStateSet.AddState( AccessibleStateType::MANAGES_DESCENDANTS );
997                 _rStateSet.AddState( AccessibleStateType::MULTI_SELECTABLE );
998             }
999             break;
1000         }
1001 
1002         case ::vcl::BBTYPE_COLUMNHEADERBAR:
1003         {
1004             sal_Int32 nCurRow = GetCurrRow();
1005             sal_uInt16 nCurColumn = GetCurrColumn();
1006             if ( IsCellVisible( nCurRow, nCurColumn ) )
1007                 _rStateSet.AddState( AccessibleStateType::VISIBLE );
1008             if ( IsEnabled() )
1009                 _rStateSet.AddState( AccessibleStateType::ENABLED );
1010             _rStateSet.AddState( AccessibleStateType::TRANSIENT );
1011             break;
1012         }
1013 
1014         case ::vcl::BBTYPE_ROWHEADERCELL:
1015         case ::vcl::BBTYPE_COLUMNHEADERCELL:
1016         {
1017             _rStateSet.AddState( AccessibleStateType::VISIBLE );
1018             _rStateSet.AddState( AccessibleStateType::FOCUSABLE );
1019             _rStateSet.AddState( AccessibleStateType::TRANSIENT );
1020             if ( IsEnabled() )
1021                 _rStateSet.AddState( AccessibleStateType::ENABLED );
1022             break;
1023         }
1024         default:
1025             break;
1026     }
1027 }
1028 
FillAccessibleStateSetForCell(::utl::AccessibleStateSetHelper & _rStateSet,sal_Int32 _nRow,sal_uInt16 _nColumn) const1029 void SvHeaderTabListBox::FillAccessibleStateSetForCell( ::utl::AccessibleStateSetHelper& _rStateSet, sal_Int32 _nRow, sal_uInt16 _nColumn ) const
1030 {
1031     _rStateSet.AddState( AccessibleStateType::SELECTABLE );
1032     _rStateSet.AddState( AccessibleStateType::TRANSIENT );
1033 
1034     if ( IsCellVisible( _nRow, _nColumn ) )
1035     {
1036         _rStateSet.AddState( AccessibleStateType::VISIBLE );
1037         _rStateSet.AddState( AccessibleStateType::ENABLED );
1038     }
1039 
1040     if ( IsRowSelected( _nRow ) )
1041     {
1042         _rStateSet.AddState( AccessibleStateType::ACTIVE );
1043         _rStateSet.AddState( AccessibleStateType::SELECTED );
1044     }
1045     if ( IsEnabled() )
1046         _rStateSet.AddState( AccessibleStateType::ENABLED );
1047 }
1048 
GrabTableFocus()1049 void SvHeaderTabListBox::GrabTableFocus()
1050 {
1051     GrabFocus();
1052 }
1053 
GetGlyphBoundRects(const Point & rOrigin,const OUString & rStr,int nIndex,int nLen,std::vector<tools::Rectangle> & rVector)1054 bool SvHeaderTabListBox::GetGlyphBoundRects( const Point& rOrigin, const OUString& rStr, int nIndex, int nLen, std::vector< tools::Rectangle >& rVector )
1055 {
1056     return GetOutDev()->GetGlyphBoundRects( rOrigin, rStr, nIndex, nLen, rVector );
1057 }
1058 
GetWindowExtentsRelative(const vcl::Window * pRelativeWindow) const1059 tools::Rectangle SvHeaderTabListBox::GetWindowExtentsRelative(const vcl::Window *pRelativeWindow) const
1060 {
1061     return Control::GetWindowExtentsRelative( pRelativeWindow );
1062 }
1063 
GrabFocus()1064 void SvHeaderTabListBox::GrabFocus()
1065 {
1066     Control::GrabFocus();
1067 }
1068 
GetAccessible()1069 Reference< XAccessible > SvHeaderTabListBox::GetAccessible()
1070 {
1071     return Control::GetAccessible();
1072 }
1073 
GetAccessibleParentWindow() const1074 vcl::Window* SvHeaderTabListBox::GetAccessibleParentWindow() const
1075 {
1076     return Control::GetAccessibleParentWindow();
1077 }
1078 
GetWindowInstance()1079 vcl::Window* SvHeaderTabListBox::GetWindowInstance()
1080 {
1081     return this;
1082 }
1083 
CreateAccessible()1084 Reference< XAccessible > SvHeaderTabListBox::CreateAccessible()
1085 {
1086     vcl::Window* pParent = GetAccessibleParentWindow();
1087     DBG_ASSERT( pParent, "SvHeaderTabListBox::::CreateAccessible - accessible parent not found" );
1088 
1089     Reference< XAccessible > xAccessible;
1090     if ( m_pAccessible ) xAccessible = m_pAccessible->getMyself();
1091 
1092     if( pParent && !m_pAccessible )
1093     {
1094         Reference< XAccessible > xAccParent = pParent->GetAccessible();
1095         if ( xAccParent.is() )
1096         {
1097             m_pAccessible = m_pImpl->m_aFactoryAccess.getFactory().createAccessibleTabListBox( xAccParent, *this );
1098             if ( m_pAccessible )
1099                 xAccessible = m_pAccessible->getMyself();
1100         }
1101     }
1102     return xAccessible;
1103 }
1104 
GetFieldCharacterBounds(sal_Int32,sal_Int32,sal_Int32)1105 tools::Rectangle SvHeaderTabListBox::GetFieldCharacterBounds(sal_Int32,sal_Int32,sal_Int32)
1106 {
1107     return tools::Rectangle();
1108 }
1109 
GetFieldIndexAtPoint(sal_Int32 _nRow,sal_Int32 _nColumnPos,const Point & _rPoint)1110 sal_Int32 SvHeaderTabListBox::GetFieldIndexAtPoint(sal_Int32 _nRow,sal_Int32 _nColumnPos,const Point& _rPoint)
1111 {
1112     OUString sText = GetAccessibleCellText( _nRow, static_cast< sal_uInt16 >( _nColumnPos ) );
1113     std::vector< tools::Rectangle > aRects;
1114     if ( GetGlyphBoundRects(Point(0,0), sText, 0, sText.getLength(), aRects) )
1115     {
1116         sal_Int32 nPos = 0;
1117         for (auto const& rectangle : aRects)
1118         {
1119             if( rectangle.IsInside(_rPoint) )
1120                 return nPos;
1121             ++nPos;
1122         }
1123     }
1124 
1125     return -1;
1126 }
1127 
1128 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1129