summaryrefslogtreecommitdiffstats
path: root/vcl/source/treelist/svtabbx.cxx
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--vcl/source/treelist/svtabbx.cxx1078
1 files changed, 1078 insertions, 0 deletions
diff --git a/vcl/source/treelist/svtabbx.cxx b/vcl/source/treelist/svtabbx.cxx
new file mode 100644
index 000000000..ec403682a
--- /dev/null
+++ b/vcl/source/treelist/svtabbx.cxx
@@ -0,0 +1,1078 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/svtaccessiblefactory.hxx>
+#include <vcl/accessiblefactory.hxx>
+#include <vcl/toolkit/svtabbx.hxx>
+#include <vcl/headbar.hxx>
+#include <vcl/toolkit/svlbitm.hxx>
+#include <vcl/toolkit/treelistentry.hxx>
+#include <unotools/accessiblestatesethelper.hxx>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <o3tl/safeint.hxx>
+#include <o3tl/string_view.hxx>
+#include <osl/diagnose.h>
+#include <strings.hrc>
+#include <svdata.hxx>
+#include <memory>
+#include <tools/json_writer.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::accessibility;
+
+constexpr SvLBoxTabFlags MYTABMASK =
+ SvLBoxTabFlags::ADJUST_RIGHT | SvLBoxTabFlags::ADJUST_LEFT | SvLBoxTabFlags::ADJUST_CENTER | SvLBoxTabFlags::FORCE;
+
+static void lcl_DumpEntryAndSiblings(tools::JsonWriter& rJsonWriter,
+ SvTreeListEntry* pEntry,
+ SvTabListBox* pTabListBox,
+ bool bCheckButtons)
+{
+ while (pEntry)
+ {
+ auto aNode = rJsonWriter.startStruct();
+
+ // simple listbox value
+ const SvLBoxItem* pIt = pEntry->GetFirstItem(SvLBoxItemType::String);
+ if (pIt)
+ rJsonWriter.put("text", static_cast<const SvLBoxString*>(pIt)->GetText());
+
+ // column based data
+ {
+ auto aColumns = rJsonWriter.startArray("columns");
+
+ for (size_t i = 0; i < pEntry->ItemCount(); i++)
+ {
+ SvLBoxItem& rItem = pEntry->GetItem(i);
+ if (rItem.GetType() == SvLBoxItemType::String)
+ {
+ const SvLBoxString* pStringItem = dynamic_cast<const SvLBoxString*>(&rItem);
+ if (pStringItem)
+ {
+ auto aColumn = rJsonWriter.startStruct();
+ rJsonWriter.put("text", pStringItem->GetText());
+ }
+ }
+ }
+ }
+
+ // SalInstanceTreeView does not use the flag CHILDREN_ON_DEMAND
+ // and it creates a dummy child
+ const SvTreeListEntries& rChildren = pEntry->GetChildEntries();
+ if (rChildren.size() == 1)
+ {
+ auto& rChild = rChildren[0];
+ if (const SvLBoxItem* pChild = rChild->GetFirstItem(SvLBoxItemType::String))
+ {
+ if (static_cast<const SvLBoxString*>(pChild)->GetText() == "<dummy>")
+ rJsonWriter.put("ondemand", "true");
+ }
+ }
+
+ if (bCheckButtons)
+ {
+ SvButtonState eCheckState = pTabListBox->GetCheckButtonState(pEntry);
+ if (eCheckState == SvButtonState::Unchecked)
+ rJsonWriter.put("state", "false");
+ else if (eCheckState == SvButtonState::Checked)
+ rJsonWriter.put("state", "true");
+ }
+
+ if (pTabListBox->IsSelected(pEntry))
+ rJsonWriter.put("selected", "true");
+
+ rJsonWriter.put("row", OString::number(pTabListBox->GetModel()->GetAbsPos(pEntry)).getStr());
+
+ SvTreeListEntry* pChild = pTabListBox->FirstChild(pEntry);
+ if (pChild)
+ {
+ auto childrenNode = rJsonWriter.startArray("children");
+ lcl_DumpEntryAndSiblings(rJsonWriter, pChild, pTabListBox, bCheckButtons);
+ }
+
+ pEntry = pEntry->NextSibling();
+ }
+}
+
+void SvTabListBox::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter)
+{
+ SvTreeListBox::DumpAsPropertyTree(rJsonWriter);
+
+ rJsonWriter.put("singleclickactivate", GetActivateOnSingleClick());
+
+ bool bCheckButtons = static_cast<int>(nTreeFlags & SvTreeFlags::CHKBTN);
+
+ auto entriesNode = rJsonWriter.startArray("entries");
+ lcl_DumpEntryAndSiblings(rJsonWriter, First(), this, bCheckButtons);
+}
+
+// SvTreeListBox callback
+
+void SvTabListBox::SetTabs()
+{
+ SvTreeListBox::SetTabs();
+ if( mvTabList.empty() )
+ return;
+
+ DBG_ASSERT(!mvTabList.empty(),"TabList ?");
+
+ // The tree listbox has now inserted its tabs into the list. Now we
+ // fluff up the list with additional tabs and adjust the rightmost tab
+ // of the tree listbox.
+
+ // Picking the rightmost tab.
+ // HACK for the explorer! If ViewParent != 0, the first tab of the tree
+ // listbox is calculated by the tree listbox itself! This behavior is
+ // necessary for ButtonsOnRoot, as the explorer does not know in this
+ // case, which additional offset it needs to add to the tabs in this mode
+ // -- the tree listbox knows that, though!
+ /*
+ if( !pViewParent )
+ {
+ SvLBoxTab* pFirstTab = (SvLBoxTab*)aTabs.GetObject( aTabs.Count()-1 );
+ pFirstTab->SetPos( pTabList[0].GetPos() );
+ pFirstTab->nFlags &= ~MYTABMASK;
+ pFirstTab->nFlags |= pTabList[0].nFlags;
+ }
+ */
+
+ // append all other tabs to the list
+ for( sal_uInt16 nCurTab = 1; nCurTab < sal_uInt16(mvTabList.size()); nCurTab++ )
+ {
+ SvLBoxTab& rTab = mvTabList[nCurTab];
+ AddTab( rTab.GetPos(), rTab.nFlags );
+ }
+}
+
+void SvTabListBox::InitEntry(SvTreeListEntry* pEntry, const OUString& rStr,
+ const Image& rColl, const Image& rExp)
+{
+ SvTreeListBox::InitEntry(pEntry, rStr, rColl, rExp);
+
+ sal_Int32 nIndex = 0;
+ // TODO: verify if nTabCount is always >0 here!
+ const sal_uInt16 nCount = mvTabList.size() - 1;
+ for( sal_uInt16 nToken = 0; nToken < nCount; nToken++ )
+ {
+ const std::u16string_view aToken = GetToken(aCurEntry, nIndex);
+ pEntry->AddItem(std::make_unique<SvLBoxString>(OUString(aToken)));
+ }
+}
+
+SvTabListBox::SvTabListBox( vcl::Window* pParent, WinBits nBits )
+ : SvTreeListBox( pParent, nBits )
+{
+ SetHighlightRange(); // select full width
+}
+
+SvTabListBox::~SvTabListBox()
+{
+ disposeOnce();
+}
+
+void SvTabListBox::dispose()
+{
+ mvTabList.clear();
+ SvTreeListBox::dispose();
+}
+
+void SvTabListBox::SetTabs(sal_uInt16 nTabs, tools::Long const pTabPositions[], MapUnit eMapUnit)
+{
+ mvTabList.resize(nTabs);
+
+ MapMode aMMSource( eMapUnit );
+ MapMode aMMDest( MapUnit::MapPixel );
+
+ for( sal_uInt16 nIdx = 0; nIdx < sal_uInt16(mvTabList.size()); nIdx++, pTabPositions++ )
+ {
+ Size aSize( *pTabPositions, 0 );
+ aSize = LogicToLogic( aSize, &aMMSource, &aMMDest );
+ tools::Long nNewTab = aSize.Width();
+ mvTabList[nIdx].SetPos( nNewTab );
+ mvTabList[nIdx].nFlags &= MYTABMASK;
+ }
+ SvTreeListBox::nTreeFlags |= SvTreeFlags::RECALCTABS;
+ if( IsUpdateMode() )
+ Invalidate();
+}
+
+SvTreeListEntry* SvTabListBox::InsertEntry( const OUString& rText, SvTreeListEntry* pParent,
+ bool /*bChildrenOnDemand*/,
+ sal_uInt32 nPos, void* pUserData )
+{
+ return InsertEntryToColumn( rText, pParent, nPos, 0xffff, pUserData );
+}
+
+SvTreeListEntry* SvTabListBox::InsertEntryToColumn(const OUString& rStr,SvTreeListEntry* pParent,sal_uInt32 nPos,sal_uInt16 nCol,
+ void* pUser )
+{
+ OUString aStr;
+ if( nCol != 0xffff )
+ {
+ while( nCol )
+ {
+ aStr += "\t";
+ nCol--;
+ }
+ }
+ aStr += rStr;
+ OUString aFirstStr( aStr );
+ sal_Int32 nEnd = aFirstStr.indexOf( '\t' );
+ if( nEnd != -1 )
+ {
+ aFirstStr = aFirstStr.copy(0, nEnd);
+ aCurEntry = aStr.copy(++nEnd);
+ }
+ else
+ aCurEntry.clear();
+ return SvTreeListBox::InsertEntry( aFirstStr, pParent, false, nPos, pUser );
+}
+
+OUString SvTabListBox::GetEntryText( SvTreeListEntry* pEntry ) const
+{
+ return GetEntryText( pEntry, 0xffff );
+}
+
+OUString SvTabListBox::GetEntryText( const SvTreeListEntry* pEntry, sal_uInt16 nCol )
+{
+ DBG_ASSERT(pEntry,"GetEntryText:Invalid Entry");
+ OUStringBuffer aResult;
+ if( pEntry )
+ {
+ sal_uInt16 nCount = pEntry->ItemCount();
+ sal_uInt16 nCur = 0;
+ while( nCur < nCount )
+ {
+ const SvLBoxItem& rStr = pEntry->GetItem( nCur );
+ if (rStr.GetType() == SvLBoxItemType::String)
+ {
+ if( nCol == 0xffff )
+ {
+ if (!aResult.isEmpty())
+ aResult.append("\t");
+ aResult.append(static_cast<const SvLBoxString&>(rStr).GetText());
+ }
+ else
+ {
+ if( nCol == 0 )
+ return static_cast<const SvLBoxString&>(rStr).GetText();
+ nCol--;
+ }
+ }
+ nCur++;
+ }
+ }
+ return aResult.makeStringAndClear();
+}
+
+OUString SvTabListBox::GetEntryText( sal_uInt32 nPos, sal_uInt16 nCol ) const
+{
+ SvTreeListEntry* pEntry = GetEntryOnPos( nPos );
+ return GetEntryText( pEntry, nCol );
+}
+
+OUString SvTabListBox::GetCellText( sal_uInt32 nPos, sal_uInt16 nCol ) const
+{
+ SvTreeListEntry* pEntry = GetEntryOnPos( nPos );
+ DBG_ASSERT( pEntry, "SvTabListBox::GetCellText(): Invalid Entry" );
+ OUString aResult;
+ if (pEntry && pEntry->ItemCount() > o3tl::make_unsigned(nCol+1))
+ {
+ const SvLBoxItem& rStr = pEntry->GetItem( nCol + 1 );
+ if (rStr.GetType() == SvLBoxItemType::String)
+ aResult = static_cast<const SvLBoxString&>(rStr).GetText();
+ }
+ return aResult;
+}
+
+sal_uInt32 SvTabListBox::GetEntryPos( const SvTreeListEntry* pEntry ) const
+{
+ sal_uInt32 nPos = 0;
+ SvTreeListEntry* pTmpEntry = First();
+ while( pTmpEntry )
+ {
+ if ( pTmpEntry == pEntry )
+ return nPos;
+ pTmpEntry = Next( pTmpEntry );
+ ++nPos;
+ }
+ return 0xffffffff;
+}
+
+// static
+std::u16string_view SvTabListBox::GetToken( std::u16string_view sStr, sal_Int32& nIndex )
+{
+ return o3tl::getToken(sStr, 0, '\t', nIndex);
+}
+
+OUString SvTabListBox::GetTabEntryText( sal_uInt32 nPos, sal_uInt16 nCol ) const
+{
+ SvTreeListEntry* pEntry = SvTreeListBox::GetEntry( nPos );
+ DBG_ASSERT( pEntry, "GetTabEntryText(): Invalid entry " );
+ OUStringBuffer aResult;
+ if ( pEntry )
+ {
+ sal_uInt16 nCount = pEntry->ItemCount();
+ sal_uInt16 nCur = 0;
+ while( nCur < nCount )
+ {
+ const SvLBoxItem& rBoxItem = pEntry->GetItem( nCur );
+ if (rBoxItem.GetType() == SvLBoxItemType::String)
+ {
+ if ( nCol == 0xffff )
+ {
+ if (!aResult.isEmpty())
+ aResult.append("\t");
+ aResult.append(static_cast<const SvLBoxString&>(rBoxItem).GetText());
+ }
+ else
+ {
+ if ( nCol == 0 )
+ {
+ OUString sRet = static_cast<const SvLBoxString&>(rBoxItem).GetText();
+ if ( sRet.isEmpty() )
+ sRet = VclResId( STR_SVT_ACC_EMPTY_FIELD );
+ return sRet;
+ }
+ --nCol;
+ }
+ }
+ ++nCur;
+ }
+ }
+ return aResult.makeStringAndClear();
+}
+
+SvTreeListEntry* SvTabListBox::GetEntryOnPos( sal_uInt32 _nEntryPos ) const
+{
+ SvTreeListEntry* pEntry = nullptr;
+ sal_uInt32 i, nPos = 0, nCount = GetLevelChildCount( nullptr );
+ for ( i = 0; i < nCount; ++i )
+ {
+ SvTreeListEntry* pParent = GetEntry(i);
+ if ( nPos == _nEntryPos )
+ {
+ pEntry = pParent;
+ break;
+ }
+ else
+ {
+ nPos++;
+ pEntry = GetChildOnPos( pParent, _nEntryPos, nPos );
+ if ( pEntry )
+ break;
+ }
+ }
+
+ return pEntry;
+}
+
+SvTreeListEntry* SvTabListBox::GetChildOnPos( SvTreeListEntry* _pParent, sal_uInt32 _nEntryPos, sal_uInt32& _rPos ) const
+{
+ sal_uInt32 i, nCount = GetLevelChildCount( _pParent );
+ for ( i = 0; i < nCount; ++i )
+ {
+ SvTreeListEntry* pParent = GetEntry( _pParent, i );
+ if ( _rPos == _nEntryPos )
+ return pParent;
+ else
+ {
+ _rPos++;
+ SvTreeListEntry* pEntry = GetChildOnPos( pParent, _nEntryPos, _rPos );
+ if ( pEntry )
+ return pEntry;
+ }
+ }
+
+ return nullptr;
+}
+
+void SvTabListBox::SetTabJustify( sal_uInt16 nTab, SvTabJustify eJustify)
+{
+ DBG_ASSERT(nTab<mvTabList.size(),"GetTabPos:Invalid Tab");
+ if( nTab >= mvTabList.size() )
+ return;
+ SvLBoxTab& rTab = mvTabList[ nTab ];
+ SvLBoxTabFlags nFlags = rTab.nFlags;
+ nFlags &= ~MYTABMASK;
+ // see SvLBoxTab::CalcOffset for force, which only matters for centering
+ nFlags |= static_cast<SvLBoxTabFlags>(eJustify) | SvLBoxTabFlags::FORCE;
+ rTab.nFlags = nFlags;
+ SvTreeListBox::nTreeFlags |= SvTreeFlags::RECALCTABS;
+ if( IsUpdateMode() )
+ Invalidate();
+}
+
+void SvTabListBox::SetTabEditable(sal_uInt16 nTab, bool bEditable)
+{
+ DBG_ASSERT(nTab<mvTabList.size(),"GetTabPos:Invalid Tab");
+ if( nTab >= mvTabList.size() )
+ return;
+ SvLBoxTab& rTab = mvTabList[ nTab ];
+ if (bEditable)
+ rTab.nFlags |= SvLBoxTabFlags::EDITABLE;
+ else
+ rTab.nFlags &= ~SvLBoxTabFlags::EDITABLE;
+}
+
+tools::Long SvTabListBox::GetLogicTab( sal_uInt16 nTab )
+{
+ if( SvTreeListBox::nTreeFlags & SvTreeFlags::RECALCTABS )
+ SetTabs();
+
+ DBG_ASSERT(nTab<mvTabList.size(),"GetTabPos:Invalid Tab");
+ return aTabs[ nTab ]->GetPos();
+}
+
+namespace vcl
+{
+ struct SvHeaderTabListBoxImpl
+ {
+ VclPtr<HeaderBar> m_pHeaderBar;
+ AccessibleFactoryAccess m_aFactoryAccess;
+
+ SvHeaderTabListBoxImpl() : m_pHeaderBar( nullptr ) { }
+ };
+}
+
+SvHeaderTabListBox::SvHeaderTabListBox( vcl::Window* pParent, WinBits nWinStyle )
+ : SvTabListBox(pParent, nWinStyle)
+ , m_bFirstPaint(true)
+ , m_pImpl(new ::vcl::SvHeaderTabListBoxImpl)
+ , m_pAccessible(nullptr)
+{
+}
+
+SvHeaderTabListBox::~SvHeaderTabListBox()
+{
+ disposeOnce();
+}
+
+void SvHeaderTabListBox::dispose()
+{
+ m_pImpl.reset();
+ SvTabListBox::dispose();
+}
+
+void SvHeaderTabListBox::Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect )
+{
+ if (m_bFirstPaint)
+ {
+ m_bFirstPaint = false;
+ }
+ SvTabListBox::Paint(rRenderContext, rRect);
+}
+
+void SvHeaderTabListBox::InitHeaderBar( HeaderBar* pHeaderBar )
+{
+ DBG_ASSERT( !m_pImpl->m_pHeaderBar, "header bar already initialized" );
+ DBG_ASSERT( pHeaderBar, "invalid header bar initialization" );
+ m_pImpl->m_pHeaderBar = pHeaderBar;
+ SetScrolledHdl( LINK( this, SvHeaderTabListBox, ScrollHdl_Impl ) );
+ m_pImpl->m_pHeaderBar->SetCreateAccessibleHdl( LINK( this, SvHeaderTabListBox, CreateAccessibleHdl_Impl ) );
+}
+
+HeaderBar* SvHeaderTabListBox::GetHeaderBar()
+{
+ return m_pImpl ? m_pImpl->m_pHeaderBar : nullptr;
+}
+
+bool SvHeaderTabListBox::IsItemChecked( SvTreeListEntry* pEntry, sal_uInt16 nCol )
+{
+ SvButtonState eState = SvButtonState::Unchecked;
+ SvLBoxButton& rItem = static_cast<SvLBoxButton&>( pEntry->GetItem( nCol + 1 ) );
+
+ if (rItem.GetType() == SvLBoxItemType::Button)
+ {
+ SvItemStateFlags nButtonFlags = rItem.GetButtonFlags();
+ eState = SvLBoxButtonData::ConvertToButtonState( nButtonFlags );
+ }
+
+ return ( eState == SvButtonState::Checked );
+}
+
+SvTreeListEntry* SvHeaderTabListBox::InsertEntryToColumn(
+ const OUString& rStr, SvTreeListEntry* pParent, sal_uInt32 nPos, sal_uInt16 nCol, void* pUserData )
+{
+ SvTreeListEntry* pEntry = SvTabListBox::InsertEntryToColumn( rStr, pParent, nPos, nCol, pUserData );
+ RecalculateAccessibleChildren();
+ return pEntry;
+}
+
+sal_uInt32 SvHeaderTabListBox::Insert(
+ SvTreeListEntry* pEnt, SvTreeListEntry* pPar, sal_uInt32 nPos )
+{
+ sal_uInt32 n = SvTabListBox::Insert( pEnt, pPar, nPos );
+ RecalculateAccessibleChildren();
+ return n;
+}
+
+sal_uInt32 SvHeaderTabListBox::Insert( SvTreeListEntry* pEntry, sal_uInt32 nRootPos )
+{
+ sal_uInt32 nPos = SvTabListBox::Insert( pEntry, nRootPos );
+ RecalculateAccessibleChildren();
+ return nPos;
+}
+
+void SvHeaderTabListBox::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter)
+{
+ SvTabListBox::DumpAsPropertyTree(rJsonWriter);
+
+ auto aHeaders = rJsonWriter.startArray("headers");
+
+ HeaderBar* pHeaderBar = GetHeaderBar();
+ for(sal_uInt16 i = 0; i < pHeaderBar->GetItemCount(); i++)
+ {
+ auto aNode = rJsonWriter.startStruct();
+ rJsonWriter.put("text", pHeaderBar->GetItemText(pHeaderBar->GetItemId(i)));
+ }
+}
+
+IMPL_LINK_NOARG(SvHeaderTabListBox, ScrollHdl_Impl, SvTreeListBox*, void)
+{
+ m_pImpl->m_pHeaderBar->SetOffset( -GetXOffset() );
+}
+
+IMPL_LINK_NOARG(SvHeaderTabListBox, CreateAccessibleHdl_Impl, HeaderBar*, void)
+{
+ vcl::Window* pParent = m_pImpl->m_pHeaderBar->GetAccessibleParentWindow();
+ DBG_ASSERT( pParent, "SvHeaderTabListBox..CreateAccessibleHdl_Impl - accessible parent not found" );
+ if ( pParent )
+ {
+ css::uno::Reference< XAccessible > xAccParent = pParent->GetAccessible();
+ if ( xAccParent.is() )
+ {
+ Reference< XAccessible > xAccessible = m_pImpl->m_aFactoryAccess.getFactory().createAccessibleBrowseBoxHeaderBar(
+ xAccParent, *this, AccessibleBrowseBoxObjType::ColumnHeaderBar );
+ m_pImpl->m_pHeaderBar->SetAccessible( xAccessible );
+ }
+ }
+}
+
+void SvHeaderTabListBox::RecalculateAccessibleChildren()
+{
+ if ( !m_aAccessibleChildren.empty() )
+ {
+ sal_uInt32 nCount = ( GetRowCount() + 1 ) * GetColumnCount();
+ if ( m_aAccessibleChildren.size() < nCount )
+ m_aAccessibleChildren.resize( nCount );
+ else
+ {
+ DBG_ASSERT( m_aAccessibleChildren.size() == nCount, "wrong children count" );
+ }
+ }
+}
+
+bool SvHeaderTabListBox::IsCellCheckBox( sal_Int32 _nRow, sal_uInt16 _nColumn, TriState& _rState ) const
+{
+ bool bRet = false;
+ SvTreeListEntry* pEntry = GetEntry( _nRow );
+ if ( pEntry )
+ {
+ sal_uInt16 nItemCount = pEntry->ItemCount();
+ if ( nItemCount > ( _nColumn + 1 ) )
+ {
+ SvLBoxItem& rItem = pEntry->GetItem( _nColumn + 1 );
+ if (rItem.GetType() == SvLBoxItemType::Button)
+ {
+ bRet = true;
+ _rState = ( ( static_cast<SvLBoxButton&>(rItem).GetButtonFlags() & SvItemStateFlags::UNCHECKED ) == SvItemStateFlags::NONE )
+ ? TRISTATE_TRUE : TRISTATE_FALSE;
+ }
+ }
+ else
+ {
+ SAL_WARN( "svtools.contnr", "SvHeaderTabListBox::IsCellCheckBox(): column out of range" );
+ }
+ }
+ return bRet;
+}
+sal_Int32 SvHeaderTabListBox::GetRowCount() const
+{
+ return GetEntryCount();
+}
+
+sal_uInt16 SvHeaderTabListBox::GetColumnCount() const
+{
+ return m_pImpl->m_pHeaderBar->GetItemCount();
+}
+
+sal_Int32 SvHeaderTabListBox::GetCurrRow() const
+{
+ sal_Int32 nRet = -1;
+ SvTreeListEntry* pEntry = GetCurEntry();
+ if ( pEntry )
+ {
+ sal_uInt32 nCount = GetEntryCount();
+ for ( sal_uInt32 i = 0; i < nCount; ++i )
+ {
+ if ( pEntry == GetEntry(i) )
+ {
+ nRet = i;
+ break;
+ }
+ }
+ }
+
+ return nRet;
+}
+
+sal_uInt16 SvHeaderTabListBox::GetCurrColumn() const
+{
+ return 0;
+}
+
+OUString SvHeaderTabListBox::GetRowDescription( sal_Int32 _nRow ) const
+{
+ return GetEntryText( _nRow );
+}
+
+OUString SvHeaderTabListBox::GetColumnDescription( sal_uInt16 _nColumn ) const
+{
+ return m_pImpl->m_pHeaderBar->GetItemText( m_pImpl->m_pHeaderBar->GetItemId( _nColumn ) );
+}
+
+bool SvHeaderTabListBox::HasRowHeader() const
+{
+ return false;
+}
+
+bool SvHeaderTabListBox::GoToCell( sal_Int32 /*_nRow*/, sal_uInt16 /*_nColumn*/ )
+{
+ return false;
+}
+
+void SvHeaderTabListBox::SetNoSelection()
+{
+ SvTreeListBox::SelectAll(false);
+}
+
+void SvHeaderTabListBox::SelectAll()
+{
+ SvTreeListBox::SelectAll(true);
+}
+
+void SvHeaderTabListBox::SelectRow( sal_Int32 _nRow, bool _bSelect, bool )
+{
+ Select( GetEntry( _nRow ), _bSelect );
+}
+
+void SvHeaderTabListBox::SelectColumn( sal_uInt16, bool )
+{
+}
+
+sal_Int32 SvHeaderTabListBox::GetSelectedRowCount() const
+{
+ return GetSelectionCount();
+}
+
+sal_Int32 SvHeaderTabListBox::GetSelectedColumnCount() const
+{
+ return 0;
+}
+
+bool SvHeaderTabListBox::IsRowSelected( sal_Int32 _nRow ) const
+{
+ SvTreeListEntry* pEntry = GetEntry( _nRow );
+ return ( pEntry && IsSelected( pEntry ) );
+}
+
+bool SvHeaderTabListBox::IsColumnSelected( sal_Int32 ) const
+{
+ return false;
+}
+
+void SvHeaderTabListBox::GetAllSelectedRows( css::uno::Sequence< sal_Int32 >& ) const
+{
+}
+
+void SvHeaderTabListBox::GetAllSelectedColumns( css::uno::Sequence< sal_Int32 >& ) const
+{
+}
+
+bool SvHeaderTabListBox::IsCellVisible( sal_Int32, sal_uInt16 ) const
+{
+ return true;
+}
+
+OUString SvHeaderTabListBox::GetAccessibleCellText( sal_Int32 _nRow, sal_uInt16 _nColumnPos ) const
+{
+ return GetTabEntryText(_nRow, _nColumnPos);
+}
+
+tools::Rectangle SvHeaderTabListBox::calcHeaderRect( bool _bIsColumnBar, bool _bOnScreen )
+{
+ tools::Rectangle aRect;
+ if ( _bIsColumnBar )
+ {
+ vcl::Window* pParent = nullptr;
+ if ( !_bOnScreen )
+ pParent = m_pImpl->m_pHeaderBar->GetAccessibleParentWindow();
+
+ aRect = m_pImpl->m_pHeaderBar->GetWindowExtentsRelative( pParent );
+ }
+ return aRect;
+}
+
+tools::Rectangle SvHeaderTabListBox::calcTableRect( bool _bOnScreen )
+{
+ vcl::Window* pParent = nullptr;
+ if ( !_bOnScreen )
+ pParent = GetAccessibleParentWindow();
+
+ tools::Rectangle aRect( GetWindowExtentsRelative( pParent ) );
+ return aRect;
+}
+
+tools::Rectangle SvHeaderTabListBox::GetFieldRectPixelAbs( sal_Int32 _nRow, sal_uInt16 _nColumn, bool _bIsHeader, bool _bOnScreen )
+{
+ DBG_ASSERT( !_bIsHeader || 0 == _nRow, "invalid parameters" );
+ tools::Rectangle aRect;
+ SvTreeListEntry* pEntry = GetEntry( _nRow );
+ if ( pEntry )
+ {
+ aRect = _bIsHeader ? calcHeaderRect( true, false ) : GetBoundingRect( pEntry );
+ Point aTopLeft = aRect.TopLeft();
+ DBG_ASSERT( m_pImpl->m_pHeaderBar->GetItemCount() > _nColumn, "invalid column" );
+ tools::Rectangle aItemRect = m_pImpl->m_pHeaderBar->GetItemRect( m_pImpl->m_pHeaderBar->GetItemId( _nColumn ) );
+ aTopLeft.setX( aItemRect.Left() );
+ Size aSize = aItemRect.GetSize();
+ aRect = tools::Rectangle( aTopLeft, aSize );
+ vcl::Window* pParent = nullptr;
+ if ( !_bOnScreen )
+ pParent = GetAccessibleParentWindow();
+ aTopLeft = aRect.TopLeft();
+ aTopLeft += GetWindowExtentsRelative( pParent ).TopLeft();
+ aRect = tools::Rectangle( aTopLeft, aRect.GetSize() );
+ }
+
+ return aRect;
+}
+
+Reference< XAccessible > SvHeaderTabListBox::CreateAccessibleCell( sal_Int32 _nRow, sal_uInt16 _nColumnPos )
+{
+ OSL_ENSURE( m_pAccessible, "Invalid call: Accessible is null" );
+
+ Reference< XAccessible > xChild;
+
+ TriState eState = TRISTATE_INDET;
+ bool bIsCheckBox = IsCellCheckBox( _nRow, _nColumnPos, eState );
+ if ( bIsCheckBox )
+ xChild = m_pImpl->m_aFactoryAccess.getFactory().createAccessibleCheckBoxCell(
+ m_pAccessible->getHeaderBar(), *this, nullptr, _nRow, _nColumnPos, eState, false );
+ else
+ xChild = m_pImpl->m_aFactoryAccess.getFactory().createAccessibleBrowseBoxTableCell(
+ m_pAccessible->getHeaderBar(), *this, nullptr, _nRow, _nColumnPos, OFFSET_NONE );
+
+ return xChild;
+}
+
+Reference< XAccessible > SvHeaderTabListBox::CreateAccessibleRowHeader( sal_Int32 )
+{
+ Reference< XAccessible > xHeader;
+ return xHeader;
+}
+
+Reference< XAccessible > SvHeaderTabListBox::CreateAccessibleColumnHeader( sal_uInt16 _nColumn )
+{
+ // first call? -> initial list
+ if ( m_aAccessibleChildren.empty() )
+ {
+ const sal_uInt16 nColumnCount = GetColumnCount();
+ m_aAccessibleChildren.assign( nColumnCount, Reference< XAccessible >() );
+ }
+
+ // get header
+ Reference< XAccessible > xChild = m_aAccessibleChildren[ _nColumn ];
+ // already exists?
+ if ( !xChild.is() && m_pAccessible )
+ {
+ // no -> create new header cell
+ xChild = m_pImpl->m_aFactoryAccess.getFactory().createAccessibleBrowseBoxHeaderCell(
+ _nColumn, m_pAccessible->getHeaderBar(),
+ *this, nullptr, AccessibleBrowseBoxObjType::ColumnHeaderCell
+ );
+
+ // insert into list
+ m_aAccessibleChildren[ _nColumn ] = xChild;
+ }
+ return xChild;
+}
+
+sal_Int32 SvHeaderTabListBox::GetAccessibleControlCount() const
+{
+ return -1;
+}
+
+Reference< XAccessible > SvHeaderTabListBox::CreateAccessibleControl( sal_Int32 )
+{
+ Reference< XAccessible > xControl;
+ return xControl;
+}
+
+bool SvHeaderTabListBox::ConvertPointToControlIndex( sal_Int32&, const Point& )
+{
+ return false;
+}
+
+bool SvHeaderTabListBox::ConvertPointToCellAddress( sal_Int32&, sal_uInt16&, const Point& )
+{
+ return false;
+}
+
+bool SvHeaderTabListBox::ConvertPointToRowHeader( sal_Int32&, const Point& )
+{
+ return false;
+}
+
+bool SvHeaderTabListBox::ConvertPointToColumnHeader( sal_uInt16&, const Point& )
+{
+ return false;
+}
+
+OUString SvHeaderTabListBox::GetAccessibleObjectName( AccessibleBrowseBoxObjType _eType, sal_Int32 _nPos ) const
+{
+ OUString aRetText;
+ switch( _eType )
+ {
+ case AccessibleBrowseBoxObjType::BrowseBox:
+ case AccessibleBrowseBoxObjType::Table:
+ case AccessibleBrowseBoxObjType::ColumnHeaderBar:
+ // should be empty now (see #i63983)
+ aRetText.clear();
+ break;
+
+ case AccessibleBrowseBoxObjType::TableCell:
+ {
+ // here we need a valid pos, we can not handle -1
+ if ( _nPos >= 0 )
+ {
+ sal_uInt16 nColumnCount = GetColumnCount();
+ if (nColumnCount > 0)
+ {
+ sal_Int32 nRow = _nPos / nColumnCount;
+ sal_uInt16 nColumn = static_cast< sal_uInt16 >( _nPos % nColumnCount );
+ aRetText = GetCellText( nRow, nColumn );
+ }
+ }
+ break;
+ }
+ case AccessibleBrowseBoxObjType::CheckBoxCell:
+ {
+ break; // checkbox cells have no name
+ }
+ case AccessibleBrowseBoxObjType::ColumnHeaderCell:
+ {
+ aRetText = m_pImpl->m_pHeaderBar->GetItemText( m_pImpl->m_pHeaderBar->GetItemId( static_cast<sal_uInt16>(_nPos) ) );
+ break;
+ }
+
+ case AccessibleBrowseBoxObjType::RowHeaderBar:
+ case AccessibleBrowseBoxObjType::RowHeaderCell:
+ aRetText = "error";
+ break;
+
+ default:
+ OSL_FAIL("BrowseBox::GetAccessibleName: invalid enum!");
+ }
+ return aRetText;
+}
+
+OUString SvHeaderTabListBox::GetAccessibleObjectDescription( AccessibleBrowseBoxObjType _eType, sal_Int32 _nPos ) const
+{
+ OUString aRetText;
+
+ if( _eType == AccessibleBrowseBoxObjType::TableCell && _nPos != -1 )
+ {
+ sal_uInt16 nColumnCount = GetColumnCount();
+ if (nColumnCount > 0)
+ {
+ sal_Int32 nRow = _nPos / nColumnCount;
+ sal_uInt16 nColumn = static_cast< sal_uInt16 >( _nPos % nColumnCount );
+
+ OUString aText( VclResId(STR_SVT_ACC_DESC_TABLISTBOX) );
+ aText = aText.replaceFirst( "%1", OUString::number( nRow ) );
+ OUString sColHeader = m_pImpl->m_pHeaderBar->GetItemText( m_pImpl->m_pHeaderBar->GetItemId( nColumn ) );
+ if ( sColHeader.isEmpty() )
+ sColHeader = OUString::number( nColumn );
+ aText = aText.replaceFirst( "%2", sColHeader );
+ aRetText = aText;
+ }
+ }
+
+ return aRetText;
+}
+
+void SvHeaderTabListBox::FillAccessibleStateSet( ::utl::AccessibleStateSetHelper& _rStateSet, AccessibleBrowseBoxObjType _eType ) const
+{
+ switch( _eType )
+ {
+ case AccessibleBrowseBoxObjType::BrowseBox:
+ case AccessibleBrowseBoxObjType::Table:
+ {
+ _rStateSet.AddState( AccessibleStateType::FOCUSABLE );
+ if ( HasFocus() )
+ _rStateSet.AddState( AccessibleStateType::FOCUSED );
+ if ( IsActive() )
+ _rStateSet.AddState( AccessibleStateType::ACTIVE );
+ if ( IsEnabled() )
+ {
+ _rStateSet.AddState( AccessibleStateType::ENABLED );
+ _rStateSet.AddState( AccessibleStateType::SENSITIVE );
+ }
+ if ( IsReallyVisible() )
+ _rStateSet.AddState( AccessibleStateType::VISIBLE );
+ if ( _eType == AccessibleBrowseBoxObjType::Table )
+ {
+
+ _rStateSet.AddState( AccessibleStateType::MANAGES_DESCENDANTS );
+ _rStateSet.AddState( AccessibleStateType::MULTI_SELECTABLE );
+ }
+ break;
+ }
+
+ case AccessibleBrowseBoxObjType::ColumnHeaderBar:
+ {
+ sal_Int32 nCurRow = GetCurrRow();
+ sal_uInt16 nCurColumn = GetCurrColumn();
+ if ( IsCellVisible( nCurRow, nCurColumn ) )
+ _rStateSet.AddState( AccessibleStateType::VISIBLE );
+ if ( IsEnabled() )
+ _rStateSet.AddState( AccessibleStateType::ENABLED );
+ _rStateSet.AddState( AccessibleStateType::TRANSIENT );
+ break;
+ }
+
+ case AccessibleBrowseBoxObjType::RowHeaderCell:
+ case AccessibleBrowseBoxObjType::ColumnHeaderCell:
+ {
+ _rStateSet.AddState( AccessibleStateType::VISIBLE );
+ _rStateSet.AddState( AccessibleStateType::FOCUSABLE );
+ _rStateSet.AddState( AccessibleStateType::TRANSIENT );
+ if ( IsEnabled() )
+ _rStateSet.AddState( AccessibleStateType::ENABLED );
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void SvHeaderTabListBox::FillAccessibleStateSetForCell( ::utl::AccessibleStateSetHelper& _rStateSet, sal_Int32 _nRow, sal_uInt16 _nColumn ) const
+{
+ _rStateSet.AddState( AccessibleStateType::SELECTABLE );
+ _rStateSet.AddState( AccessibleStateType::TRANSIENT );
+
+ if ( IsCellVisible( _nRow, _nColumn ) )
+ {
+ _rStateSet.AddState( AccessibleStateType::VISIBLE );
+ _rStateSet.AddState( AccessibleStateType::ENABLED );
+ }
+
+ if ( IsRowSelected( _nRow ) )
+ {
+ _rStateSet.AddState( AccessibleStateType::ACTIVE );
+ _rStateSet.AddState( AccessibleStateType::SELECTED );
+ }
+ if ( IsEnabled() )
+ _rStateSet.AddState( AccessibleStateType::ENABLED );
+}
+
+void SvHeaderTabListBox::GrabTableFocus()
+{
+ GrabFocus();
+}
+
+bool SvHeaderTabListBox::GetGlyphBoundRects( const Point& rOrigin, const OUString& rStr, int nIndex, int nLen, std::vector< tools::Rectangle >& rVector )
+{
+ return GetOutDev()->GetGlyphBoundRects( rOrigin, rStr, nIndex, nLen, rVector );
+}
+
+tools::Rectangle SvHeaderTabListBox::GetWindowExtentsRelative(const vcl::Window *pRelativeWindow) const
+{
+ return Control::GetWindowExtentsRelative( pRelativeWindow );
+}
+
+void SvHeaderTabListBox::GrabFocus()
+{
+ Control::GrabFocus();
+}
+
+Reference< XAccessible > SvHeaderTabListBox::GetAccessible()
+{
+ return Control::GetAccessible();
+}
+
+vcl::Window* SvHeaderTabListBox::GetAccessibleParentWindow() const
+{
+ return Control::GetAccessibleParentWindow();
+}
+
+vcl::Window* SvHeaderTabListBox::GetWindowInstance()
+{
+ return this;
+}
+
+Reference< XAccessible > SvHeaderTabListBox::CreateAccessible()
+{
+ vcl::Window* pParent = GetAccessibleParentWindow();
+ DBG_ASSERT( pParent, "SvHeaderTabListBox::::CreateAccessible - accessible parent not found" );
+
+ Reference< XAccessible > xAccessible;
+ if ( m_pAccessible ) xAccessible = m_pAccessible->getMyself();
+
+ if( pParent && !m_pAccessible )
+ {
+ Reference< XAccessible > xAccParent = pParent->GetAccessible();
+ if ( xAccParent.is() )
+ {
+ m_pAccessible = m_pImpl->m_aFactoryAccess.getFactory().createAccessibleTabListBox( xAccParent, *this );
+ if ( m_pAccessible )
+ xAccessible = m_pAccessible->getMyself();
+ }
+ }
+ return xAccessible;
+}
+
+tools::Rectangle SvHeaderTabListBox::GetFieldCharacterBounds(sal_Int32,sal_Int32,sal_Int32)
+{
+ return tools::Rectangle();
+}
+
+sal_Int32 SvHeaderTabListBox::GetFieldIndexAtPoint(sal_Int32 _nRow,sal_Int32 _nColumnPos,const Point& _rPoint)
+{
+ OUString sText = GetAccessibleCellText( _nRow, static_cast< sal_uInt16 >( _nColumnPos ) );
+ std::vector< tools::Rectangle > aRects;
+ if ( GetGlyphBoundRects(Point(0,0), sText, 0, sText.getLength(), aRects) )
+ {
+ sal_Int32 nPos = 0;
+ for (auto const& rectangle : aRects)
+ {
+ if( rectangle.Contains(_rPoint) )
+ return nPos;
+ ++nPos;
+ }
+ }
+
+ return -1;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */