/src/libreoffice/vcl/source/treelist/svtabbx.cxx
Line | Count | Source |
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 <accessibility/accessibletablistbox.hxx> |
21 | | |
22 | | #include <comphelper/types.hxx> |
23 | | #include <vcl/toolkit/svtabbx.hxx> |
24 | | #include <vcl/headbar.hxx> |
25 | | #include <vcl/toolkit/svlbitm.hxx> |
26 | | #include <vcl/toolkit/treelistbox.hxx> |
27 | | #include <vcl/toolkit/treelistentry.hxx> |
28 | | #include <com/sun/star/accessibility/AccessibleStateType.hpp> |
29 | | #include <com/sun/star/accessibility/XAccessible.hpp> |
30 | | #include <rtl/ustrbuf.hxx> |
31 | | #include <sal/log.hxx> |
32 | | #include <o3tl/safeint.hxx> |
33 | | #include <o3tl/string_view.hxx> |
34 | | #include <osl/diagnose.h> |
35 | | #include <strings.hrc> |
36 | | #include <svdata.hxx> |
37 | | #include <memory> |
38 | | #include <tools/json_writer.hxx> |
39 | | #include <comphelper/propertyvalue.hxx> |
40 | | #include <vcl/accessibility/AccessibleBrowseBoxCheckBoxCell.hxx> |
41 | | #include <vcl/accessibility/AccessibleBrowseBoxHeaderBar.hxx> |
42 | | #include <vcl/accessibility/AccessibleBrowseBoxHeaderCell.hxx> |
43 | | #include <vcl/accessibility/AccessibleBrowseBoxTableCell.hxx> |
44 | | #include <vcl/filter/PngImageWriter.hxx> |
45 | | #include <comphelper/base64.hxx> |
46 | | |
47 | | using namespace ::com::sun::star::uno; |
48 | | using namespace ::com::sun::star::accessibility; |
49 | | |
50 | | namespace { |
51 | | OString lcl_extractPngString(const Bitmap& rImage) |
52 | 0 | { |
53 | 0 | SvMemoryStream aOStm(65535, 65535); |
54 | | // Use fastest compression "1" |
55 | 0 | css::uno::Sequence<css::beans::PropertyValue> aFilterData{ |
56 | 0 | comphelper::makePropertyValue(u"Compression"_ustr, sal_Int32(1)), |
57 | 0 | }; |
58 | 0 | vcl::PngImageWriter aPNGWriter(aOStm); |
59 | 0 | aPNGWriter.setParameters(aFilterData); |
60 | 0 | if (aPNGWriter.write(rImage)) |
61 | 0 | { |
62 | 0 | css::uno::Sequence<sal_Int8> aSeq(static_cast<sal_Int8 const*>(aOStm.GetData()), |
63 | 0 | aOStm.Tell()); |
64 | 0 | OStringBuffer aBuffer("data:image/png;base64,"); |
65 | 0 | ::comphelper::Base64::encode(aBuffer, aSeq); |
66 | 0 | return aBuffer.makeStringAndClear(); |
67 | 0 | } |
68 | | |
69 | 0 | return ""_ostr; |
70 | 0 | } |
71 | | } |
72 | | |
73 | | static void lcl_DumpEntryAndSiblings(tools::JsonWriter& rJsonWriter, |
74 | | SvTreeListEntry* pEntry, |
75 | | SvTabListBox* pTabListBox, |
76 | | bool bCheckButtons) |
77 | 0 | { |
78 | 0 | while (pEntry) |
79 | 0 | { |
80 | 0 | auto aNode = rJsonWriter.startStruct(); |
81 | | |
82 | | // DEPRECATED |
83 | | // simple listbox value |
84 | 0 | const SvLBoxItem* pIt = pEntry->GetFirstItem(SvLBoxItemType::String); |
85 | 0 | if (pIt) |
86 | 0 | rJsonWriter.put("text", static_cast<const SvLBoxString*>(pIt)->GetText()); |
87 | | |
88 | | // column based data |
89 | 0 | { |
90 | 0 | auto aColumns = rJsonWriter.startArray("columns"); |
91 | |
|
92 | 0 | for (size_t i = 0; i < pEntry->ItemCount(); i++) |
93 | 0 | { |
94 | 0 | SvLBoxItem& rItem = pEntry->GetItem(i); |
95 | 0 | if (rItem.GetType() == SvLBoxItemType::String) |
96 | 0 | { |
97 | 0 | const SvLBoxString* pStringItem = dynamic_cast<const SvLBoxString*>(&rItem); |
98 | 0 | if (pStringItem) |
99 | 0 | { |
100 | 0 | auto aColumn = rJsonWriter.startStruct(); |
101 | 0 | rJsonWriter.put("text", pStringItem->GetText()); |
102 | |
|
103 | 0 | SvLBoxTab* pTab = pTabListBox->GetTab( pEntry, &rItem ); |
104 | 0 | if ( pTab ) |
105 | 0 | rJsonWriter.put("editable", pTab->IsEditable()); |
106 | |
|
107 | 0 | if (pStringItem->IsCustomRender()) |
108 | 0 | rJsonWriter.put("customEntryRenderer", true); |
109 | 0 | } |
110 | 0 | } |
111 | 0 | else if (rItem.GetType() == SvLBoxItemType::ContextBmp) |
112 | 0 | { |
113 | 0 | const SvLBoxContextBmp* pBmpItem = dynamic_cast<const SvLBoxContextBmp*>(&rItem); |
114 | 0 | if (pBmpItem) |
115 | 0 | { |
116 | 0 | const OUString aCollapsed = pBmpItem->GetBitmap1().GetStock(); |
117 | 0 | const OUString aExpanded = pBmpItem->GetBitmap2().GetStock(); |
118 | | |
119 | | // send identifier only, we will use svg icon |
120 | 0 | if (!o3tl::trim(aCollapsed).empty() || !o3tl::trim(aExpanded).empty()) |
121 | 0 | { |
122 | 0 | auto aColumn = rJsonWriter.startStruct(); |
123 | 0 | if (!o3tl::trim(aCollapsed).empty()) |
124 | 0 | rJsonWriter.put("collapsed", aCollapsed); |
125 | 0 | if (!o3tl::trim(aExpanded).empty()) |
126 | 0 | rJsonWriter.put("expanded", aExpanded); |
127 | 0 | } |
128 | | // custom bitmap - send png |
129 | 0 | else |
130 | 0 | { |
131 | 0 | Bitmap aCollapsedImage(pBmpItem->GetBitmap1().GetBitmap()); |
132 | 0 | Bitmap aExpandedImage(pBmpItem->GetBitmap2().GetBitmap()); |
133 | 0 | bool bHasCollapsed = !aCollapsedImage.IsEmpty() && !aCollapsedImage.GetSizePixel().IsEmpty(); |
134 | 0 | bool bHasExpanded = !aExpandedImage.IsEmpty() && !aExpandedImage.GetSizePixel().IsEmpty(); |
135 | 0 | if (bHasCollapsed || bHasExpanded) |
136 | 0 | { |
137 | 0 | auto aColumn = rJsonWriter.startStruct(); |
138 | 0 | if (bHasCollapsed) |
139 | 0 | rJsonWriter.put("collapsedimage", lcl_extractPngString(aCollapsedImage)); |
140 | 0 | if (bHasExpanded) |
141 | 0 | rJsonWriter.put("collapsedimage", lcl_extractPngString(aExpandedImage)); |
142 | 0 | } |
143 | 0 | } |
144 | 0 | } |
145 | 0 | } |
146 | 0 | } |
147 | 0 | } |
148 | | |
149 | | // SalInstanceTreeView does not use the flag CHILDREN_ON_DEMAND |
150 | | // and it creates a dummy child |
151 | 0 | const SvTreeListEntries& rChildren = pEntry->GetChildEntries(); |
152 | 0 | if (rChildren.size() == 1) |
153 | 0 | { |
154 | 0 | auto& rChild = rChildren[0]; |
155 | 0 | if (const SvLBoxItem* pChild = rChild->GetFirstItem(SvLBoxItemType::String)) |
156 | 0 | { |
157 | 0 | if (static_cast<const SvLBoxString*>(pChild)->GetText() == "<dummy>") |
158 | 0 | rJsonWriter.put("ondemand", true); |
159 | 0 | } |
160 | 0 | } |
161 | 0 | if (rChildren.size() > 0 && !pTabListBox->IsExpanded(pEntry)) |
162 | 0 | { |
163 | 0 | rJsonWriter.put("collapsed", true); |
164 | 0 | } |
165 | |
|
166 | 0 | if (bCheckButtons) |
167 | 0 | { |
168 | 0 | SvButtonState eCheckState = pTabListBox->GetCheckButtonState(pEntry); |
169 | 0 | if (eCheckState == SvButtonState::Unchecked) |
170 | 0 | rJsonWriter.put("state", false); |
171 | 0 | else if (eCheckState == SvButtonState::Checked) |
172 | 0 | rJsonWriter.put("state", true); |
173 | 0 | rJsonWriter.put("enabled", pTabListBox->GetCheckButtonEnabled(pEntry)); |
174 | 0 | } |
175 | |
|
176 | 0 | if (pTabListBox->IsSelected(pEntry)) |
177 | 0 | rJsonWriter.put("selected", true); |
178 | |
|
179 | 0 | rJsonWriter.put("row", pTabListBox->GetModel()->GetAbsPos(pEntry)); |
180 | |
|
181 | 0 | SvTreeListEntry* pChild = pTabListBox->FirstChild(pEntry); |
182 | 0 | if (pChild) |
183 | 0 | { |
184 | 0 | auto childrenNode = rJsonWriter.startArray("children"); |
185 | 0 | lcl_DumpEntryAndSiblings(rJsonWriter, pChild, pTabListBox, bCheckButtons); |
186 | 0 | } |
187 | |
|
188 | 0 | pEntry = pEntry->NextSibling(); |
189 | 0 | } |
190 | 0 | } |
191 | | |
192 | | void SvTabListBox::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter) |
193 | 0 | { |
194 | 0 | SvTreeListBox::DumpAsPropertyTree(rJsonWriter); |
195 | |
|
196 | 0 | rJsonWriter.put("singleclickactivate", GetActivateOnSingleClick()); |
197 | |
|
198 | 0 | switch (m_eRole) |
199 | 0 | { |
200 | 0 | case SvTabListBoxRole::Unknown: |
201 | 0 | assert(false && "this shouldn't be possible on load from .ui"); |
202 | 0 | break; |
203 | 0 | case SvTabListBoxRole::Tree: |
204 | 0 | rJsonWriter.put("role", "tree"); |
205 | 0 | break; |
206 | 0 | case SvTabListBoxRole::TreeGrid: |
207 | 0 | rJsonWriter.put("role", "treegrid"); |
208 | 0 | break; |
209 | 0 | case SvTabListBoxRole::ListBox: |
210 | 0 | rJsonWriter.put("role", "listbox"); |
211 | 0 | break; |
212 | 0 | case SvTabListBoxRole::Grid: |
213 | 0 | rJsonWriter.put("role", "grid"); |
214 | 0 | break; |
215 | 0 | } |
216 | | |
217 | 0 | bool bCheckButtons = static_cast<int>(m_nTreeFlags & SvTreeFlags::CHKBTN); |
218 | |
|
219 | 0 | bool isRadioButton = false; |
220 | 0 | if (m_pCheckButtonData) |
221 | 0 | { |
222 | 0 | isRadioButton = m_pCheckButtonData->IsRadio(); |
223 | 0 | } |
224 | |
|
225 | 0 | OUString checkboxtype; |
226 | 0 | if (bCheckButtons) |
227 | 0 | { |
228 | 0 | checkboxtype = "checkbox"; |
229 | 0 | if(isRadioButton) |
230 | 0 | { |
231 | 0 | checkboxtype = "radio"; |
232 | 0 | } |
233 | 0 | } |
234 | |
|
235 | 0 | rJsonWriter.put("checkboxtype", checkboxtype); |
236 | 0 | if (GetCustomEntryRenderer()) |
237 | 0 | rJsonWriter.put("customEntryRenderer", true); |
238 | 0 | auto entriesNode = rJsonWriter.startArray("entries"); |
239 | 0 | lcl_DumpEntryAndSiblings(rJsonWriter, First(), this, bCheckButtons); |
240 | 0 | } |
241 | | |
242 | | // SvTreeListBox callback |
243 | | |
244 | | void SvTabListBox::SetTabs() |
245 | 0 | { |
246 | 0 | SvTreeListBox::SetTabs(); |
247 | 0 | if( mvTabList.empty() ) |
248 | 0 | return; |
249 | | |
250 | | // The tree listbox has now inserted its tabs into the list. Now we |
251 | | // fluff up the list with additional tabs and adjust the rightmost tab |
252 | | // of the tree listbox. |
253 | | |
254 | | // the 1st column (index 1 or 2 depending on button flags) is always set |
255 | | // editable by SvTreeListBox::SetTabs(), |
256 | | // which prevents setting a different column to editable as the first |
257 | | // one with the flag is picked in SvTreeListBox::ImplEditEntry() |
258 | 0 | assert(m_aTabs.back()->nFlags & SvLBoxTabFlags::EDITABLE); |
259 | 0 | if (!(mvTabList[0].nFlags & SvLBoxTabFlags::EDITABLE)) |
260 | 0 | { |
261 | 0 | m_aTabs.back()->nFlags &= ~SvLBoxTabFlags::EDITABLE; |
262 | 0 | } |
263 | | |
264 | | // append all other tabs to the list |
265 | 0 | for( sal_uInt16 nCurTab = 1; nCurTab < sal_uInt16(mvTabList.size()); nCurTab++ ) |
266 | 0 | { |
267 | 0 | SvLBoxTab& rTab = mvTabList[nCurTab]; |
268 | 0 | AddTab( rTab.GetPos(), rTab.nFlags ); |
269 | 0 | } |
270 | 0 | } |
271 | | |
272 | | void SvTabListBox::InitEntry(SvTreeListEntry* pEntry, const OUString& rStr, |
273 | | const Image& rColl, const Image& rExp) |
274 | 0 | { |
275 | 0 | SvTreeListBox::InitEntry(pEntry, rStr, rColl, rExp); |
276 | |
|
277 | 0 | sal_Int32 nIndex = 0; |
278 | | // TODO: verify if nTabCount is always >0 here! |
279 | 0 | const sal_uInt16 nCount = mvTabList.size() - 1; |
280 | 0 | for( sal_uInt16 nToken = 0; nToken < nCount; nToken++ ) |
281 | 0 | { |
282 | 0 | const std::u16string_view aToken = GetToken(aCurEntry, nIndex); |
283 | 0 | pEntry->AddItem(std::make_unique<SvLBoxString>(OUString(aToken))); |
284 | 0 | } |
285 | 0 | } |
286 | | |
287 | | SvTabListBox::SvTabListBox( vcl::Window* pParent, WinBits nBits ) |
288 | 0 | : SvTreeListBox( pParent, nBits ) |
289 | 0 | , m_eRole(SvTabListBoxRole::Unknown) |
290 | 0 | { |
291 | 0 | SetHighlightRange(); // select full width |
292 | 0 | } Unexecuted instantiation: SvTabListBox::SvTabListBox(vcl::Window*, long) Unexecuted instantiation: SvTabListBox::SvTabListBox(vcl::Window*, long) |
293 | | |
294 | | SvTabListBox::~SvTabListBox() |
295 | 0 | { |
296 | 0 | disposeOnce(); |
297 | 0 | } |
298 | | |
299 | | void SvTabListBox::dispose() |
300 | 0 | { |
301 | 0 | mvTabList.clear(); |
302 | 0 | SvTreeListBox::dispose(); |
303 | 0 | } |
304 | | |
305 | | void SvTabListBox::SetTabWidth(sal_uInt16 nTab, tools::Long tabWidth) |
306 | 0 | { |
307 | | // Ensure that mvTabList[nTab + 1] exists because it is required to calculate diff |
308 | 0 | if (nTab + 2 > tools::Long(mvTabList.size())) |
309 | 0 | mvTabList.resize(nTab + 2); |
310 | |
|
311 | 0 | tools::Long diff = tabWidth - |
312 | 0 | (mvTabList[nTab + 1].GetPos() - mvTabList[nTab].GetPos()); // Width change |
313 | | |
314 | | // Shift all tab positions after nTab by diff |
315 | 0 | for( sal_uInt16 nIdx = nTab + 1; nIdx < sal_uInt16(mvTabList.size()); nIdx++) |
316 | 0 | mvTabList[nIdx].SetPos(mvTabList[nIdx].GetPos() + diff); |
317 | 0 | SvTreeListBox::m_nTreeFlags |= SvTreeFlags::RECALCTABS; |
318 | 0 | if( IsUpdateMode() ) |
319 | 0 | Invalidate(); |
320 | 0 | } |
321 | | |
322 | | void SvTabListBox::SetTabs(const std::vector<tools::Long>& rTabPositions) |
323 | 0 | { |
324 | 0 | assert(!rTabPositions.empty()); |
325 | 0 | mvTabList.resize(rTabPositions.size()); |
326 | |
|
327 | 0 | for( sal_uInt16 nIdx = 0; nIdx < sal_uInt16(mvTabList.size()); nIdx++) |
328 | 0 | mvTabList[nIdx].SetPos(rTabPositions.at(nIdx)); |
329 | |
|
330 | 0 | SvTreeListBox::m_nTreeFlags |= SvTreeFlags::RECALCTABS; |
331 | 0 | if( IsUpdateMode() ) |
332 | 0 | Invalidate(); |
333 | 0 | } |
334 | | |
335 | | SvTreeListEntry* SvTabListBox::InsertEntry( const OUString& rText, SvTreeListEntry* pParent, |
336 | | bool /*bChildrenOnDemand*/, |
337 | | sal_uInt32 nPos, OUString* pUserData ) |
338 | 0 | { |
339 | 0 | return InsertEntryToColumn( rText, pParent, nPos, 0xffff, pUserData ); |
340 | 0 | } |
341 | | |
342 | | SvTreeListEntry* SvTabListBox::InsertEntryToColumn(const OUString& rStr,SvTreeListEntry* pParent,sal_uInt32 nPos,sal_uInt16 nCol, |
343 | | OUString* pUser ) |
344 | 0 | { |
345 | 0 | OUString aStr; |
346 | 0 | if( nCol != 0xffff ) |
347 | 0 | { |
348 | 0 | while( nCol ) |
349 | 0 | { |
350 | 0 | aStr += "\t"; |
351 | 0 | nCol--; |
352 | 0 | } |
353 | 0 | } |
354 | 0 | aStr += rStr; |
355 | 0 | OUString aFirstStr( aStr ); |
356 | 0 | sal_Int32 nEnd = aFirstStr.indexOf( '\t' ); |
357 | 0 | if( nEnd != -1 ) |
358 | 0 | { |
359 | 0 | aFirstStr = aFirstStr.copy(0, nEnd); |
360 | 0 | aCurEntry = aStr.copy(++nEnd); |
361 | 0 | } |
362 | 0 | else |
363 | 0 | aCurEntry.clear(); |
364 | 0 | return SvTreeListBox::InsertEntry( aFirstStr, pParent, false, nPos, pUser ); |
365 | 0 | } |
366 | | |
367 | | OUString SvTabListBox::GetEntryText( SvTreeListEntry* pEntry ) const |
368 | 0 | { |
369 | 0 | return GetEntryText( pEntry, 0xffff ); |
370 | 0 | } |
371 | | |
372 | | OUString SvTabListBox::GetEntryText( const SvTreeListEntry* pEntry, sal_uInt16 nCol ) |
373 | 0 | { |
374 | 0 | DBG_ASSERT(pEntry,"GetEntryText:Invalid Entry"); |
375 | 0 | OUStringBuffer aResult; |
376 | 0 | if( pEntry ) |
377 | 0 | { |
378 | 0 | sal_uInt16 nCount = pEntry->ItemCount(); |
379 | 0 | sal_uInt16 nCur = 0; |
380 | 0 | while( nCur < nCount ) |
381 | 0 | { |
382 | 0 | const SvLBoxItem& rStr = pEntry->GetItem( nCur ); |
383 | 0 | if (rStr.GetType() == SvLBoxItemType::String) |
384 | 0 | { |
385 | 0 | if( nCol == 0xffff ) |
386 | 0 | { |
387 | 0 | if (!aResult.isEmpty()) |
388 | 0 | aResult.append("\t"); |
389 | 0 | aResult.append(static_cast<const SvLBoxString&>(rStr).GetText()); |
390 | 0 | } |
391 | 0 | else |
392 | 0 | { |
393 | 0 | if( nCol == 0 ) |
394 | 0 | return static_cast<const SvLBoxString&>(rStr).GetText(); |
395 | 0 | nCol--; |
396 | 0 | } |
397 | 0 | } |
398 | 0 | nCur++; |
399 | 0 | } |
400 | 0 | } |
401 | 0 | return aResult.makeStringAndClear(); |
402 | 0 | } |
403 | | |
404 | | OUString SvTabListBox::GetEntryText( sal_uInt32 nPos, sal_uInt16 nCol ) const |
405 | 0 | { |
406 | 0 | SvTreeListEntry* pEntry = GetEntryOnPos( nPos ); |
407 | 0 | return GetEntryText( pEntry, nCol ); |
408 | 0 | } |
409 | | |
410 | | OUString SvTabListBox::GetCellText( sal_uInt32 nPos, sal_uInt16 nCol ) const |
411 | 0 | { |
412 | 0 | SvTreeListEntry* pEntry = GetEntryOnPos( nPos ); |
413 | 0 | DBG_ASSERT( pEntry, "SvTabListBox::GetCellText(): Invalid Entry" ); |
414 | 0 | OUString aResult; |
415 | 0 | if (pEntry && pEntry->ItemCount() > o3tl::make_unsigned(nCol+1)) |
416 | 0 | { |
417 | 0 | const SvLBoxItem& rStr = pEntry->GetItem( nCol + 1 ); |
418 | 0 | if (rStr.GetType() == SvLBoxItemType::String) |
419 | 0 | aResult = static_cast<const SvLBoxString&>(rStr).GetText(); |
420 | 0 | } |
421 | 0 | return aResult; |
422 | 0 | } |
423 | | |
424 | | // static |
425 | | std::u16string_view SvTabListBox::GetToken( std::u16string_view sStr, sal_Int32& nIndex ) |
426 | 0 | { |
427 | 0 | return o3tl::getToken(sStr, 0, '\t', nIndex); |
428 | 0 | } |
429 | | |
430 | | OUString SvTabListBox::GetTabEntryText( sal_uInt32 nPos, sal_uInt16 nCol ) const |
431 | 0 | { |
432 | 0 | SvTreeListEntry* pEntry = GetEntryOnPos( nPos ); |
433 | 0 | DBG_ASSERT( pEntry, "GetTabEntryText(): Invalid entry " ); |
434 | 0 | OUStringBuffer aResult; |
435 | 0 | if ( pEntry ) |
436 | 0 | { |
437 | 0 | sal_uInt16 nCount = pEntry->ItemCount(); |
438 | 0 | sal_uInt16 nCur = 0; |
439 | 0 | while( nCur < nCount ) |
440 | 0 | { |
441 | 0 | const SvLBoxItem& rBoxItem = pEntry->GetItem( nCur ); |
442 | 0 | if (rBoxItem.GetType() == SvLBoxItemType::String) |
443 | 0 | { |
444 | 0 | if ( nCol == 0xffff ) |
445 | 0 | { |
446 | 0 | if (!aResult.isEmpty()) |
447 | 0 | aResult.append("\t"); |
448 | 0 | aResult.append(static_cast<const SvLBoxString&>(rBoxItem).GetText()); |
449 | 0 | } |
450 | 0 | else |
451 | 0 | { |
452 | 0 | if ( nCol == 0 ) |
453 | 0 | { |
454 | 0 | OUString sRet = static_cast<const SvLBoxString&>(rBoxItem).GetText(); |
455 | 0 | if ( sRet.isEmpty() ) |
456 | 0 | sRet = VclResId( STR_SVT_ACC_EMPTY_FIELD ); |
457 | 0 | return sRet; |
458 | 0 | } |
459 | 0 | --nCol; |
460 | 0 | } |
461 | 0 | } |
462 | 0 | ++nCur; |
463 | 0 | } |
464 | 0 | } |
465 | 0 | return aResult.makeStringAndClear(); |
466 | 0 | } |
467 | | |
468 | | SvTreeListEntry* SvTabListBox::GetEntryOnPos( sal_uInt32 _nEntryPos ) const |
469 | 0 | { |
470 | 0 | SvTreeListEntry* pEntry = nullptr; |
471 | 0 | sal_uInt32 i, nPos = 0, nCount = GetLevelChildCount( nullptr ); |
472 | 0 | for ( i = 0; i < nCount; ++i ) |
473 | 0 | { |
474 | 0 | SvTreeListEntry* pParent = GetEntry(i); |
475 | 0 | if ( nPos == _nEntryPos ) |
476 | 0 | { |
477 | 0 | pEntry = pParent; |
478 | 0 | break; |
479 | 0 | } |
480 | 0 | else |
481 | 0 | { |
482 | 0 | nPos++; |
483 | 0 | pEntry = GetChildOnPos( pParent, _nEntryPos, nPos ); |
484 | 0 | if ( pEntry ) |
485 | 0 | break; |
486 | 0 | } |
487 | 0 | } |
488 | |
|
489 | 0 | return pEntry; |
490 | 0 | } |
491 | | |
492 | | SvTreeListEntry* SvTabListBox::GetChildOnPos( SvTreeListEntry* _pParent, sal_uInt32 _nEntryPos, sal_uInt32& _rPos ) const |
493 | 0 | { |
494 | 0 | sal_uInt32 i, nCount = GetLevelChildCount( _pParent ); |
495 | 0 | for ( i = 0; i < nCount; ++i ) |
496 | 0 | { |
497 | 0 | SvTreeListEntry* pParent = GetEntry( _pParent, i ); |
498 | 0 | if ( _rPos == _nEntryPos ) |
499 | 0 | return pParent; |
500 | 0 | else |
501 | 0 | { |
502 | 0 | _rPos++; |
503 | 0 | SvTreeListEntry* pEntry = GetChildOnPos( pParent, _nEntryPos, _rPos ); |
504 | 0 | if ( pEntry ) |
505 | 0 | return pEntry; |
506 | 0 | } |
507 | 0 | } |
508 | | |
509 | 0 | return nullptr; |
510 | 0 | } |
511 | | |
512 | | void SvTabListBox::SetTabAlignCenter(sal_uInt16 nTab) |
513 | 0 | { |
514 | 0 | DBG_ASSERT(nTab<mvTabList.size(),"GetTabPos:Invalid Tab"); |
515 | 0 | if( nTab >= mvTabList.size() ) |
516 | 0 | return; |
517 | 0 | SvLBoxTab& rTab = mvTabList[ nTab ]; |
518 | 0 | SvLBoxTabFlags nFlags = rTab.nFlags; |
519 | 0 | nFlags &= ~SvLBoxTabFlags::ADJUST_FLAGS; |
520 | | // see SvLBoxTab::CalcOffset for force, which only matters for centering |
521 | 0 | nFlags |= SvLBoxTabFlags::ADJUST_CENTER | SvLBoxTabFlags::FORCE; |
522 | 0 | rTab.nFlags = nFlags; |
523 | 0 | SvTreeListBox::m_nTreeFlags |= SvTreeFlags::RECALCTABS; |
524 | 0 | if( IsUpdateMode() ) |
525 | 0 | Invalidate(); |
526 | 0 | } |
527 | | |
528 | | void SvTabListBox::SetTabEditable(sal_uInt16 nTab, bool bEditable) |
529 | 0 | { |
530 | 0 | DBG_ASSERT(nTab<mvTabList.size(),"GetTabPos:Invalid Tab"); |
531 | 0 | if( nTab >= mvTabList.size() ) |
532 | 0 | return; |
533 | 0 | SvLBoxTab& rTab = mvTabList[ nTab ]; |
534 | 0 | if (bEditable) |
535 | 0 | rTab.nFlags |= SvLBoxTabFlags::EDITABLE; |
536 | 0 | else |
537 | 0 | rTab.nFlags &= ~SvLBoxTabFlags::EDITABLE; |
538 | 0 | } |
539 | | |
540 | | void SvTabListBox::SetTabVisible(sal_uInt16 nTab, bool bVisible) |
541 | 0 | { |
542 | 0 | DBG_ASSERT(nTab<mvTabList.size(),"GetTabPos:Invalid Tab"); |
543 | 0 | if( nTab >= mvTabList.size() ) |
544 | 0 | return; |
545 | | |
546 | 0 | if( SvTreeListBox::m_nTreeFlags & SvTreeFlags::RECALCTABS ) |
547 | 0 | SetTabs(); |
548 | | |
549 | | // Find index in aTabs |
550 | 0 | nTab += m_aTabs.size() - mvTabList.size(); |
551 | 0 | SvLBoxTab* pTab = m_aTabs[ nTab ].get(); |
552 | |
|
553 | 0 | if (!bVisible) |
554 | 0 | pTab->nFlags |= SvLBoxTabFlags::HIDDEN; |
555 | 0 | else |
556 | 0 | pTab->nFlags &= ~SvLBoxTabFlags::HIDDEN; |
557 | 0 | } |
558 | | |
559 | | bool SvTabListBox::GetTabVisible(sal_uInt16 nTab) |
560 | 0 | { |
561 | 0 | DBG_ASSERT(nTab<mvTabList.size(),"GetTabPos:Invalid Tab"); |
562 | 0 | if( nTab >= mvTabList.size() ) |
563 | 0 | return false; |
564 | | |
565 | 0 | if( SvTreeListBox::m_nTreeFlags & SvTreeFlags::RECALCTABS ) |
566 | 0 | SetTabs(); |
567 | |
|
568 | 0 | nTab += m_aTabs.size() - mvTabList.size(); |
569 | 0 | SvLBoxTab* pTab = m_aTabs[ nTab ].get(); |
570 | 0 | return !pTab->IsHidden(); |
571 | 0 | } |
572 | | |
573 | | tools::Long SvTabListBox::GetLogicTab( sal_uInt16 nTab ) |
574 | 0 | { |
575 | 0 | if (SvTreeListBox::m_nTreeFlags & SvTreeFlags::RECALCTABS) |
576 | 0 | SetTabs(); |
577 | |
|
578 | 0 | DBG_ASSERT(nTab<mvTabList.size(),"GetTabPos:Invalid Tab"); |
579 | 0 | return m_aTabs[nTab]->GetPos(); |
580 | 0 | } |
581 | | |
582 | | SvHeaderTabListBox::SvHeaderTabListBox(vcl::Window* pParent, WinBits nWinStyle, HeaderBar* pHeaderBar) |
583 | 0 | : SvTabListBox(pParent, nWinStyle) |
584 | 0 | , m_bFirstPaint(true) |
585 | 0 | { |
586 | |
|
587 | 0 | assert(pHeaderBar); |
588 | 0 | m_xHeaderBar = pHeaderBar; |
589 | 0 | SetScrolledHdl(LINK(this, SvHeaderTabListBox, ScrollHdl_Impl)); |
590 | 0 | m_xHeaderBar->SetCreateAccessibleHdl(LINK(this, SvHeaderTabListBox, CreateAccessibleHdl_Impl)); |
591 | 0 | } Unexecuted instantiation: SvHeaderTabListBox::SvHeaderTabListBox(vcl::Window*, long, HeaderBar*) Unexecuted instantiation: SvHeaderTabListBox::SvHeaderTabListBox(vcl::Window*, long, HeaderBar*) |
592 | | |
593 | | SvHeaderTabListBox::~SvHeaderTabListBox() |
594 | 0 | { |
595 | 0 | disposeOnce(); |
596 | 0 | } |
597 | | |
598 | | void SvHeaderTabListBox::dispose() |
599 | 0 | { |
600 | 0 | for (rtl::Reference<AccessibleBrowseBoxHeaderCell>& rxChild : m_aAccessibleChildren) |
601 | 0 | comphelper::disposeComponent(rxChild); |
602 | 0 | m_aAccessibleChildren.clear(); |
603 | 0 | m_xAccessible.clear(); |
604 | |
|
605 | 0 | m_xHeaderBar.reset(); |
606 | 0 | SvTabListBox::dispose(); |
607 | 0 | } |
608 | | |
609 | | void SvHeaderTabListBox::Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect ) |
610 | 0 | { |
611 | 0 | if (m_bFirstPaint) |
612 | 0 | { |
613 | 0 | m_bFirstPaint = false; |
614 | 0 | } |
615 | 0 | SvTabListBox::Paint(rRenderContext, rRect); |
616 | 0 | } |
617 | | |
618 | | HeaderBar* SvHeaderTabListBox::GetHeaderBar() |
619 | 0 | { |
620 | 0 | return m_xHeaderBar; |
621 | 0 | } |
622 | | |
623 | | bool SvHeaderTabListBox::IsItemChecked( SvTreeListEntry* pEntry, sal_uInt16 nCol ) |
624 | 0 | { |
625 | 0 | SvButtonState eState = SvButtonState::Unchecked; |
626 | 0 | SvLBoxButton& rItem = static_cast<SvLBoxButton&>( pEntry->GetItem( nCol + 1 ) ); |
627 | |
|
628 | 0 | if (rItem.GetType() == SvLBoxItemType::Button) |
629 | 0 | { |
630 | 0 | SvItemStateFlags nButtonFlags = rItem.GetButtonFlags(); |
631 | 0 | eState = SvLBoxButtonData::ConvertToButtonState( nButtonFlags ); |
632 | 0 | } |
633 | |
|
634 | 0 | return ( eState == SvButtonState::Checked ); |
635 | 0 | } |
636 | | |
637 | | SvTreeListEntry* SvHeaderTabListBox::InsertEntryToColumn( |
638 | | const OUString& rStr, SvTreeListEntry* pParent, sal_uInt32 nPos, sal_uInt16 nCol, OUString* pUserData ) |
639 | 0 | { |
640 | 0 | SvTreeListEntry* pEntry = SvTabListBox::InsertEntryToColumn( rStr, pParent, nPos, nCol, pUserData ); |
641 | 0 | RecalculateAccessibleChildren(); |
642 | 0 | return pEntry; |
643 | 0 | } |
644 | | |
645 | | void SvHeaderTabListBox::Insert(SvTreeListEntry* pEnt, SvTreeListEntry* pPar, sal_uInt32 nPos) |
646 | 0 | { |
647 | 0 | SvTabListBox::Insert(pEnt, pPar, nPos); |
648 | 0 | RecalculateAccessibleChildren(); |
649 | 0 | } |
650 | | |
651 | | void SvHeaderTabListBox::Insert(SvTreeListEntry* pEntry, sal_uInt32 nRootPos) |
652 | 0 | { |
653 | 0 | SvTabListBox::Insert(pEntry, nRootPos); |
654 | 0 | RecalculateAccessibleChildren(); |
655 | 0 | } |
656 | | |
657 | | void SvHeaderTabListBox::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter) |
658 | 0 | { |
659 | 0 | SvTabListBox::DumpAsPropertyTree(rJsonWriter); |
660 | |
|
661 | 0 | auto aHeaders = rJsonWriter.startArray("headers"); |
662 | |
|
663 | 0 | HeaderBar* pHeaderBar = GetHeaderBar(); |
664 | 0 | for(sal_uInt16 i = 0; i < pHeaderBar->GetItemCount(); i++) |
665 | 0 | { |
666 | 0 | auto aNode = rJsonWriter.startStruct(); |
667 | 0 | sal_uInt16 nItemId = pHeaderBar->GetItemId(i); |
668 | 0 | HeaderBarItemBits eItemBits = pHeaderBar->GetItemBits(nItemId); |
669 | 0 | rJsonWriter.put("text", pHeaderBar->GetItemText(nItemId)); |
670 | 0 | rJsonWriter.put("sortable", !!(eItemBits & HeaderBarItemBits::CLICKABLE)); |
671 | 0 | if (eItemBits & HeaderBarItemBits::UPARROW) |
672 | 0 | rJsonWriter.put("arrow", "up"); |
673 | 0 | else if (eItemBits & HeaderBarItemBits::DOWNARROW) |
674 | 0 | rJsonWriter.put("arrow", "down"); |
675 | 0 | } |
676 | 0 | } |
677 | | |
678 | | IMPL_LINK_NOARG(SvHeaderTabListBox, ScrollHdl_Impl, SvTreeListBox*, void) |
679 | 0 | { |
680 | 0 | m_xHeaderBar->SetOffset(-GetXOffset()); |
681 | 0 | } |
682 | | |
683 | | IMPL_LINK_NOARG(SvHeaderTabListBox, CreateAccessibleHdl_Impl, HeaderBar*, void) |
684 | 0 | { |
685 | 0 | css::uno::Reference< XAccessible > xAccParent = m_xHeaderBar->GetAccessibleParent(); |
686 | 0 | if ( xAccParent.is() ) |
687 | 0 | { |
688 | 0 | rtl::Reference<comphelper::OAccessible> pAccessible = new AccessibleBrowseBoxHeaderBar( |
689 | 0 | xAccParent, *this, AccessibleBrowseBoxObjType::ColumnHeaderBar); |
690 | 0 | m_xHeaderBar->SetAccessible(pAccessible); |
691 | 0 | } |
692 | 0 | } |
693 | | |
694 | | void SvHeaderTabListBox::RecalculateAccessibleChildren() |
695 | 0 | { |
696 | 0 | if ( !m_aAccessibleChildren.empty() ) |
697 | 0 | { |
698 | 0 | sal_uInt32 nCount = ( GetRowCount() + 1 ) * GetColumnCount(); |
699 | 0 | if ( m_aAccessibleChildren.size() < nCount ) |
700 | 0 | m_aAccessibleChildren.resize( nCount ); |
701 | 0 | else |
702 | 0 | { |
703 | 0 | DBG_ASSERT( m_aAccessibleChildren.size() == nCount, "wrong children count" ); |
704 | 0 | } |
705 | 0 | } |
706 | 0 | } |
707 | | |
708 | | bool SvHeaderTabListBox::IsCellCheckBox( sal_Int32 _nRow, sal_uInt16 _nColumn, TriState& _rState ) const |
709 | 0 | { |
710 | 0 | bool bRet = false; |
711 | 0 | SvTreeListEntry* pEntry = GetEntryOnPos( _nRow ); |
712 | 0 | if ( pEntry ) |
713 | 0 | { |
714 | 0 | sal_uInt16 nItemCount = pEntry->ItemCount(); |
715 | 0 | if ( nItemCount > ( _nColumn + 1 ) ) |
716 | 0 | { |
717 | 0 | SvLBoxItem& rItem = pEntry->GetItem( _nColumn + 1 ); |
718 | 0 | if (rItem.GetType() == SvLBoxItemType::Button) |
719 | 0 | { |
720 | 0 | bRet = true; |
721 | 0 | _rState = ( ( static_cast<SvLBoxButton&>(rItem).GetButtonFlags() & SvItemStateFlags::UNCHECKED ) == SvItemStateFlags::NONE ) |
722 | 0 | ? TRISTATE_TRUE : TRISTATE_FALSE; |
723 | 0 | } |
724 | 0 | } |
725 | 0 | else |
726 | 0 | { |
727 | 0 | SAL_WARN( "svtools.contnr", "SvHeaderTabListBox::IsCellCheckBox(): column out of range" ); |
728 | 0 | } |
729 | 0 | } |
730 | 0 | return bRet; |
731 | 0 | } |
732 | | sal_Int32 SvHeaderTabListBox::GetRowCount() const |
733 | 0 | { |
734 | 0 | return GetEntryCount(); |
735 | 0 | } |
736 | | |
737 | | sal_uInt16 SvHeaderTabListBox::GetColumnCount() const |
738 | 0 | { |
739 | 0 | return m_xHeaderBar->GetItemCount(); |
740 | 0 | } |
741 | | |
742 | | sal_Int32 SvHeaderTabListBox::GetCurrRow() const |
743 | 0 | { |
744 | 0 | sal_Int32 nRet = -1; |
745 | 0 | SvTreeListEntry* pEntry = GetCurEntry(); |
746 | 0 | if ( pEntry ) |
747 | 0 | { |
748 | 0 | sal_uInt32 nCount = GetEntryCount(); |
749 | 0 | for ( sal_uInt32 i = 0; i < nCount; ++i ) |
750 | 0 | { |
751 | 0 | if ( pEntry == GetEntryOnPos(i) ) |
752 | 0 | { |
753 | 0 | nRet = i; |
754 | 0 | break; |
755 | 0 | } |
756 | 0 | } |
757 | 0 | } |
758 | |
|
759 | 0 | return nRet; |
760 | 0 | } |
761 | | |
762 | | sal_uInt16 SvHeaderTabListBox::GetCurrColumn() const |
763 | 0 | { |
764 | 0 | return 0; |
765 | 0 | } |
766 | | |
767 | | OUString SvHeaderTabListBox::GetRowDescription( sal_Int32 _nRow ) const |
768 | 0 | { |
769 | 0 | return GetEntryText( _nRow ); |
770 | 0 | } |
771 | | |
772 | | OUString SvHeaderTabListBox::GetColumnDescription( sal_uInt16 _nColumn ) const |
773 | 0 | { |
774 | 0 | return m_xHeaderBar->GetItemText(m_xHeaderBar->GetItemId(_nColumn )); |
775 | 0 | } |
776 | | |
777 | | bool SvHeaderTabListBox::HasRowHeader() const |
778 | 0 | { |
779 | 0 | return false; |
780 | 0 | } |
781 | | |
782 | | bool SvHeaderTabListBox::GoToCell( sal_Int32 /*_nRow*/, sal_uInt16 /*_nColumn*/ ) |
783 | 0 | { |
784 | 0 | return false; |
785 | 0 | } |
786 | | |
787 | | void SvHeaderTabListBox::SetNoSelection() |
788 | 0 | { |
789 | 0 | SvTreeListBox::SelectAll(false); |
790 | 0 | } |
791 | | |
792 | | void SvHeaderTabListBox::SelectAll() |
793 | 0 | { |
794 | 0 | SvTreeListBox::SelectAll(true); |
795 | 0 | } |
796 | | |
797 | | void SvHeaderTabListBox::SelectRow( sal_Int32 _nRow, bool _bSelect, bool ) |
798 | 0 | { |
799 | 0 | Select( GetEntryOnPos( _nRow ), _bSelect ); |
800 | 0 | } |
801 | | |
802 | | void SvHeaderTabListBox::SelectColumn( sal_uInt16, bool ) |
803 | 0 | { |
804 | 0 | } |
805 | | |
806 | | sal_Int32 SvHeaderTabListBox::GetSelectedRowCount() const |
807 | 0 | { |
808 | 0 | return GetSelectionCount(); |
809 | 0 | } |
810 | | |
811 | | sal_Int32 SvHeaderTabListBox::GetSelectedColumnCount() const |
812 | 0 | { |
813 | 0 | return 0; |
814 | 0 | } |
815 | | |
816 | | bool SvHeaderTabListBox::IsRowSelected( sal_Int32 _nRow ) const |
817 | 0 | { |
818 | 0 | SvTreeListEntry* pEntry = GetEntryOnPos( _nRow ); |
819 | 0 | return ( pEntry && IsSelected( pEntry ) ); |
820 | 0 | } |
821 | | |
822 | | bool SvHeaderTabListBox::IsColumnSelected( sal_Int32 ) const |
823 | 0 | { |
824 | 0 | return false; |
825 | 0 | } |
826 | | |
827 | | void SvHeaderTabListBox::GetAllSelectedRows(css::uno::Sequence<sal_Int32 >& rRowIndices) const |
828 | 0 | { |
829 | 0 | const sal_Int32 nCount = GetSelectedRowCount(); |
830 | 0 | rRowIndices.realloc(nCount); |
831 | 0 | auto pRows = rRowIndices.getArray(); |
832 | 0 | SvTreeListEntry* pEntry = FirstSelected(); |
833 | 0 | sal_Int32 nIndex = 0; |
834 | 0 | while (nIndex < nCount && pEntry) |
835 | 0 | { |
836 | 0 | pRows[nIndex] = GetEntryPos(pEntry); |
837 | 0 | pEntry = NextSelected( pEntry ); |
838 | 0 | ++nIndex; |
839 | 0 | } |
840 | 0 | assert(nIndex == nCount && "Mismatch between GetSelectedRowCount() and count of selected rows when iterating."); |
841 | 0 | } |
842 | | |
843 | | void SvHeaderTabListBox::GetAllSelectedColumns( css::uno::Sequence< sal_Int32 >& ) const |
844 | 0 | { |
845 | 0 | } |
846 | | |
847 | | bool SvHeaderTabListBox::IsCellVisible( sal_Int32, sal_uInt16 ) const |
848 | 0 | { |
849 | 0 | return true; |
850 | 0 | } |
851 | | |
852 | | OUString SvHeaderTabListBox::GetAccessibleCellText( sal_Int32 _nRow, sal_uInt16 _nColumnPos ) const |
853 | 0 | { |
854 | 0 | return GetTabEntryText(_nRow, _nColumnPos); |
855 | 0 | } |
856 | | |
857 | | tools::Rectangle SvHeaderTabListBox::calcHeaderRect(bool _bIsColumnBar) |
858 | 0 | { |
859 | 0 | tools::Rectangle aRect; |
860 | 0 | if ( _bIsColumnBar ) |
861 | 0 | { |
862 | 0 | vcl::Window* pParent = m_xHeaderBar->GetAccessibleParentWindow(); |
863 | 0 | assert(pParent); |
864 | 0 | aRect = m_xHeaderBar->GetWindowExtentsRelative(*pParent); |
865 | 0 | } |
866 | 0 | return aRect; |
867 | 0 | } |
868 | | |
869 | | tools::Rectangle SvHeaderTabListBox::calcTableRect() |
870 | 0 | { |
871 | 0 | tools::Rectangle aScreenRect(GetWindowExtentsAbsolute()); |
872 | 0 | return tools::Rectangle(Point(0, 0), aScreenRect.GetSize()); |
873 | 0 | } |
874 | | |
875 | | tools::Rectangle SvHeaderTabListBox::calcFieldRectPixel(sal_Int32 _nRow, sal_uInt16 _nColumn, bool _bIsHeader) |
876 | 0 | { |
877 | 0 | DBG_ASSERT( !_bIsHeader || 0 == _nRow, "invalid parameters" ); |
878 | 0 | tools::Rectangle aRect; |
879 | 0 | SvTreeListEntry* pEntry = GetEntryOnPos(_nRow ); |
880 | 0 | if ( pEntry ) |
881 | 0 | { |
882 | 0 | aRect = _bIsHeader ? calcHeaderRect(true) : GetBoundingRect(pEntry); |
883 | 0 | Point aTopLeft = aRect.TopLeft(); |
884 | 0 | DBG_ASSERT(m_xHeaderBar->GetItemCount() > _nColumn, "invalid column"); |
885 | 0 | tools::Rectangle aItemRect = m_xHeaderBar->GetItemRect(m_xHeaderBar->GetItemId(_nColumn)); |
886 | 0 | aTopLeft.setX( aItemRect.Left() ); |
887 | 0 | Size aSize = aItemRect.GetSize(); |
888 | 0 | aRect = tools::Rectangle( aTopLeft, aSize ); |
889 | 0 | } |
890 | |
|
891 | 0 | return aRect; |
892 | 0 | } |
893 | | |
894 | | rtl::Reference<comphelper::OAccessible> |
895 | | SvHeaderTabListBox::CreateAccessibleCell(sal_Int32 _nRow, sal_uInt16 _nColumnPos) |
896 | 0 | { |
897 | 0 | OSL_ENSURE(m_xAccessible.is(), "Invalid call: Accessible is null"); |
898 | |
|
899 | 0 | rtl::Reference< AccessibleBrowseBoxCell > xChild; |
900 | |
|
901 | 0 | TriState eState = TRISTATE_INDET; |
902 | 0 | bool bIsCheckBox = IsCellCheckBox( _nRow, _nColumnPos, eState ); |
903 | 0 | if ( bIsCheckBox ) |
904 | 0 | xChild = new AccessibleCheckBoxCell(m_xAccessible->getTable(), *this, _nRow, _nColumnPos, |
905 | 0 | eState, false); |
906 | 0 | else |
907 | 0 | xChild = new AccessibleBrowseBoxTableCell(m_xAccessible->getTable(), *this, _nRow, |
908 | 0 | _nColumnPos); |
909 | |
|
910 | 0 | return xChild; |
911 | 0 | } |
912 | | |
913 | | Reference< XAccessible > SvHeaderTabListBox::CreateAccessibleRowHeader( sal_Int32 ) |
914 | 0 | { |
915 | 0 | Reference< XAccessible > xHeader; |
916 | 0 | return xHeader; |
917 | 0 | } |
918 | | |
919 | | Reference< XAccessible > SvHeaderTabListBox::CreateAccessibleColumnHeader( sal_uInt16 _nColumn ) |
920 | 0 | { |
921 | | // first call? -> initial list |
922 | 0 | if ( m_aAccessibleChildren.empty() ) |
923 | 0 | { |
924 | 0 | const sal_uInt16 nColumnCount = GetColumnCount(); |
925 | 0 | m_aAccessibleChildren.resize( nColumnCount ); |
926 | 0 | } |
927 | | |
928 | | // get header |
929 | 0 | rtl::Reference< AccessibleBrowseBoxHeaderCell > xChild = m_aAccessibleChildren[ _nColumn ]; |
930 | | // already exists? |
931 | 0 | if (!xChild.is() && m_xAccessible.is()) |
932 | 0 | { |
933 | | // no -> create new header cell |
934 | 0 | xChild = new AccessibleBrowseBoxHeaderCell(_nColumn, m_xAccessible->getHeaderBar(), *this, |
935 | 0 | AccessibleBrowseBoxObjType::ColumnHeaderCell); |
936 | | |
937 | | // insert into list |
938 | 0 | m_aAccessibleChildren[ _nColumn ] = xChild; |
939 | 0 | } |
940 | 0 | return xChild; |
941 | 0 | } |
942 | | |
943 | | sal_Int32 SvHeaderTabListBox::GetAccessibleControlCount() const |
944 | 0 | { |
945 | 0 | return -1; |
946 | 0 | } |
947 | | |
948 | | rtl::Reference<comphelper::OAccessible> SvHeaderTabListBox::CreateAccessibleControl(sal_Int32) |
949 | 0 | { |
950 | 0 | return {}; |
951 | 0 | } |
952 | | |
953 | | bool SvHeaderTabListBox::ConvertPointToControlIndex( sal_Int32&, const Point& ) |
954 | 0 | { |
955 | 0 | return false; |
956 | 0 | } |
957 | | |
958 | | bool SvHeaderTabListBox::ConvertPointToCellAddress( sal_Int32&, sal_uInt16&, const Point& ) |
959 | 0 | { |
960 | 0 | return false; |
961 | 0 | } |
962 | | |
963 | | bool SvHeaderTabListBox::ConvertPointToRowHeader( sal_Int32&, const Point& ) |
964 | 0 | { |
965 | 0 | return false; |
966 | 0 | } |
967 | | |
968 | | bool SvHeaderTabListBox::ConvertPointToColumnHeader( sal_uInt16&, const Point& ) |
969 | 0 | { |
970 | 0 | return false; |
971 | 0 | } |
972 | | |
973 | | OUString SvHeaderTabListBox::GetAccessibleObjectName( AccessibleBrowseBoxObjType _eType, sal_Int32 _nPos ) const |
974 | 0 | { |
975 | 0 | OUString aRetText; |
976 | 0 | switch( _eType ) |
977 | 0 | { |
978 | 0 | case AccessibleBrowseBoxObjType::BrowseBox: |
979 | 0 | case AccessibleBrowseBoxObjType::Table: |
980 | 0 | case AccessibleBrowseBoxObjType::ColumnHeaderBar: |
981 | | // should be empty now (see #i63983) |
982 | 0 | aRetText.clear(); |
983 | 0 | break; |
984 | | |
985 | 0 | case AccessibleBrowseBoxObjType::TableCell: |
986 | 0 | { |
987 | | // here we need a valid pos, we can not handle -1 |
988 | 0 | if ( _nPos >= 0 ) |
989 | 0 | { |
990 | 0 | sal_uInt16 nColumnCount = GetColumnCount(); |
991 | 0 | if (nColumnCount > 0) |
992 | 0 | { |
993 | 0 | sal_Int32 nRow = _nPos / nColumnCount; |
994 | 0 | sal_uInt16 nColumn = static_cast< sal_uInt16 >( _nPos % nColumnCount ); |
995 | 0 | aRetText = GetCellText( nRow, nColumn ); |
996 | 0 | } |
997 | 0 | } |
998 | 0 | break; |
999 | 0 | } |
1000 | 0 | case AccessibleBrowseBoxObjType::CheckBoxCell: |
1001 | 0 | { |
1002 | 0 | break; // checkbox cells have no name |
1003 | 0 | } |
1004 | 0 | case AccessibleBrowseBoxObjType::ColumnHeaderCell: |
1005 | 0 | { |
1006 | 0 | aRetText = m_xHeaderBar->GetItemText(m_xHeaderBar->GetItemId(static_cast<sal_uInt16>(_nPos))); |
1007 | 0 | break; |
1008 | 0 | } |
1009 | | |
1010 | 0 | case AccessibleBrowseBoxObjType::RowHeaderBar: |
1011 | 0 | case AccessibleBrowseBoxObjType::RowHeaderCell: |
1012 | 0 | aRetText = "error"; |
1013 | 0 | break; |
1014 | | |
1015 | 0 | default: |
1016 | 0 | OSL_FAIL("BrowseBox::GetAccessibleName: invalid enum!"); |
1017 | 0 | } |
1018 | 0 | return aRetText; |
1019 | 0 | } |
1020 | | |
1021 | | OUString SvHeaderTabListBox::GetAccessibleObjectDescription( AccessibleBrowseBoxObjType _eType, sal_Int32 _nPos ) const |
1022 | 0 | { |
1023 | 0 | OUString aRetText; |
1024 | |
|
1025 | 0 | if( _eType == AccessibleBrowseBoxObjType::TableCell && _nPos != -1 ) |
1026 | 0 | { |
1027 | 0 | sal_uInt16 nColumnCount = GetColumnCount(); |
1028 | 0 | if (nColumnCount > 0) |
1029 | 0 | { |
1030 | 0 | sal_Int32 nRow = _nPos / nColumnCount; |
1031 | 0 | sal_uInt16 nColumn = static_cast< sal_uInt16 >( _nPos % nColumnCount ); |
1032 | |
|
1033 | 0 | OUString aText( VclResId(STR_SVT_ACC_DESC_TABLISTBOX) ); |
1034 | 0 | aText = aText.replaceFirst( "%1", OUString::number( nRow ) ); |
1035 | 0 | OUString sColHeader = m_xHeaderBar->GetItemText(m_xHeaderBar->GetItemId(nColumn)); |
1036 | 0 | if ( sColHeader.isEmpty() ) |
1037 | 0 | sColHeader = OUString::number( nColumn ); |
1038 | 0 | aText = aText.replaceFirst( "%2", sColHeader ); |
1039 | 0 | aRetText = aText; |
1040 | 0 | } |
1041 | 0 | } |
1042 | |
|
1043 | 0 | return aRetText; |
1044 | 0 | } |
1045 | | |
1046 | | void SvHeaderTabListBox::FillAccessibleStateSet( sal_Int64& _rStateSet, AccessibleBrowseBoxObjType _eType ) const |
1047 | 0 | { |
1048 | 0 | switch( _eType ) |
1049 | 0 | { |
1050 | 0 | case AccessibleBrowseBoxObjType::BrowseBox: |
1051 | 0 | case AccessibleBrowseBoxObjType::Table: |
1052 | 0 | { |
1053 | 0 | _rStateSet |= AccessibleStateType::FOCUSABLE; |
1054 | 0 | if ( HasFocus() ) |
1055 | 0 | _rStateSet |= AccessibleStateType::FOCUSED; |
1056 | 0 | if ( IsActive() ) |
1057 | 0 | _rStateSet |= AccessibleStateType::ACTIVE; |
1058 | 0 | if ( IsEnabled() ) |
1059 | 0 | { |
1060 | 0 | _rStateSet |= AccessibleStateType::ENABLED; |
1061 | 0 | _rStateSet |= AccessibleStateType::SENSITIVE; |
1062 | 0 | } |
1063 | 0 | if ( IsReallyVisible() ) |
1064 | 0 | _rStateSet |= AccessibleStateType::VISIBLE; |
1065 | 0 | if ( _eType == AccessibleBrowseBoxObjType::Table ) |
1066 | 0 | { |
1067 | |
|
1068 | 0 | _rStateSet |= AccessibleStateType::MANAGES_DESCENDANTS; |
1069 | 0 | _rStateSet |= AccessibleStateType::MULTI_SELECTABLE; |
1070 | 0 | } |
1071 | 0 | break; |
1072 | 0 | } |
1073 | | |
1074 | 0 | case AccessibleBrowseBoxObjType::ColumnHeaderBar: |
1075 | 0 | { |
1076 | 0 | sal_Int32 nCurRow = GetCurrRow(); |
1077 | 0 | sal_uInt16 nCurColumn = GetCurrColumn(); |
1078 | 0 | if ( IsCellVisible( nCurRow, nCurColumn ) ) |
1079 | 0 | _rStateSet |= AccessibleStateType::VISIBLE; |
1080 | 0 | if ( IsEnabled() ) |
1081 | 0 | _rStateSet |= AccessibleStateType::ENABLED; |
1082 | 0 | _rStateSet |= AccessibleStateType::TRANSIENT; |
1083 | 0 | break; |
1084 | 0 | } |
1085 | | |
1086 | 0 | case AccessibleBrowseBoxObjType::RowHeaderCell: |
1087 | 0 | case AccessibleBrowseBoxObjType::ColumnHeaderCell: |
1088 | 0 | { |
1089 | 0 | _rStateSet |= AccessibleStateType::VISIBLE; |
1090 | 0 | _rStateSet |= AccessibleStateType::FOCUSABLE; |
1091 | 0 | _rStateSet |= AccessibleStateType::TRANSIENT; |
1092 | 0 | if ( IsEnabled() ) |
1093 | 0 | _rStateSet |= AccessibleStateType::ENABLED; |
1094 | 0 | break; |
1095 | 0 | } |
1096 | 0 | default: |
1097 | 0 | break; |
1098 | 0 | } |
1099 | 0 | } |
1100 | | |
1101 | | void SvHeaderTabListBox::FillAccessibleStateSetForCell( sal_Int64& _rStateSet, sal_Int32 _nRow, sal_uInt16 _nColumn ) const |
1102 | 0 | { |
1103 | 0 | _rStateSet |= AccessibleStateType::FOCUSABLE; |
1104 | 0 | _rStateSet |= AccessibleStateType::SELECTABLE; |
1105 | 0 | _rStateSet |= AccessibleStateType::TRANSIENT; |
1106 | |
|
1107 | 0 | if ( IsCellVisible( _nRow, _nColumn ) ) |
1108 | 0 | { |
1109 | 0 | _rStateSet |= AccessibleStateType::VISIBLE; |
1110 | 0 | _rStateSet |= AccessibleStateType::ENABLED; |
1111 | 0 | } |
1112 | |
|
1113 | 0 | if ( IsRowSelected( _nRow ) ) |
1114 | 0 | { |
1115 | 0 | _rStateSet |= AccessibleStateType::ACTIVE; |
1116 | 0 | if (HasChildPathFocus()) |
1117 | 0 | _rStateSet |= AccessibleStateType::FOCUSED; |
1118 | 0 | _rStateSet |= AccessibleStateType::SELECTED; |
1119 | 0 | } |
1120 | 0 | if ( IsEnabled() ) |
1121 | 0 | _rStateSet |= AccessibleStateType::ENABLED; |
1122 | 0 | } |
1123 | | |
1124 | | void SvHeaderTabListBox::GrabTableFocus() |
1125 | 0 | { |
1126 | 0 | GrabFocus(); |
1127 | 0 | } |
1128 | | |
1129 | | bool SvHeaderTabListBox::GetGlyphBoundRects( const Point& rOrigin, const OUString& rStr, int nIndex, int nLen, std::vector< tools::Rectangle >& rVector ) |
1130 | 0 | { |
1131 | 0 | return GetOutDev()->GetGlyphBoundRects( rOrigin, rStr, nIndex, nLen, rVector ); |
1132 | 0 | } |
1133 | | |
1134 | | tools::Rectangle SvHeaderTabListBox::GetWindowExtentsRelative(const vcl::Window& rRelativeWindow) const |
1135 | 0 | { |
1136 | 0 | return Control::GetWindowExtentsRelative( rRelativeWindow ); |
1137 | 0 | } |
1138 | | |
1139 | | void SvHeaderTabListBox::GrabFocus() |
1140 | 0 | { |
1141 | 0 | Control::GrabFocus(); |
1142 | 0 | } |
1143 | | |
1144 | | rtl::Reference<comphelper::OAccessible> SvHeaderTabListBox::GetAccessible() |
1145 | 0 | { |
1146 | 0 | return Control::GetAccessible(); |
1147 | 0 | } |
1148 | | |
1149 | | vcl::Window* SvHeaderTabListBox::GetAccessibleParentWindow() const |
1150 | 0 | { |
1151 | 0 | return Control::GetAccessibleParentWindow(); |
1152 | 0 | } |
1153 | | |
1154 | | vcl::Window* SvHeaderTabListBox::GetWindowInstance() |
1155 | 0 | { |
1156 | 0 | return this; |
1157 | 0 | } |
1158 | | |
1159 | | rtl::Reference<comphelper::OAccessible> SvHeaderTabListBox::CreateAccessible() |
1160 | 0 | { |
1161 | 0 | if (m_xAccessible.is()) |
1162 | 0 | return m_xAccessible; |
1163 | | |
1164 | 0 | rtl::Reference<comphelper::OAccessible> pAccParent = GetAccessibleParent(); |
1165 | 0 | if (pAccParent.is()) |
1166 | 0 | { |
1167 | 0 | m_xAccessible = new AccessibleTabListBox(pAccParent, *this); |
1168 | 0 | return m_xAccessible; |
1169 | 0 | } |
1170 | 0 | return nullptr; |
1171 | 0 | } |
1172 | | |
1173 | | tools::Rectangle SvHeaderTabListBox::GetFieldCharacterBounds(sal_Int32,sal_Int32,sal_Int32) |
1174 | 0 | { |
1175 | 0 | return tools::Rectangle(); |
1176 | 0 | } |
1177 | | |
1178 | | sal_Int32 SvHeaderTabListBox::GetFieldIndexAtPoint(sal_Int32 _nRow,sal_Int32 _nColumnPos,const Point& _rPoint) |
1179 | 0 | { |
1180 | 0 | OUString sText = GetAccessibleCellText( _nRow, static_cast< sal_uInt16 >( _nColumnPos ) ); |
1181 | 0 | std::vector< tools::Rectangle > aRects; |
1182 | 0 | if ( GetGlyphBoundRects(Point(0,0), sText, 0, sText.getLength(), aRects) ) |
1183 | 0 | { |
1184 | 0 | sal_Int32 nPos = 0; |
1185 | 0 | for (auto const& rectangle : aRects) |
1186 | 0 | { |
1187 | 0 | if( rectangle.Contains(_rPoint) ) |
1188 | 0 | return nPos; |
1189 | 0 | ++nPos; |
1190 | 0 | } |
1191 | 0 | } |
1192 | | |
1193 | 0 | return -1; |
1194 | 0 | } |
1195 | | |
1196 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |