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