summaryrefslogtreecommitdiff
path: root/vcl/source
diff options
context:
space:
mode:
authorCaolán McNamara <caolanm@redhat.com>2018-11-17 21:37:50 +0000
committerCaolán McNamara <caolanm@redhat.com>2018-11-21 22:08:04 +0100
commit47897fdd936d9b6e9ac8cb6110c79352ab080df7 (patch)
treec657b53080caa94590d1e9b1fd4383d6dc795728 /vcl/source
parentcfa76f538a44d4396574ece59e8a3953c22c6eb7 (diff)
weld SwCondCollPage
and put back original SvTreeListBox a11y factory use Change-Id: I4ad8ce29d8fed6ec5d44e9a1d641919a89226b79 Reviewed-on: https://gerrit.libreoffice.org/63501 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caolanm@redhat.com> Tested-by: Caolán McNamara <caolanm@redhat.com>
Diffstat (limited to 'vcl/source')
-rw-r--r--vcl/source/app/salvtables.cxx60
-rw-r--r--vcl/source/helper/svtaccessiblefactory.cxx270
-rw-r--r--vcl/source/treelist/headbar.cxx1354
-rw-r--r--vcl/source/treelist/svtabbx.cxx1155
-rw-r--r--vcl/source/treelist/treelistbox.cxx21
-rw-r--r--vcl/source/window/builder.cxx16
6 files changed, 2855 insertions, 21 deletions
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx
index ea574dd322dc..248ea5b0fef1 100644
--- a/vcl/source/app/salvtables.cxx
+++ b/vcl/source/app/salvtables.cxx
@@ -45,9 +45,9 @@
#include <vcl/slider.hxx>
#include <vcl/sysdata.hxx>
#include <vcl/svlbitm.hxx>
+#include <vcl/svtabbx.hxx>
#include <vcl/tabctrl.hxx>
#include <vcl/tabpage.hxx>
-#include <vcl/treelistbox.hxx>
#include <vcl/treelistentry.hxx>
#include <vcl/toolkit/unowrap.hxx>
#include <vcl/weld.hxx>
@@ -1039,7 +1039,7 @@ public:
virtual int get_vscroll_width() const override
{
- return m_xScrolledWindow->getVertScrollBar().GetSizePixel().Width();
+ return m_xScrolledWindow->getVertScrollBar().get_preferred_size().Width();
}
virtual void set_user_managed_scrolling() override
@@ -1764,14 +1764,14 @@ class SalInstanceTreeView : public SalInstanceContainer, public virtual weld::Tr
private:
// owner for UserData
std::vector<std::unique_ptr<OUString>> m_aUserData;
- VclPtr<SvTreeListBox> m_xTreeView;
+ VclPtr<SvTabListBox> m_xTreeView;
DECL_LINK(SelectHdl, SvTreeListBox*, void);
DECL_LINK(DoubleClickHdl, SvTreeListBox*, bool);
DECL_LINK(ExpandingHdl, SvTreeListBox*, bool);
public:
- SalInstanceTreeView(SvTreeListBox* pTreeView, bool bTakeOwnership)
+ SalInstanceTreeView(SvTabListBox* pTreeView, bool bTakeOwnership)
: SalInstanceContainer(pTreeView, bTakeOwnership)
, m_xTreeView(pTreeView)
{
@@ -1779,6 +1779,16 @@ public:
m_xTreeView->SetSelectHdl(LINK(this, SalInstanceTreeView, SelectHdl));
m_xTreeView->SetDoubleClickHdl(LINK(this, SalInstanceTreeView, DoubleClickHdl));
m_xTreeView->SetExpandingHdl(LINK(this, SalInstanceTreeView, ExpandingHdl));
+ const long aTabPositions[] = { 0 };
+ m_xTreeView->SetTabs(SAL_N_ELEMENTS(aTabPositions), aTabPositions);
+ }
+
+ virtual void set_column_fixed_widths(const std::vector<int>& rWidths) override
+ {
+ std::vector<long> aTabPositions;
+ aTabPositions.push_back(0);
+ aTabPositions.insert(aTabPositions.end(), rWidths.begin(), rWidths.end());
+ m_xTreeView->SetTabs(aTabPositions.size(), aTabPositions.data(), MapUnit::MapPixel);
}
virtual void insert(weld::TreeIter* pParent, int pos, const OUString& rStr, const OUString* pId,
@@ -1916,10 +1926,44 @@ public:
return aRows;
}
- virtual OUString get_text(int pos) const override
+ virtual OUString get_text(int pos, int col) const override
+ {
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ if (col == -1)
+ return SvTabListBox::GetEntryText(pEntry, 0);
+
+ if (static_cast<size_t>(col) == pEntry->ItemCount())
+ return OUString();
+
+ assert(col >= 0 && static_cast<size_t>(col) < pEntry->ItemCount());
+ SvLBoxItem& rItem = pEntry->GetItem(col);
+ assert(dynamic_cast<SvLBoxString*>(&rItem));
+ return static_cast<SvLBoxString&>(rItem).GetText();
+ }
+
+ virtual void set_text(int pos, const OUString& rText, int col) override
{
SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
- return m_xTreeView->GetEntryText(pEntry);
+ if (col == -1)
+ {
+ m_xTreeView->SetEntryText(pEntry, rText);
+ return;
+ }
+
+ ++col; //skip dummy/expander column
+
+ if (static_cast<size_t>(col) == pEntry->ItemCount())
+ {
+ pEntry->AddItem(o3tl::make_unique<SvLBoxString>(rText));
+ }
+ else
+ {
+ assert(col >= 0 && static_cast<size_t>(col) < pEntry->ItemCount());
+ SvLBoxItem& rItem = pEntry->GetItem(col);
+ assert(dynamic_cast<SvLBoxString*>(&rItem));
+ static_cast<SvLBoxString&>(rItem).SetText(rText);
+ }
+ m_xTreeView->ModelHasEntryInvalidated(pEntry);
}
const OUString* getEntryData(int index) const
@@ -2115,7 +2159,7 @@ public:
m_xTreeView->SetStyle(m_xTreeView->GetStyle() | WB_SORT);
}
- SvTreeListBox& getTreeView()
+ SvTabListBox& getTreeView()
{
return *m_xTreeView;
}
@@ -3248,7 +3292,7 @@ public:
virtual std::unique_ptr<weld::TreeView> weld_tree_view(const OString &id, bool bTakeOwnership) override
{
- SvTreeListBox* pTreeView = m_xBuilder->get<SvTreeListBox>(id);
+ SvTabListBox* pTreeView = m_xBuilder->get<SvTabListBox>(id);
return pTreeView ? o3tl::make_unique<SalInstanceTreeView>(pTreeView, bTakeOwnership) : nullptr;
}
diff --git a/vcl/source/helper/svtaccessiblefactory.cxx b/vcl/source/helper/svtaccessiblefactory.cxx
new file mode 100644
index 000000000000..2f1410048cb7
--- /dev/null
+++ b/vcl/source/helper/svtaccessiblefactory.cxx
@@ -0,0 +1,270 @@
+/* -*- 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 <config_features.h>
+
+#include <vcl/svtaccessiblefactory.hxx>
+
+#include <tools/svlibrary.h>
+
+#include <osl/module.h>
+#include <osl/diagnose.h>
+
+namespace vcl
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::awt;
+ using namespace ::com::sun::star::accessibility;
+
+ namespace
+ {
+#ifndef DISABLE_DYNLOADING
+ static oslModule s_hAccessibleImplementationModule = nullptr;
+#endif
+#if HAVE_FEATURE_DESKTOP
+ static GetSvtAccessibilityComponentFactory s_pAccessibleFactoryFunc = nullptr;
+#endif
+ static ::rtl::Reference< IAccessibleFactory > s_pFactory;
+
+
+ //= AccessibleDummyFactory
+
+ class AccessibleDummyFactory:
+ public IAccessibleFactory
+ {
+ public:
+ AccessibleDummyFactory();
+ AccessibleDummyFactory(const AccessibleDummyFactory&) = delete;
+ AccessibleDummyFactory& operator=(const AccessibleDummyFactory&) = delete;
+
+ protected:
+ virtual ~AccessibleDummyFactory() override;
+
+ public:
+ // IAccessibleFactory
+ virtual vcl::IAccessibleTabListBox*
+ createAccessibleTabListBox(
+ const css::uno::Reference< css::accessibility::XAccessible >& /*rxParent*/,
+ SvHeaderTabListBox& /*rBox*/
+ ) const override
+ {
+ return nullptr;
+ }
+
+ virtual css::uno::Reference< css::accessibility::XAccessible >
+ createAccessibleTreeListBox(
+ SvTreeListBox& /*_rListBox*/,
+ const css::uno::Reference< css::accessibility::XAccessible >& /*_xParent*/
+ ) const override
+ {
+ return nullptr;
+ }
+
+ virtual vcl::IAccessibleBrowseBox*
+ createAccessibleBrowseBox(
+ const css::uno::Reference< css::accessibility::XAccessible >& /*_rxParent*/,
+ vcl::IAccessibleTableProvider& /*_rBrowseBox*/
+ ) const override
+ {
+ return nullptr;
+ }
+
+ virtual table::IAccessibleTableControl*
+ createAccessibleTableControl(
+ const css::uno::Reference< css::accessibility::XAccessible >& /*_rxParent*/,
+ table::IAccessibleTable& /*_rTable*/
+ ) const override
+ {
+ return nullptr;
+ }
+
+ virtual css::uno::Reference< css::accessibility::XAccessible >
+ createAccessibleIconChoiceCtrl(
+ SvtIconChoiceCtrl& /*_rIconCtrl*/,
+ const css::uno::Reference< css::accessibility::XAccessible >& /*_xParent*/
+ ) const override
+ {
+ return nullptr;
+ }
+
+ virtual css::uno::Reference< css::accessibility::XAccessible >
+ createAccessibleTabBar(
+ TabBar& /*_rTabBar*/
+ ) const override
+ {
+ return nullptr;
+ }
+
+ virtual css::uno::Reference< css::accessibility::XAccessibleContext >
+ createAccessibleTextWindowContext(
+ VCLXWindow* /*pVclXWindow*/, TextEngine& /*rEngine*/, TextView& /*rView*/
+ ) const override
+ {
+ return nullptr;
+ }
+
+ virtual css::uno::Reference< css::accessibility::XAccessible >
+ createAccessibleBrowseBoxHeaderBar(
+ const css::uno::Reference< css::accessibility::XAccessible >& /*rxParent*/,
+ vcl::IAccessibleTableProvider& /*_rOwningTable*/,
+ vcl::AccessibleBrowseBoxObjType /*_eObjType*/
+ ) const override
+ {
+ return nullptr;
+ }
+
+ virtual css::uno::Reference< css::accessibility::XAccessible >
+ createAccessibleBrowseBoxTableCell(
+ const css::uno::Reference< css::accessibility::XAccessible >& /*_rxParent*/,
+ vcl::IAccessibleTableProvider& /*_rBrowseBox*/,
+ const css::uno::Reference< css::awt::XWindow >& /*_xFocusWindow*/,
+ sal_Int32 /*_nRowId*/,
+ sal_uInt16 /*_nColId*/,
+ sal_Int32 /*_nOffset*/
+ ) const override
+ {
+ return nullptr;
+ }
+
+ virtual css::uno::Reference< css::accessibility::XAccessible >
+ createAccessibleBrowseBoxHeaderCell(
+ sal_Int32 /*_nColumnRowId*/,
+ const css::uno::Reference< css::accessibility::XAccessible >& /*rxParent*/,
+ vcl::IAccessibleTableProvider& /*_rBrowseBox*/,
+ const css::uno::Reference< css::awt::XWindow >& /*_xFocusWindow*/,
+ vcl::AccessibleBrowseBoxObjType /*_eObjType*/
+ ) const override
+ {
+ return nullptr;
+ }
+
+ virtual css::uno::Reference< css::accessibility::XAccessible >
+ createAccessibleCheckBoxCell(
+ const css::uno::Reference< css::accessibility::XAccessible >& /*_rxParent*/,
+ vcl::IAccessibleTableProvider& /*_rBrowseBox*/,
+ const css::uno::Reference< css::awt::XWindow >& /*_xFocusWindow*/,
+ sal_Int32 /*_nRowPos*/,
+ sal_uInt16 /*_nColPos*/,
+ const TriState& /*_eState*/,
+ bool /*_bIsTriState*/
+ ) const override
+ {
+ return nullptr;
+ }
+
+ virtual css::uno::Reference< css::accessibility::XAccessible >
+ createEditBrowseBoxTableCellAccess(
+ const css::uno::Reference< css::accessibility::XAccessible >& /*_rxParent*/,
+ const css::uno::Reference< css::accessibility::XAccessible >& /*_rxControlAccessible*/,
+ const css::uno::Reference< css::awt::XWindow >& /*_rxFocusWindow*/,
+ vcl::IAccessibleTableProvider& /*_rBrowseBox*/,
+ sal_Int32 /*_nRowPos*/,
+ sal_uInt16 /*_nColPos*/
+ ) const override
+ {
+ return nullptr;
+ }
+ };
+
+
+ AccessibleDummyFactory::AccessibleDummyFactory()
+ {
+ }
+
+
+ AccessibleDummyFactory::~AccessibleDummyFactory()
+ {
+ }
+
+ }
+
+
+ //= AccessibleFactoryAccess
+
+
+ AccessibleFactoryAccess::AccessibleFactoryAccess()
+ :m_bInitialized( false )
+ {
+ }
+
+#if HAVE_FEATURE_DESKTOP
+#ifndef DISABLE_DYNLOADING
+ extern "C" { static void thisModule() {} }
+#else
+ extern "C" void* getSvtAccessibilityComponentFactory();
+#endif
+#endif // HAVE_FEATURE_DESKTOP
+
+ void AccessibleFactoryAccess::ensureInitialized()
+ {
+ if ( m_bInitialized )
+ return;
+
+ ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
+
+#if HAVE_FEATURE_DESKTOP
+ // load the library implementing the factory
+ if (!s_pFactory)
+ {
+#ifndef DISABLE_DYNLOADING
+ const OUString sModuleName( SVLIBRARY( "acc" ));
+ s_hAccessibleImplementationModule = osl_loadModuleRelative( &thisModule, sModuleName.pData, 0 );
+ if ( s_hAccessibleImplementationModule != nullptr )
+ {
+ const OUString sFactoryCreationFunc( "getSvtAccessibilityComponentFactory" );
+ s_pAccessibleFactoryFunc = reinterpret_cast<GetSvtAccessibilityComponentFactory>(
+ osl_getFunctionSymbol( s_hAccessibleImplementationModule, sFactoryCreationFunc.pData ));
+
+ }
+ OSL_ENSURE( s_pAccessibleFactoryFunc, "ac_registerClient: could not load the library, or not retrieve the needed symbol!" );
+#else
+ s_pAccessibleFactoryFunc = getSvtAccessibilityComponentFactory;
+#endif // DISABLE_DYNLOADING
+
+ // get a factory instance
+ if ( s_pAccessibleFactoryFunc )
+ {
+ IAccessibleFactory* pFactory = static_cast< IAccessibleFactory* >( (*s_pAccessibleFactoryFunc)() );
+ if ( pFactory )
+ {
+ s_pFactory = pFactory;
+ pFactory->release();
+ }
+ }
+ }
+#endif // HAVE_FEATURE_DESKTOP
+
+ if (!s_pFactory)
+ // the attempt to load the lib, or to create the factory, failed
+ // -> fall back to a dummy factory
+ s_pFactory = new AccessibleDummyFactory;
+
+ m_bInitialized = true;
+ }
+
+ IAccessibleFactory& AccessibleFactoryAccess::getFactory()
+ {
+ ensureInitialized();
+ DBG_ASSERT( s_pFactory.is(), "AccessibleFactoryAccess::getFactory: at least a dummy factory should have been created!" );
+ return *s_pFactory;
+ }
+
+} // namespace vcl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/treelist/headbar.cxx b/vcl/source/treelist/headbar.cxx
new file mode 100644
index 000000000000..95d6584d166a
--- /dev/null
+++ b/vcl/source/treelist/headbar.cxx
@@ -0,0 +1,1354 @@
+/* -*- 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/headbar.hxx>
+#include <tools/debug.hxx>
+
+#include <vcl/svapp.hxx>
+#include <vcl/help.hxx>
+#include <vcl/image.hxx>
+#include <vcl/salnativewidgets.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/commandevent.hxx>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/XAccessible.hpp>
+
+class ImplHeadItem
+{
+public:
+ sal_uInt16 mnId;
+ HeaderBarItemBits mnBits;
+ long mnSize;
+ OString const maHelpId;
+ Image const maImage;
+ OUString maOutText;
+ OUString maText;
+ OUString maHelpText;
+};
+
+#define HEAD_ARROWSIZE1 4
+#define HEAD_ARROWSIZE2 7
+
+#define HEADERBAR_TEXTOFF 2
+#define HEADERBAR_ARROWOFF 5
+#define HEADERBAR_SPLITOFF 3
+
+#define HEADERBAR_DRAGOUTOFF 15
+
+#define HEAD_HITTEST_ITEM (sal_uInt16(0x0001))
+#define HEAD_HITTEST_DIVIDER (sal_uInt16(0x0002))
+
+void HeaderBar::ImplInit( WinBits nWinStyle )
+{
+ mnBorderOff1 = 0;
+ mnBorderOff2 = 0;
+ mnOffset = 0;
+ mnDX = 0;
+ mnDY = 0;
+ mnDragSize = 0;
+ mnStartPos = 0;
+ mnDragPos = 0;
+ mnMouseOff = 0;
+ mnCurItemId = 0;
+ mnItemDragPos = HEADERBAR_ITEM_NOTFOUND;
+ mbDrag = false;
+ mbItemDrag = false;
+ mbOutDrag = false;
+ mbItemMode = false;
+
+ // evaluate StyleBits
+ if ( nWinStyle & WB_DRAG )
+ mbDragable = true;
+ else
+ mbDragable = false;
+ if ( nWinStyle & WB_BUTTONSTYLE )
+ mbButtonStyle = true;
+ else
+ mbButtonStyle = false;
+ if ( nWinStyle & WB_BORDER )
+ {
+ mnBorderOff1 = 1;
+ mnBorderOff2 = 1;
+ }
+ else
+ {
+ if ( nWinStyle & WB_BOTTOMBORDER )
+ mnBorderOff2 = 1;
+ }
+
+ ImplInitSettings( true, true, true );
+}
+
+HeaderBar::HeaderBar(vcl::Window* pParent, WinBits nWinStyle)
+ : Window(pParent, nWinStyle & WB_3DLOOK)
+{
+ SetType(WindowType::HEADERBAR);
+ ImplInit(nWinStyle);
+ SetSizePixel( CalcWindowSizePixel() );
+}
+
+HeaderBar::~HeaderBar() = default;
+
+void HeaderBar::ApplySettings(vcl::RenderContext& rRenderContext)
+{
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+
+ ApplyControlFont(rRenderContext, rStyleSettings.GetToolFont());
+
+ ApplyControlForeground(rRenderContext, rStyleSettings.GetButtonTextColor());
+ SetTextFillColor();
+
+ ApplyControlBackground(rRenderContext, rStyleSettings.GetFaceColor());
+}
+
+void HeaderBar::ImplInitSettings(bool bFont, bool bForeground, bool bBackground)
+{
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+
+ if (bFont)
+ ApplyControlFont(*this, rStyleSettings.GetToolFont());
+
+ if (bForeground || bFont)
+ {
+ ApplyControlForeground(*this, rStyleSettings.GetButtonTextColor());
+ SetTextFillColor();
+ }
+
+ if (bBackground)
+ ApplyControlBackground(*this, rStyleSettings.GetFaceColor());
+}
+
+long HeaderBar::ImplGetItemPos( sal_uInt16 nPos ) const
+{
+ long nX = -mnOffset;
+ for ( size_t i = 0; i < nPos; i++ )
+ nX += mvItemList[ i ]->mnSize;
+ return nX;
+}
+
+tools::Rectangle HeaderBar::ImplGetItemRect( sal_uInt16 nPos ) const
+{
+ tools::Rectangle aRect( ImplGetItemPos( nPos ), 0, 0, mnDY-1 );
+ aRect.SetRight( aRect.Left() + mvItemList[ nPos ]->mnSize - 1 );
+ // check for overflow on various systems
+ if ( aRect.Right() > 16000 )
+ aRect.SetRight( 16000 );
+ return aRect;
+}
+
+sal_uInt16 HeaderBar::ImplHitTest( const Point& rPos,
+ long& nMouseOff, sal_uInt16& nPos ) const
+{
+ size_t nCount = static_cast<sal_uInt16>(mvItemList.size());
+ bool bLastFixed = true;
+ long nX = -mnOffset;
+
+ for ( size_t i = 0; i < nCount; i++ )
+ {
+ auto& pItem = mvItemList[ i ];
+
+ if ( rPos.X() < (nX+pItem->mnSize) )
+ {
+ sal_uInt16 nMode;
+
+ if ( !bLastFixed && (rPos.X() < (nX+HEADERBAR_SPLITOFF)) )
+ {
+ nMode = HEAD_HITTEST_DIVIDER;
+ nPos = i-1;
+ nMouseOff = rPos.X()-nX+1;
+ }
+ else
+ {
+ nPos = i;
+
+ if ( !(pItem->mnBits & HeaderBarItemBits::FIXED) && (rPos.X() >= (nX+pItem->mnSize-HEADERBAR_SPLITOFF)) )
+ {
+ nMode = HEAD_HITTEST_DIVIDER;
+ nMouseOff = rPos.X()-(nX+pItem->mnSize);
+ }
+ else
+ {
+ nMode = HEAD_HITTEST_ITEM;
+ nMouseOff = rPos.X()-nX;
+ }
+ }
+
+ return nMode;
+ }
+
+ bLastFixed = static_cast<bool>(pItem->mnBits & HeaderBarItemBits::FIXED);
+
+ nX += pItem->mnSize;
+ }
+
+ if ( !bLastFixed )
+ {
+ auto& pItem = mvItemList[ nCount-1 ];
+ if ( (pItem->mnSize < 4) && (rPos.X() < (nX+HEADERBAR_SPLITOFF)) )
+ {
+ nPos = nCount-1;
+ nMouseOff = rPos.X()-nX+1;
+ return HEAD_HITTEST_DIVIDER;
+ }
+ }
+
+ return 0;
+}
+
+void HeaderBar::ImplInvertDrag( sal_uInt16 nStartPos, sal_uInt16 nEndPos )
+{
+ tools::Rectangle aRect1 = ImplGetItemRect( nStartPos );
+ tools::Rectangle aRect2 = ImplGetItemRect( nEndPos );
+ Point aStartPos = aRect1.Center();
+ Point aEndPos = aStartPos;
+ tools::Rectangle aStartRect( aStartPos.X()-2, aStartPos.Y()-2,
+ aStartPos.X()+2, aStartPos.Y()+2 );
+
+ if ( nEndPos > nStartPos )
+ {
+ aStartPos.AdjustX(3 );
+ aEndPos.setX( aRect2.Right()-6 );
+ }
+ else
+ {
+ aStartPos.AdjustX( -3 );
+ aEndPos.setX( aRect2.Left()+6 );
+ }
+
+ SetRasterOp( RasterOp::Invert );
+ DrawRect( aStartRect );
+ DrawLine( aStartPos, aEndPos );
+ if ( nEndPos > nStartPos )
+ {
+ DrawLine( Point( aEndPos.X()+1, aEndPos.Y()-3 ),
+ Point( aEndPos.X()+1, aEndPos.Y()+3 ) );
+ DrawLine( Point( aEndPos.X()+2, aEndPos.Y()-2 ),
+ Point( aEndPos.X()+2, aEndPos.Y()+2 ) );
+ DrawLine( Point( aEndPos.X()+3, aEndPos.Y()-1 ),
+ Point( aEndPos.X()+3, aEndPos.Y()+1 ) );
+ DrawPixel( Point( aEndPos.X()+4, aEndPos.Y() ) );
+ }
+ else
+ {
+ DrawLine( Point( aEndPos.X()-1, aEndPos.Y()-3 ),
+ Point( aEndPos.X()-1, aEndPos.Y()+3 ) );
+ DrawLine( Point( aEndPos.X()-2, aEndPos.Y()-2 ),
+ Point( aEndPos.X()-2, aEndPos.Y()+2 ) );
+ DrawLine( Point( aEndPos.X()-3, aEndPos.Y()-1 ),
+ Point( aEndPos.X()-3, aEndPos.Y()+1 ) );
+ DrawPixel( Point( aEndPos.X()-4, aEndPos.Y() ) );
+ }
+ SetRasterOp( RasterOp::OverPaint );
+}
+
+void HeaderBar::ImplDrawItem(vcl::RenderContext& rRenderContext, sal_uInt16 nPos, bool bHigh,
+ const tools::Rectangle& rItemRect, const tools::Rectangle* pRect )
+{
+ ImplControlValue aControlValue(0);
+ tools::Rectangle aCtrlRegion;
+ ControlState nState(ControlState::NONE);
+
+ tools::Rectangle aRect = rItemRect;
+
+ // do not display if there is no space
+ if (aRect.GetWidth() <= 1)
+ return;
+
+ // check of rectangle is visible
+ if (pRect)
+ {
+ if (aRect.Right() < pRect->Left())
+ return;
+ else if (aRect.Left() > pRect->Right())
+ return;
+ }
+ else
+ {
+ if (aRect.Right() < 0)
+ return;
+ else if (aRect.Left() > mnDX)
+ return;
+ }
+
+ auto& pItem = mvItemList[nPos];
+ HeaderBarItemBits nBits = pItem->mnBits;
+ const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
+
+ if (rRenderContext.IsNativeControlSupported(ControlType::WindowBackground, ControlPart::Entire))
+ {
+ aCtrlRegion = aRect;
+ rRenderContext.DrawNativeControl(ControlType::WindowBackground, ControlPart::Entire,
+ aCtrlRegion, nState, aControlValue, OUString());
+
+ }
+ else
+ {
+ // do not draw border
+ aRect.AdjustTop(mnBorderOff1 );
+ aRect.AdjustBottom( -(mnBorderOff2) );
+
+ // delete background
+ if ( !pRect )
+ {
+ rRenderContext.DrawWallpaper(aRect, rRenderContext.GetBackground());
+ }
+ }
+
+ Color aSelectionTextColor(COL_TRANSPARENT);
+
+ if (rRenderContext.IsNativeControlSupported(ControlType::ListHeader, ControlPart::Button))
+ {
+ aCtrlRegion = aRect;
+ aControlValue.setTristateVal(ButtonValue::On);
+ nState |= ControlState::ENABLED;
+ if (bHigh)
+ nState |= ControlState::PRESSED;
+ rRenderContext.DrawNativeControl(ControlType::ListHeader, ControlPart::Button,
+ aCtrlRegion, nState, aControlValue, OUString());
+ }
+ else
+ {
+ // draw separation line
+ rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
+ rRenderContext.DrawLine(Point(aRect.Right(), aRect.Top()), Point(aRect.Right(), aRect.Bottom()));
+
+ // draw ButtonStyle
+ // avoid 3D borders
+ if (bHigh)
+ vcl::RenderTools::DrawSelectionBackground(rRenderContext, *this, aRect, 1, true, false, false, &aSelectionTextColor);
+ else if (!mbButtonStyle || (nBits & HeaderBarItemBits::FLAT))
+ vcl::RenderTools::DrawSelectionBackground(rRenderContext, *this, aRect, 0, true, false, false, &aSelectionTextColor);
+ }
+
+ // do not draw if there is no space
+ if (aRect.GetWidth() < 1)
+ return;
+
+ // calculate size and position and draw content
+ pItem->maOutText = pItem->maText;
+ Size aImageSize = pItem->maImage.GetSizePixel();
+ Size aTxtSize(rRenderContext.GetTextWidth(pItem->maOutText), 0);
+ if (!pItem->maOutText.isEmpty())
+ aTxtSize.setHeight( rRenderContext.GetTextHeight() );
+ long nArrowWidth = 0;
+ if (nBits & (HeaderBarItemBits::UPARROW | HeaderBarItemBits::DOWNARROW))
+ nArrowWidth = HEAD_ARROWSIZE2 + HEADERBAR_ARROWOFF;
+
+ // do not draw if there is not enough space for the image
+ long nTestHeight = aImageSize.Height();
+ if (!(nBits & (HeaderBarItemBits::LEFTIMAGE | HeaderBarItemBits::RIGHTIMAGE)))
+ nTestHeight += aTxtSize.Height();
+ if ((aImageSize.Width() > aRect.GetWidth()) || (nTestHeight > aRect.GetHeight()))
+ {
+ aImageSize.setWidth( 0 );
+ aImageSize.setHeight( 0 );
+ }
+
+ // cut text to correct length
+ bool bLeftText = false;
+ long nMaxTxtWidth = aRect.GetWidth() - (HEADERBAR_TEXTOFF * 2) - nArrowWidth;
+ if (nBits & (HeaderBarItemBits::LEFTIMAGE | HeaderBarItemBits::RIGHTIMAGE))
+ nMaxTxtWidth -= aImageSize.Width();
+ long nTxtWidth = aTxtSize.Width();
+ if (nTxtWidth > nMaxTxtWidth)
+ {
+ bLeftText = true;
+ OUStringBuffer aBuf(pItem->maOutText);
+ aBuf.append("...");
+ do
+ {
+ aBuf.remove(aBuf.getLength() - 3 - 1, 1);
+ nTxtWidth = rRenderContext.GetTextWidth(aBuf.toString());
+ }
+ while ((nTxtWidth > nMaxTxtWidth) && (aBuf.getLength() > 3));
+ pItem->maOutText = aBuf.makeStringAndClear();
+ if (pItem->maOutText.getLength() == 3)
+ {
+ nTxtWidth = 0;
+ pItem->maOutText.clear();
+ }
+ }
+
+ // calculate text/imageposition
+ long nTxtPos;
+ if (!bLeftText && (nBits & HeaderBarItemBits::RIGHT))
+ {
+ nTxtPos = aRect.Right() - nTxtWidth - HEADERBAR_TEXTOFF;
+ if (nBits & HeaderBarItemBits::RIGHTIMAGE)
+ nTxtPos -= aImageSize.Width();
+ }
+ else if (!bLeftText && (nBits & HeaderBarItemBits::CENTER))
+ {
+ long nTempWidth = nTxtWidth;
+ if (nBits & (HeaderBarItemBits::LEFTIMAGE | HeaderBarItemBits::RIGHTIMAGE))
+ nTempWidth += aImageSize.Width();
+ nTxtPos = aRect.Left() + (aRect.GetWidth() - nTempWidth) / 2;
+ if (nBits & HeaderBarItemBits::LEFTIMAGE)
+ nTxtPos += aImageSize.Width();
+ if (nArrowWidth)
+ {
+ if (nTxtPos + nTxtWidth + nArrowWidth >= aRect.Right())
+ {
+ nTxtPos = aRect.Left() + HEADERBAR_TEXTOFF;
+ if (nBits & HeaderBarItemBits::LEFTIMAGE)
+ nTxtPos += aImageSize.Width();
+ }
+ }
+ }
+ else
+ {
+ nTxtPos = aRect.Left() + HEADERBAR_TEXTOFF;
+ if (nBits & HeaderBarItemBits::LEFTIMAGE)
+ nTxtPos += aImageSize.Width();
+ if (nBits & HeaderBarItemBits::RIGHT)
+ nTxtPos += nArrowWidth;
+ }
+
+ // calculate text/imageposition
+ long nTxtPosY = 0;
+ if (!pItem->maOutText.isEmpty() || (nArrowWidth && aTxtSize.Height()))
+ {
+ if (nBits & HeaderBarItemBits::TOP)
+ {
+ nTxtPosY = aRect.Top();
+ if (!(nBits & (HeaderBarItemBits::LEFTIMAGE | HeaderBarItemBits::RIGHTIMAGE)))
+ nTxtPosY += aImageSize.Height();
+ }
+ else if (nBits & HeaderBarItemBits::BOTTOM)
+ nTxtPosY = aRect.Bottom()-aTxtSize.Height();
+ else
+ {
+ long nTempHeight = aTxtSize.Height();
+ nTempHeight += aImageSize.Height();
+ nTxtPosY = aRect.Top()+((aRect.GetHeight()-nTempHeight)/2);
+ if (!(nBits & (HeaderBarItemBits::LEFTIMAGE | HeaderBarItemBits::RIGHTIMAGE)))
+ nTxtPosY += aImageSize.Height();
+ }
+ }
+
+ // display text
+ if (!pItem->maOutText.isEmpty())
+ {
+ if (aSelectionTextColor != COL_TRANSPARENT)
+ {
+ rRenderContext.Push(PushFlags::TEXTCOLOR);
+ rRenderContext.SetTextColor(aSelectionTextColor);
+ }
+ if (IsEnabled())
+ rRenderContext.DrawText(Point(nTxtPos, nTxtPosY), pItem->maOutText);
+ else
+ rRenderContext.DrawCtrlText(Point(nTxtPos, nTxtPosY), pItem->maOutText, 0, pItem->maOutText.getLength(), DrawTextFlags::Disable);
+ if (aSelectionTextColor != COL_TRANSPARENT)
+ rRenderContext.Pop();
+ }
+
+ // calculate the position and draw image if it is available
+ long nImagePosY = 0;
+ if (aImageSize.Width() && aImageSize.Height())
+ {
+ long nImagePos = nTxtPos;
+ if (nBits & HeaderBarItemBits::LEFTIMAGE)
+ {
+ nImagePos -= aImageSize.Width();
+ if (nBits & HeaderBarItemBits::RIGHT)
+ nImagePos -= nArrowWidth;
+ }
+ else if (nBits & HeaderBarItemBits::RIGHTIMAGE)
+ {
+ nImagePos += nTxtWidth;
+ if (!(nBits & HeaderBarItemBits::RIGHT))
+ nImagePos += nArrowWidth;
+ }
+ else
+ {
+ if (nBits & HeaderBarItemBits::RIGHT )
+ nImagePos = aRect.Right()-aImageSize.Width();
+ else if (nBits & HeaderBarItemBits::CENTER)
+ nImagePos = aRect.Left() + (aRect.GetWidth() - aImageSize.Width()) / 2;
+ else
+ nImagePos = aRect.Left() + HEADERBAR_TEXTOFF;
+ }
+
+ if (nBits & HeaderBarItemBits::TOP)
+ nImagePosY = aRect.Top();
+ else if (nBits & HeaderBarItemBits::BOTTOM)
+ {
+ nImagePosY = aRect.Bottom() - aImageSize.Height();
+ if (!(nBits & (HeaderBarItemBits::LEFTIMAGE | HeaderBarItemBits::RIGHTIMAGE)))
+ nImagePosY -= aTxtSize.Height();
+ }
+ else
+ {
+ long nTempHeight = aImageSize.Height();
+ if (!(nBits & (HeaderBarItemBits::LEFTIMAGE | HeaderBarItemBits::RIGHTIMAGE)))
+ nTempHeight += aTxtSize.Height();
+ nImagePosY = aRect.Top() + ((aRect.GetHeight() - nTempHeight) / 2);
+ }
+ if (nImagePos + aImageSize.Width() <= aRect.Right())
+ {
+ DrawImageFlags nStyle = DrawImageFlags::NONE;
+ if (!IsEnabled())
+ nStyle |= DrawImageFlags::Disable;
+ rRenderContext.DrawImage(Point(nImagePos, nImagePosY), pItem->maImage, nStyle);
+ }
+ }
+
+ if (!(nBits & (HeaderBarItemBits::UPARROW | HeaderBarItemBits::DOWNARROW)))
+ return;
+
+ long nArrowX = nTxtPos;
+ if (nBits & HeaderBarItemBits::RIGHT)
+ nArrowX -= nArrowWidth;
+ else
+ nArrowX += nTxtWidth + HEADERBAR_ARROWOFF;
+ if (!(nBits & (HeaderBarItemBits::LEFTIMAGE | HeaderBarItemBits::RIGHTIMAGE)) && pItem->maText.isEmpty())
+ {
+ if (nBits & HeaderBarItemBits::RIGHT)
+ nArrowX -= aImageSize.Width();
+ else
+ nArrowX += aImageSize.Width();
+ }
+
+ // is there enough space to draw the item?
+ bool bDraw = true;
+ if (nArrowX < aRect.Left() + HEADERBAR_TEXTOFF)
+ bDraw = false;
+ else if (nArrowX + HEAD_ARROWSIZE2 > aRect.Right())
+ bDraw = false;
+
+ if (!bDraw)
+ return;
+
+ if (rRenderContext.IsNativeControlSupported(ControlType::ListHeader, ControlPart::Arrow))
+ {
+ aCtrlRegion = tools::Rectangle(Point(nArrowX, aRect.Top()), Size(nArrowWidth, aRect.GetHeight()));
+ // control value passes 1 if arrow points down, 0 otherwise
+ aControlValue.setNumericVal((nBits & HeaderBarItemBits::DOWNARROW) ? 1 : 0);
+ nState |= ControlState::ENABLED;
+ if (bHigh)
+ nState |= ControlState::PRESSED;
+ rRenderContext.DrawNativeControl(ControlType::ListHeader, ControlPart::Arrow, aCtrlRegion,
+ nState, aControlValue, OUString());
+ }
+ else
+ {
+ long nArrowY;
+ if (aTxtSize.Height())
+ nArrowY = nTxtPosY + (aTxtSize.Height() / 2);
+ else if (aImageSize.Width() && aImageSize.Height())
+ nArrowY = nImagePosY + (aImageSize.Height() / 2);
+ else
+ {
+ if (nBits & HeaderBarItemBits::TOP)
+ nArrowY = aRect.Top() + 1;
+ else if (nBits & HeaderBarItemBits::BOTTOM)
+ nArrowY = aRect.Bottom() - HEAD_ARROWSIZE2 - 1;
+ else
+ nArrowY = aRect.Top() + ((aRect.GetHeight() - HEAD_ARROWSIZE2) / 2);
+ }
+ nArrowY -= HEAD_ARROWSIZE1 - 1;
+ if (nBits & HeaderBarItemBits::DOWNARROW)
+ {
+ rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
+ rRenderContext.DrawLine(Point(nArrowX, nArrowY),
+ Point(nArrowX + HEAD_ARROWSIZE2, nArrowY));
+ rRenderContext.DrawLine(Point(nArrowX, nArrowY),
+ Point(nArrowX + HEAD_ARROWSIZE1, nArrowY + HEAD_ARROWSIZE2));
+ rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
+ rRenderContext.DrawLine(Point(nArrowX + HEAD_ARROWSIZE1, nArrowY + HEAD_ARROWSIZE2),
+ Point(nArrowX + HEAD_ARROWSIZE2, nArrowY));
+ }
+ else
+ {
+ rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
+ rRenderContext.DrawLine(Point(nArrowX, nArrowY + HEAD_ARROWSIZE2),
+ Point(nArrowX + HEAD_ARROWSIZE1, nArrowY));
+ rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
+ rRenderContext.DrawLine(Point(nArrowX, nArrowY + HEAD_ARROWSIZE2),
+ Point(nArrowX + HEAD_ARROWSIZE2, nArrowY + HEAD_ARROWSIZE2));
+ rRenderContext.DrawLine(Point(nArrowX + HEAD_ARROWSIZE2, nArrowY + HEAD_ARROWSIZE2),
+ Point(nArrowX + HEAD_ARROWSIZE1, nArrowY));
+ }
+ }
+}
+
+void HeaderBar::ImplDrawItem(vcl::RenderContext& rRenderContext, sal_uInt16 nPos,
+ bool bHigh, const tools::Rectangle* pRect )
+{
+ tools::Rectangle aRect = ImplGetItemRect(nPos);
+ ImplDrawItem(rRenderContext, nPos, bHigh, aRect, pRect );
+}
+
+void HeaderBar::ImplUpdate(sal_uInt16 nPos, bool bEnd)
+{
+ if (!(IsVisible() && IsUpdateMode()))
+ return;
+
+ tools::Rectangle aRect;
+ size_t nItemCount = mvItemList.size();
+ if (nPos < nItemCount)
+ aRect = ImplGetItemRect(nPos);
+ else
+ {
+ aRect.SetBottom( mnDY - 1 );
+ if (nItemCount)
+ aRect.SetLeft( ImplGetItemRect(nItemCount - 1).Right() );
+ }
+ if (bEnd)
+ aRect.SetRight( mnDX - 1 );
+ aRect.AdjustTop(mnBorderOff1 );
+ aRect.AdjustBottom( -(mnBorderOff2) );
+ Invalidate(aRect);
+}
+
+void HeaderBar::ImplStartDrag( const Point& rMousePos, bool bCommand )
+{
+ sal_uInt16 nPos;
+ sal_uInt16 nHitTest = ImplHitTest( rMousePos, mnMouseOff, nPos );
+ if ( !nHitTest )
+ return;
+
+ mbDrag = false;
+ auto& pItem = mvItemList[ nPos ];
+ if ( nHitTest & HEAD_HITTEST_DIVIDER )
+ mbDrag = true;
+ else
+ {
+ if ( ((pItem->mnBits & HeaderBarItemBits::CLICKABLE) && !(pItem->mnBits & HeaderBarItemBits::FLAT)) ||
+ (mbDragable && !(pItem->mnBits & HeaderBarItemBits::FIXEDPOS)) )
+ {
+ mbItemMode = true;
+ mbDrag = true;
+ if ( bCommand )
+ {
+ if ( mbDragable )
+ mbItemDrag = true;
+ else
+ {
+ mbItemMode = false;
+ mbDrag = false;
+ }
+ }
+ }
+ else
+ {
+ if ( !bCommand )
+ {
+ mnCurItemId = pItem->mnId;
+ Select();
+ mnCurItemId = 0;
+ }
+ }
+ }
+
+ if ( mbDrag )
+ {
+ mbOutDrag = false;
+ mnCurItemId = pItem->mnId;
+ mnItemDragPos = nPos;
+ StartTracking();
+ mnStartPos = rMousePos.X()-mnMouseOff;
+ mnDragPos = mnStartPos;
+ maStartDragHdl.Call( this );
+ if (mbItemMode)
+ Invalidate();
+ else
+ {
+ tools::Rectangle aSizeRect( mnDragPos, 0, mnDragPos, mnDragSize+mnDY );
+ ShowTracking( aSizeRect, ShowTrackFlags::Split );
+ }
+ }
+ else
+ mnMouseOff = 0;
+}
+
+void HeaderBar::ImplDrag( const Point& rMousePos )
+{
+ sal_uInt16 nPos = GetItemPos( mnCurItemId );
+
+ mnDragPos = rMousePos.X()-mnMouseOff;
+ if ( mbItemMode )
+ {
+ bool bNewOutDrag;
+
+ tools::Rectangle aItemRect = ImplGetItemRect( nPos );
+ bNewOutDrag = !aItemRect.IsInside( rMousePos );
+
+ // if needed switch on ItemDrag
+ if ( bNewOutDrag && mbDragable && !mbItemDrag &&
+ !(mvItemList[ nPos ]->mnBits & HeaderBarItemBits::FIXEDPOS) )
+ {
+ if ( (rMousePos.Y() >= aItemRect.Top()) && (rMousePos.Y() <= aItemRect.Bottom()) )
+ {
+ mbItemDrag = true;
+ Invalidate();
+ }
+ }
+
+ sal_uInt16 nOldItemDragPos = mnItemDragPos;
+ if ( mbItemDrag )
+ {
+ bNewOutDrag = (rMousePos.Y() < -HEADERBAR_DRAGOUTOFF) || (rMousePos.Y() > mnDY+HEADERBAR_DRAGOUTOFF);
+
+ if ( bNewOutDrag )
+ mnItemDragPos = HEADERBAR_ITEM_NOTFOUND;
+ else
+ {
+ sal_uInt16 nTempId = GetItemId( Point( rMousePos.X(), 2 ) );
+ if ( nTempId )
+ mnItemDragPos = GetItemPos( nTempId );
+ else
+ {
+ if ( rMousePos.X() <= 0 )
+ mnItemDragPos = 0;
+ else
+ mnItemDragPos = GetItemCount()-1;
+ }
+
+ // do not use non-movable items
+ if ( mnItemDragPos < nPos )
+ {
+ while ( (mvItemList[ mnItemDragPos ]->mnBits & HeaderBarItemBits::FIXEDPOS) &&
+ (mnItemDragPos < nPos) )
+ mnItemDragPos++;
+ }
+ else if ( mnItemDragPos > nPos )
+ {
+ while ( (mvItemList[ mnItemDragPos ]->mnBits & HeaderBarItemBits::FIXEDPOS) &&
+ (mnItemDragPos > nPos) )
+ mnItemDragPos--;
+ }
+ }
+
+ if ( (mnItemDragPos != nOldItemDragPos) &&
+ (nOldItemDragPos != nPos) &&
+ (nOldItemDragPos != HEADERBAR_ITEM_NOTFOUND) )
+ {
+ ImplInvertDrag( nPos, nOldItemDragPos );
+ Invalidate();
+ }
+ }
+
+ if ( bNewOutDrag != mbOutDrag )
+ Invalidate();
+
+ if ( mbItemDrag )
+ {
+ if ( (mnItemDragPos != nOldItemDragPos) &&
+ (mnItemDragPos != nPos) &&
+ (mnItemDragPos != HEADERBAR_ITEM_NOTFOUND) )
+ {
+ Invalidate();
+ ImplInvertDrag( nPos, mnItemDragPos );
+ }
+ }
+
+ mbOutDrag = bNewOutDrag;
+ }
+ else
+ {
+ tools::Rectangle aItemRect = ImplGetItemRect( nPos );
+ if ( mnDragPos < aItemRect.Left() )
+ mnDragPos = aItemRect.Left();
+ if ( (mnDragPos < 0) || (mnDragPos > mnDX-1) )
+ HideTracking();
+ else
+ {
+ tools::Rectangle aSizeRect( mnDragPos, 0, mnDragPos, mnDragSize+mnDY );
+ ShowTracking( aSizeRect, ShowTrackFlags::Split );
+ }
+ }
+
+ maDragHdl.Call( this );
+}
+
+void HeaderBar::ImplEndDrag( bool bCancel )
+{
+ HideTracking();
+
+ if ( bCancel || mbOutDrag )
+ {
+ if ( mbItemMode && (!mbOutDrag || mbItemDrag) )
+ {
+ Invalidate();
+ }
+
+ mnCurItemId = 0;
+ }
+ else
+ {
+ sal_uInt16 nPos = GetItemPos( mnCurItemId );
+ if ( mbItemMode )
+ {
+ if ( mbItemDrag )
+ {
+ Pointer aPointer( PointerStyle::Arrow );
+ SetPointer( aPointer );
+ if ( (mnItemDragPos != nPos) &&
+ (mnItemDragPos != HEADERBAR_ITEM_NOTFOUND) )
+ {
+ ImplInvertDrag( nPos, mnItemDragPos );
+ MoveItem( mnCurItemId, mnItemDragPos );
+ }
+ else
+ Invalidate();
+ }
+ else
+ {
+ Select();
+ ImplUpdate( nPos );
+ }
+ }
+ else
+ {
+ long nDelta = mnDragPos - mnStartPos;
+ if ( nDelta )
+ {
+ auto& pItem = mvItemList[ nPos ];
+ pItem->mnSize += nDelta;
+ ImplUpdate( nPos, true );
+ }
+ }
+ }
+
+ mbDrag = false;
+ EndDrag();
+ mnCurItemId = 0;
+ mnItemDragPos = HEADERBAR_ITEM_NOTFOUND;
+ mbOutDrag = false;
+ mbItemMode = false;
+ mbItemDrag = false;
+}
+
+void HeaderBar::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if ( !rMEvt.IsLeft() )
+ return;
+
+ if ( rMEvt.GetClicks() == 2 )
+ {
+ long nTemp;
+ sal_uInt16 nPos;
+ sal_uInt16 nHitTest = ImplHitTest( rMEvt.GetPosPixel(), nTemp, nPos );
+ if ( nHitTest )
+ {
+ auto& pItem = mvItemList[ nPos ];
+ if ( nHitTest & HEAD_HITTEST_DIVIDER )
+ mbItemMode = false;
+ else
+ mbItemMode = true;
+ mnCurItemId = pItem->mnId;
+ DoubleClick();
+ mbItemMode = false;
+ mnCurItemId = 0;
+ }
+ }
+ else
+ ImplStartDrag( rMEvt.GetPosPixel(), false );
+}
+
+void HeaderBar::MouseMove( const MouseEvent& rMEvt )
+{
+ long nTemp1;
+ sal_uInt16 nTemp2;
+ PointerStyle eStyle = PointerStyle::Arrow;
+ sal_uInt16 nHitTest = ImplHitTest( rMEvt.GetPosPixel(), nTemp1, nTemp2 );
+
+ if ( nHitTest & HEAD_HITTEST_DIVIDER )
+ eStyle = PointerStyle::HSizeBar;
+ Pointer aPtr( eStyle );
+ SetPointer( aPtr );
+}
+
+void HeaderBar::Tracking( const TrackingEvent& rTEvt )
+{
+ Point aMousePos = rTEvt.GetMouseEvent().GetPosPixel();
+
+ if ( rTEvt.IsTrackingEnded() )
+ ImplEndDrag( rTEvt.IsTrackingCanceled() );
+ else
+ ImplDrag( aMousePos );
+}
+
+void HeaderBar::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
+{
+ if (mnBorderOff1 || mnBorderOff2)
+ {
+ rRenderContext.SetLineColor(rRenderContext.GetSettings().GetStyleSettings().GetDarkShadowColor());
+ if (mnBorderOff1)
+ rRenderContext.DrawLine(Point(0, 0), Point(mnDX - 1, 0));
+ if (mnBorderOff2)
+ rRenderContext.DrawLine(Point(0, mnDY - 1), Point(mnDX - 1, mnDY - 1));
+ // #i40393# draw left and right border, if WB_BORDER was set in ImplInit()
+ if (mnBorderOff1 && mnBorderOff2)
+ {
+ rRenderContext.DrawLine(Point(0, 0), Point(0, mnDY - 1));
+ rRenderContext.DrawLine(Point(mnDX - 1, 0), Point(mnDX - 1, mnDY - 1));
+ }
+ }
+
+ sal_uInt16 nCurItemPos;
+ if (mbDrag)
+ nCurItemPos = GetItemPos(mnCurItemId);
+ else
+ nCurItemPos = HEADERBAR_ITEM_NOTFOUND;
+ sal_uInt16 nItemCount = static_cast<sal_uInt16>(mvItemList.size());
+ for (sal_uInt16 i = 0; i < nItemCount; i++)
+ ImplDrawItem(rRenderContext, i, (i == nCurItemPos), &rRect);
+}
+
+void HeaderBar::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize,
+ DrawFlags nFlags )
+{
+ Point aPos = pDev->LogicToPixel( rPos );
+ Size aSize = pDev->LogicToPixel( rSize );
+ tools::Rectangle aRect( aPos, aSize );
+ vcl::Font aFont = GetDrawPixelFont( pDev );
+
+ pDev->Push();
+ pDev->SetMapMode();
+ pDev->SetFont( aFont );
+ if ( nFlags & DrawFlags::Mono )
+ pDev->SetTextColor( COL_BLACK );
+ else
+ pDev->SetTextColor( GetTextColor() );
+ pDev->SetTextFillColor();
+
+ if ( !(nFlags & DrawFlags::NoBackground) )
+ {
+ pDev->DrawWallpaper( aRect, GetBackground() );
+ if ( mnBorderOff1 || mnBorderOff2 )
+ {
+ pDev->SetLineColor( GetSettings().GetStyleSettings().GetDarkShadowColor() );
+ if ( mnBorderOff1 )
+ pDev->DrawLine( aRect.TopLeft(), Point( aRect.Right(), aRect.Top() ) );
+ if ( mnBorderOff2 )
+ pDev->DrawLine( Point( aRect.Left(), aRect.Bottom() ), Point( aRect.Right(), aRect.Bottom() ) );
+ // #i40393# draw left and right border, if WB_BORDER was set in ImplInit()
+ if ( mnBorderOff1 && mnBorderOff2 )
+ {
+ pDev->DrawLine( aRect.TopLeft(), Point( aRect.Left(), aRect.Bottom() ) );
+ pDev->DrawLine( Point( aRect.Right(), aRect.Top() ), Point( aRect.Right(), aRect.Bottom() ) );
+ }
+ }
+ }
+
+ tools::Rectangle aItemRect( aRect );
+ size_t nItemCount = mvItemList.size();
+ for ( size_t i = 0; i < nItemCount; i++ )
+ {
+ aItemRect.SetLeft( aRect.Left()+ImplGetItemPos( i ) );
+ aItemRect.SetRight( aItemRect.Left() + mvItemList[ i ]->mnSize - 1 );
+ // check for overflow on some systems
+ if ( aItemRect.Right() > 16000 )
+ aItemRect.SetRight( 16000 );
+ vcl::Region aRegion( aRect );
+ pDev->SetClipRegion( aRegion );
+ ImplDrawItem(*pDev, i, false, aItemRect, &aRect );
+ pDev->SetClipRegion();
+ }
+
+ pDev->Pop();
+}
+
+void HeaderBar::Resize()
+{
+ Size aSize = GetOutputSizePixel();
+ if ( IsVisible() && (mnDY != aSize.Height()) )
+ Invalidate();
+ mnDX = aSize.Width();
+ mnDY = aSize.Height();
+}
+
+void HeaderBar::Command( const CommandEvent& rCEvt )
+{
+ if ( rCEvt.IsMouseEvent() && (rCEvt.GetCommand() == CommandEventId::StartDrag) && !mbDrag )
+ {
+ ImplStartDrag( rCEvt.GetMousePosPixel(), true );
+ return;
+ }
+
+ Window::Command( rCEvt );
+}
+
+void HeaderBar::RequestHelp( const HelpEvent& rHEvt )
+{
+ sal_uInt16 nItemId = GetItemId( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) );
+ if ( nItemId )
+ {
+ if ( rHEvt.GetMode() & (HelpEventMode::QUICK | HelpEventMode::BALLOON) )
+ {
+ tools::Rectangle aItemRect = GetItemRect( nItemId );
+ Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
+ aItemRect.SetLeft( aPt.X() );
+ aItemRect.SetTop( aPt.Y() );
+ aPt = OutputToScreenPixel( aItemRect.BottomRight() );
+ aItemRect.SetRight( aPt.X() );
+ aItemRect.SetBottom( aPt.Y() );
+
+ OUString aStr = GetHelpText( nItemId );
+ if ( aStr.isEmpty() || !(rHEvt.GetMode() & HelpEventMode::BALLOON) )
+ {
+ auto& pItem = mvItemList[ GetItemPos( nItemId ) ];
+ // Quick-help is only displayed if the text is not fully visible.
+ // Otherwise we display Helptext only if the items do not contain text
+ if ( pItem->maOutText != pItem->maText )
+ aStr = pItem->maText;
+ else if (!pItem->maText.isEmpty())
+ aStr.clear();
+ }
+
+ if (!aStr.isEmpty())
+ {
+ if ( rHEvt.GetMode() & HelpEventMode::BALLOON )
+ Help::ShowBalloon( this, aItemRect.Center(), aItemRect, aStr );
+ else
+ Help::ShowQuickHelp( this, aItemRect, aStr );
+ return;
+ }
+ }
+ else if ( rHEvt.GetMode() & HelpEventMode::EXTENDED )
+ {
+ OUString aHelpId( OStringToOUString( GetHelpId( nItemId ), RTL_TEXTENCODING_UTF8 ) );
+ if ( !aHelpId.isEmpty() )
+ {
+ // display it if help is available
+ Help* pHelp = Application::GetHelp();
+ if ( pHelp )
+ pHelp->Start( aHelpId, this );
+ return;
+ }
+ }
+ }
+
+ Window::RequestHelp( rHEvt );
+}
+
+void HeaderBar::StateChanged( StateChangedType nType )
+{
+ Window::StateChanged( nType );
+
+ if ( nType == StateChangedType::Enable )
+ Invalidate();
+ else if ( (nType == StateChangedType::Zoom) ||
+ (nType == StateChangedType::ControlFont) )
+ {
+ ImplInitSettings( true, false, false );
+ Invalidate();
+ }
+ else if ( nType == StateChangedType::ControlForeground )
+ {
+ ImplInitSettings( false, true, false );
+ Invalidate();
+ }
+ else if ( nType == StateChangedType::ControlBackground )
+ {
+ ImplInitSettings( false, false, true );
+ Invalidate();
+ }
+}
+
+void HeaderBar::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Window::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
+ (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
+ ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
+ (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
+ {
+ ImplInitSettings( true, true, true );
+ Invalidate();
+ }
+}
+
+void HeaderBar::EndDrag()
+{
+ maEndDragHdl.Call( this );
+}
+
+void HeaderBar::Select()
+{
+ maSelectHdl.Call( this );
+}
+
+void HeaderBar::DoubleClick()
+{
+}
+
+void HeaderBar::InsertItem( sal_uInt16 nItemId, const OUString& rText,
+ long nSize, HeaderBarItemBits nBits, sal_uInt16 nPos )
+{
+ DBG_ASSERT( nItemId, "HeaderBar::InsertItem(): ItemId == 0" );
+ DBG_ASSERT( GetItemPos( nItemId ) == HEADERBAR_ITEM_NOTFOUND,
+ "HeaderBar::InsertItem(): ItemId already exists" );
+
+ // create item and insert in the list
+ std::unique_ptr<ImplHeadItem> pItem(new ImplHeadItem);
+ pItem->mnId = nItemId;
+ pItem->mnBits = nBits;
+ pItem->mnSize = nSize;
+ pItem->maText = rText;
+ if ( nPos < mvItemList.size() ) {
+ auto it = mvItemList.begin();
+ it += nPos;
+ mvItemList.insert( it, std::move(pItem) );
+ } else {
+ mvItemList.push_back( std::move(pItem) );
+ }
+
+ // update display
+ ImplUpdate( nPos, true );
+}
+
+void HeaderBar::RemoveItem( sal_uInt16 nItemId )
+{
+ sal_uInt16 nPos = GetItemPos( nItemId );
+ if ( nPos != HEADERBAR_ITEM_NOTFOUND )
+ {
+ if ( nPos < mvItemList.size() ) {
+ auto it = mvItemList.begin();
+ it += nPos;
+ mvItemList.erase( it );
+ }
+ }
+}
+
+void HeaderBar::MoveItem( sal_uInt16 nItemId, sal_uInt16 nNewPos )
+{
+ sal_uInt16 nPos = GetItemPos( nItemId );
+ if ( nPos == HEADERBAR_ITEM_NOTFOUND )
+ return;
+
+ if ( nPos == nNewPos )
+ return;
+
+ auto it = mvItemList.begin();
+ it += nPos;
+ std::unique_ptr<ImplHeadItem> pItem = std::move(*it);
+ mvItemList.erase( it );
+ if ( nNewPos < nPos )
+ nPos = nNewPos;
+ it = mvItemList.begin();
+ it += nNewPos;
+ mvItemList.insert( it, std::move(pItem) );
+ ImplUpdate( nPos, true);
+}
+
+void HeaderBar::Clear()
+{
+ // delete all items
+ mvItemList.clear();
+
+ ImplUpdate( 0, true );
+}
+
+void HeaderBar::SetOffset( long nNewOffset )
+{
+ // move area
+ tools::Rectangle aRect( 0, mnBorderOff1, mnDX-1, mnDY-mnBorderOff1-mnBorderOff2-1 );
+ long nDelta = mnOffset-nNewOffset;
+ mnOffset = nNewOffset;
+ Scroll( nDelta, 0, aRect );
+}
+
+sal_uInt16 HeaderBar::GetItemCount() const
+{
+ return static_cast<sal_uInt16>(mvItemList.size());
+}
+
+sal_uInt16 HeaderBar::GetItemPos( sal_uInt16 nItemId ) const
+{
+ for ( size_t i = 0, n = mvItemList.size(); i < n; ++i ) {
+ auto& pItem = mvItemList[ i ];
+ if ( pItem->mnId == nItemId )
+ return static_cast<sal_uInt16>(i);
+ }
+ return HEADERBAR_ITEM_NOTFOUND;
+}
+
+sal_uInt16 HeaderBar::GetItemId( sal_uInt16 nPos ) const
+{
+ ImplHeadItem* pItem = (nPos < mvItemList.size() ) ? mvItemList[ nPos ].get() : nullptr;
+ if ( pItem )
+ return pItem->mnId;
+ else
+ return 0;
+}
+
+sal_uInt16 HeaderBar::GetItemId( const Point& rPos ) const
+{
+ for ( size_t i = 0, n = mvItemList.size(); i < n; ++i ) {
+ if ( ImplGetItemRect( i ).IsInside( rPos ) ) {
+ return GetItemId( i );
+ }
+ }
+ return 0;
+}
+
+tools::Rectangle HeaderBar::GetItemRect( sal_uInt16 nItemId ) const
+{
+ tools::Rectangle aRect;
+ sal_uInt16 nPos = GetItemPos( nItemId );
+ if ( nPos != HEADERBAR_ITEM_NOTFOUND )
+ aRect = ImplGetItemRect( nPos );
+ return aRect;
+}
+
+void HeaderBar::SetItemSize( sal_uInt16 nItemId, long nNewSize )
+{
+ sal_uInt16 nPos = GetItemPos( nItemId );
+ if ( nPos != HEADERBAR_ITEM_NOTFOUND )
+ {
+ auto& pItem = mvItemList[ nPos ];
+ if ( pItem->mnSize != nNewSize )
+ {
+ pItem->mnSize = nNewSize;
+ ImplUpdate( nPos, true );
+ }
+ }
+}
+
+long HeaderBar::GetItemSize( sal_uInt16 nItemId ) const
+{
+ sal_uInt16 nPos = GetItemPos( nItemId );
+ if ( nPos != HEADERBAR_ITEM_NOTFOUND )
+ return mvItemList[ nPos ]->mnSize;
+ else
+ return 0;
+}
+
+void HeaderBar::SetItemBits( sal_uInt16 nItemId, HeaderBarItemBits nNewBits )
+{
+ sal_uInt16 nPos = GetItemPos( nItemId );
+ if ( nPos != HEADERBAR_ITEM_NOTFOUND )
+ {
+ auto& pItem = mvItemList[ nPos ];
+ if ( pItem->mnBits != nNewBits )
+ {
+ pItem->mnBits = nNewBits;
+ ImplUpdate( nPos );
+ }
+ }
+}
+
+HeaderBarItemBits HeaderBar::GetItemBits( sal_uInt16 nItemId ) const
+{
+ sal_uInt16 nPos = GetItemPos( nItemId );
+ if ( nPos != HEADERBAR_ITEM_NOTFOUND )
+ return mvItemList[ nPos ]->mnBits;
+ else
+ return HeaderBarItemBits::NONE;
+}
+
+void HeaderBar::SetItemText( sal_uInt16 nItemId, const OUString& rText )
+{
+ sal_uInt16 nPos = GetItemPos( nItemId );
+ if ( nPos != HEADERBAR_ITEM_NOTFOUND )
+ {
+ mvItemList[ nPos ]->maText = rText;
+ ImplUpdate( nPos );
+ }
+}
+
+OUString HeaderBar::GetItemText( sal_uInt16 nItemId ) const
+{
+ sal_uInt16 nPos = GetItemPos( nItemId );
+ if ( nPos != HEADERBAR_ITEM_NOTFOUND )
+ return mvItemList[ nPos ]->maText;
+ return OUString();
+}
+
+OUString HeaderBar::GetHelpText( sal_uInt16 nItemId ) const
+{
+ sal_uInt16 nPos = GetItemPos( nItemId );
+ if ( nPos != HEADERBAR_ITEM_NOTFOUND )
+ {
+ auto& pItem = mvItemList[ nPos ];
+ if ( pItem->maHelpText.isEmpty() && !pItem->maHelpId.isEmpty() )
+ {
+ Help* pHelp = Application::GetHelp();
+ if ( pHelp )
+ pItem->maHelpText = pHelp->GetHelpText( OStringToOUString( pItem->maHelpId, RTL_TEXTENCODING_UTF8 ), this );
+ }
+
+ return pItem->maHelpText;
+ }
+
+ return OUString();
+}
+
+OString HeaderBar::GetHelpId( sal_uInt16 nItemId ) const
+{
+ sal_uInt16 nPos = GetItemPos( nItemId );
+ if ( nPos != HEADERBAR_ITEM_NOTFOUND )
+ return mvItemList[ nPos ]->maHelpId;
+ return OString();
+}
+
+Size HeaderBar::CalcWindowSizePixel() const
+{
+ long nMaxImageSize = 0;
+ Size aSize( 0, GetTextHeight() );
+
+ for (auto& pItem : mvItemList)
+ {
+ // take image size into account
+ long nImageHeight = pItem->maImage.GetSizePixel().Height();
+ if ( !(pItem->mnBits & (HeaderBarItemBits::LEFTIMAGE | HeaderBarItemBits::RIGHTIMAGE)) && !pItem->maText.isEmpty() )
+ nImageHeight += aSize.Height();
+ if ( nImageHeight > nMaxImageSize )
+ nMaxImageSize = nImageHeight;
+
+ // add width
+ aSize.AdjustWidth(pItem->mnSize );
+ }
+
+ if ( nMaxImageSize > aSize.Height() )
+ aSize.setHeight( nMaxImageSize );
+
+ // add border
+ if ( mbButtonStyle )
+ aSize.AdjustHeight(4 );
+ else
+ aSize.AdjustHeight(2 );
+ aSize.AdjustHeight(mnBorderOff1+mnBorderOff2 );
+
+ return aSize;
+}
+
+css::uno::Reference< css::accessibility::XAccessible > HeaderBar::CreateAccessible()
+{
+ if ( !mxAccessible.is() )
+ {
+ maCreateAccessibleHdl.Call( this );
+
+ if ( !mxAccessible.is() )
+ mxAccessible = Window::CreateAccessible();
+ }
+
+ return mxAccessible;
+}
+
+void HeaderBar::SetAccessible( const css::uno::Reference< css::accessibility::XAccessible >& _xAccessible )
+{
+ mxAccessible = _xAccessible;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/treelist/svtabbx.cxx b/vcl/source/treelist/svtabbx.cxx
new file mode 100644
index 000000000000..72c7a8f50926
--- /dev/null
+++ b/vcl/source/treelist/svtabbx.cxx
@@ -0,0 +1,1155 @@
+/* -*- 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/svtabbx.hxx>
+#include <vcl/headbar.hxx>
+#include <vcl/svlbitm.hxx>
+#include <vcl/treelistentry.hxx>
+#include <vcl/builderfactory.hxx>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <o3tl/make_unique.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+#include <strings.hrc>
+#include <svdata.hxx>
+#include <memory>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::accessibility;
+
+static constexpr SvLBoxTabFlags MYTABMASK =
+ SvLBoxTabFlags::ADJUST_RIGHT | SvLBoxTabFlags::ADJUST_LEFT | SvLBoxTabFlags::ADJUST_CENTER | SvLBoxTabFlags::ADJUST_NUMERIC;
+
+// 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 tre listbox itself! This behavior is
+ // necessary for ButtonsOnRoot, as the explorer does not know in this
+ // case, which additional offset it need 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, SvLBoxButtonKind eButtonKind)
+{
+ SvTreeListBox::InitEntry(pEntry, rStr, rColl, rExp, eButtonKind);
+
+ 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 OUString aToken = GetToken(aCurEntry, nIndex);
+ pEntry->AddItem(o3tl::make_unique<SvLBoxString>(aToken));
+ }
+}
+
+SvTabListBox::SvTabListBox( vcl::Window* pParent, WinBits nBits )
+ : SvTreeListBox( pParent, nBits )
+{
+ SetHighlightRange(); // select full width
+}
+
+VCL_BUILDER_FACTORY_CONSTRUCTOR(SvTabListBox, WB_TABSTOP)
+
+SvTabListBox::~SvTabListBox()
+{
+ disposeOnce();
+}
+
+void SvTabListBox::dispose()
+{
+ mvTabList.clear();
+ SvTreeListBox::dispose();
+}
+
+void SvTabListBox::SetTabs(sal_uInt16 nTabs, 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 );
+ long nNewTab = aSize.Width();
+ mvTabList[nIdx].SetPos( nNewTab );
+ mvTabList[nIdx].nFlags=(SvLBoxTabFlags::ADJUST_LEFT| SvLBoxTabFlags::INV_ALWAYS);
+ }
+ SvTreeListBox::nTreeFlags |= SvTreeFlags::RECALCTABS;
+ if( IsUpdateMode() )
+ Invalidate();
+}
+
+void SvTabListBox::SetTab( sal_uInt16 nTab,long nValue,MapUnit eMapUnit )
+{
+ DBG_ASSERT(nTab<mvTabList.size(),"Invalid Tab-Pos");
+ if( nTab >= mvTabList.size() )
+ return;
+
+ MapMode aMMSource( eMapUnit );
+ MapMode aMMDest( MapUnit::MapPixel );
+ Size aSize( nValue, 0 );
+ aSize = LogicToLogic( aSize, &aMMSource, &aMMDest );
+ nValue = aSize.Width();
+ mvTabList[ nTab ].SetPos( nValue );
+ SvTreeListBox::nTreeFlags |= SvTreeFlags::RECALCTABS;
+ if( IsUpdateMode() )
+ Invalidate();
+}
+
+SvTreeListEntry* SvTabListBox::InsertEntry( const OUString& rText, SvTreeListEntry* pParent,
+ bool /*bChildrenOnDemand*/,
+ sal_uLong nPos, void* pUserData,
+ SvLBoxButtonKind )
+{
+ return InsertEntryToColumn( rText, pParent, nPos, 0xffff, pUserData );
+}
+
+SvTreeListEntry* SvTabListBox::InsertEntry( const OUString& rText,
+ const Image& rExpandedEntryBmp,
+ const Image& rCollapsedEntryBmp,
+ SvTreeListEntry* pParent,
+ bool /*bChildrenOnDemand*/,
+ sal_uLong nPos, void* pUserData,
+ SvLBoxButtonKind )
+{
+ return InsertEntryToColumn( rText, rExpandedEntryBmp, rCollapsedEntryBmp,
+ pParent, nPos, 0xffff, pUserData );
+}
+
+SvTreeListEntry* SvTabListBox::InsertEntryToColumn(const OUString& rStr,SvTreeListEntry* pParent,sal_uLong 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 );
+}
+
+SvTreeListEntry* SvTabListBox::InsertEntryToColumn( const OUString& rStr,
+ const Image& rExpandedEntryBmp, const Image& rCollapsedEntryBmp,
+ SvTreeListEntry* pParent,sal_uLong 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,
+ rExpandedEntryBmp, rCollapsedEntryBmp,
+ pParent, false, nPos, pUser );
+}
+
+SvTreeListEntry* SvTabListBox::InsertEntryToColumn( const OUString& rStr, sal_uLong nPos,
+ sal_uInt16 nCol, void* pUser )
+{
+ return InsertEntryToColumn( rStr,nullptr,nPos, nCol, pUser );
+}
+
+OUString SvTabListBox::GetEntryText( SvTreeListEntry* pEntry ) const
+{
+ return GetEntryText( pEntry, 0xffff );
+}
+
+OUString SvTabListBox::GetEntryText( 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_uLong nPos, sal_uInt16 nCol ) const
+{
+ SvTreeListEntry* pEntry = GetEntryOnPos( nPos );
+ return GetEntryText( pEntry, nCol );
+}
+
+void SvTabListBox::SetEntryText(const OUString& rStr, sal_uLong nPos, sal_uInt16 nCol)
+{
+ SvTreeListEntry* pEntry = SvTreeListBox::GetEntry( nPos );
+ SetEntryText( rStr, pEntry, nCol );
+}
+
+void SvTabListBox::SetEntryText(const OUString& rStr, SvTreeListEntry* pEntry, sal_uInt16 nCol)
+{
+ DBG_ASSERT(pEntry,"SetEntryText:Invalid Entry");
+ if( !pEntry )
+ return;
+
+ OUString sOldText = GetEntryText(pEntry, nCol);
+ if (sOldText == rStr)
+ return;
+
+ sal_Int32 nIndex = 0;
+ const sal_uInt16 nTextColumn = nCol;
+ const sal_uInt16 nCount = pEntry->ItemCount();
+ for (sal_uInt16 nCur = 0; nCur < nCount; ++nCur)
+ {
+ SvLBoxItem& rBoxItem = pEntry->GetItem( nCur );
+ if (rBoxItem.GetType() == SvLBoxItemType::String)
+ {
+ if (!nCol || nCol==0xFFFF)
+ {
+ const OUString aTemp(GetToken(rStr, nIndex));
+ static_cast<SvLBoxString&>(rBoxItem).SetText( aTemp );
+ if (!nCol && nIndex<0)
+ break;
+ }
+ else
+ {
+ --nCol;
+ }
+ }
+ }
+ GetModel()->InvalidateEntry( pEntry );
+
+ std::unique_ptr<TabListBoxEventData> pData( new TabListBoxEventData( pEntry, nTextColumn, sOldText ) );
+ CallEventListeners( VclEventId::TableCellNameChanged, pData.get() );
+}
+
+OUString SvTabListBox::GetCellText( sal_uLong nPos, sal_uInt16 nCol ) const
+{
+ SvTreeListEntry* pEntry = GetEntryOnPos( nPos );
+ DBG_ASSERT( pEntry, "SvTabListBox::GetCellText(): Invalid Entry" );
+ OUString aResult;
+ if (pEntry && pEntry->ItemCount() > static_cast<size_t>(nCol+1))
+ {
+ const SvLBoxItem& rStr = pEntry->GetItem( nCol + 1 );
+ if (rStr.GetType() == SvLBoxItemType::String)
+ aResult = static_cast<const SvLBoxString&>(rStr).GetText();
+ }
+ return aResult;
+}
+
+sal_uLong SvTabListBox::GetEntryPos( const OUString& rStr, sal_uInt16 nCol )
+{
+ sal_uLong nPos = 0;
+ SvTreeListEntry* pEntry = First();
+ while( pEntry )
+ {
+ OUString aStr( GetEntryText( pEntry, nCol ));
+ if( aStr == rStr )
+ return nPos;
+ pEntry = Next( pEntry );
+ nPos++;
+ }
+ return 0xffffffff;
+}
+
+sal_uLong SvTabListBox::GetEntryPos( const SvTreeListEntry* pEntry ) const
+{
+ sal_uLong nPos = 0;
+ SvTreeListEntry* pTmpEntry = First();
+ while( pTmpEntry )
+ {
+ if ( pTmpEntry == pEntry )
+ return nPos;
+ pTmpEntry = Next( pTmpEntry );
+ ++nPos;
+ }
+ return 0xffffffff;
+}
+
+// static
+OUString SvTabListBox::GetToken( const OUString &sStr, sal_Int32& nIndex )
+{
+ return sStr.getToken(0, '\t', nIndex);
+}
+
+OUString SvTabListBox::GetTabEntryText( sal_uLong 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 == nCol && IsCellFocusEnabled() ) ? GetCurrentTabPos() : 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_uLong _nEntryPos ) const
+{
+ SvTreeListEntry* pEntry = nullptr;
+ sal_uLong 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_uLong _nEntryPos, sal_uLong& _rPos ) const
+{
+ sal_uLong 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);
+ nFlags |= static_cast<SvLBoxTabFlags>(eJustify);
+ rTab.nFlags = nFlags;
+ SvTreeListBox::nTreeFlags |= SvTreeFlags::RECALCTABS;
+ if( IsUpdateMode() )
+ Invalidate();
+}
+
+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 ) );
+}
+
+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, sal_uLong nPos, sal_uInt16 nCol, void* pUserData )
+{
+ SvTreeListEntry* pEntry = SvTabListBox::InsertEntryToColumn( rStr, nPos, nCol, pUserData );
+ RecalculateAccessibleChildren();
+ return pEntry;
+}
+
+SvTreeListEntry* SvHeaderTabListBox::InsertEntryToColumn(
+ const OUString& rStr, SvTreeListEntry* pParent, sal_uLong nPos, sal_uInt16 nCol, void* pUserData )
+{
+ SvTreeListEntry* pEntry = SvTabListBox::InsertEntryToColumn( rStr, pParent, nPos, nCol, pUserData );
+ RecalculateAccessibleChildren();
+ return pEntry;
+}
+
+SvTreeListEntry* SvHeaderTabListBox::InsertEntryToColumn(
+ const OUString& rStr, const Image& rExpandedEntryBmp, const Image& rCollapsedEntryBmp,
+ SvTreeListEntry* pParent, sal_uLong nPos, sal_uInt16 nCol, void* pUserData )
+{
+ SvTreeListEntry* pEntry = SvTabListBox::InsertEntryToColumn(
+ rStr, rExpandedEntryBmp, rCollapsedEntryBmp, pParent, nPos, nCol, pUserData );
+ RecalculateAccessibleChildren();
+ return pEntry;
+}
+
+sal_uLong SvHeaderTabListBox::Insert(
+ SvTreeListEntry* pEnt, SvTreeListEntry* pPar, sal_uLong nPos )
+{
+ sal_uLong n = SvTabListBox::Insert( pEnt, pPar, nPos );
+ RecalculateAccessibleChildren();
+ return n;
+}
+
+sal_uLong SvHeaderTabListBox::Insert( SvTreeListEntry* pEntry, sal_uLong nRootPos )
+{
+ sal_uLong nPos = SvTabListBox::Insert( pEntry, nRootPos );
+ RecalculateAccessibleChildren();
+ return nPos;
+}
+
+void SvHeaderTabListBox::RemoveEntry( SvTreeListEntry const * _pEntry )
+{
+ GetModel()->Remove( _pEntry );
+ m_aAccessibleChildren.clear();
+}
+
+void SvHeaderTabListBox::Clear()
+{
+ SvTabListBox::Clear();
+ m_aAccessibleChildren.clear();
+}
+
+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, ::vcl::BBTYPE_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( long _nRow, sal_uInt16 _nColumn, TriState& _rState )
+{
+ 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;
+}
+long 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_uLong nCount = GetEntryCount();
+ for ( sal_uLong i = 0; i < nCount; ++i )
+ {
+ if ( pEntry == GetEntry(i) )
+ {
+ nRet = i;
+ break;
+ }
+ }
+ }
+
+ return nRet;
+}
+
+sal_uInt16 SvHeaderTabListBox::GetCurrColumn() const
+{
+ sal_uInt16 nPos = GetCurrentTabPos() - 1;
+ return nPos;
+}
+
+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 )
+{
+ bool bRet = IsCellFocusEnabled();
+ if ( bRet )
+ {
+ // first set cursor to _nRow
+ SetCursor( GetEntry( _nRow ), true );
+ // then set the focus into _nColumn
+ bRet = SetCurrentTabPos( _nColumn );
+ }
+ return bRet;
+}
+
+void SvHeaderTabListBox::SetNoSelection()
+{
+ SvTreeListBox::SelectAll(false);
+}
+
+void SvHeaderTabListBox::SelectAll()
+{
+ SvTreeListBox::SelectAll(true);
+}
+
+void SvHeaderTabListBox::SelectRow( long _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( long _nRow ) const
+{
+ SvTreeListEntry* pEntry = GetEntry( _nRow );
+ return ( pEntry && IsSelected( pEntry ) );
+}
+
+bool SvHeaderTabListBox::IsColumnSelected( long ) 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( long _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;
+ sal_Int32 nIndex = -1;
+
+ if ( !AreChildrenTransient() )
+ {
+ const sal_uInt16 nColumnCount = GetColumnCount();
+
+ // first call? -> initial list
+ if ( m_aAccessibleChildren.empty() )
+ {
+ sal_Int32 nCount = ( GetRowCount() + 1 ) * nColumnCount;
+ m_aAccessibleChildren.assign( nCount, Reference< XAccessible >() );
+ }
+
+ nIndex = ( _nRow * nColumnCount ) + _nColumnPos + nColumnCount;
+ xChild = m_aAccessibleChildren[ nIndex ];
+ }
+
+ if ( !xChild.is() )
+ {
+ 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 );
+
+ // insert into list
+ if ( !AreChildrenTransient() )
+ m_aAccessibleChildren[ nIndex ] = xChild;
+ }
+
+ 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();
+ sal_Int32 nCount = AreChildrenTransient() ?
+ nColumnCount : ( GetRowCount() + 1 ) * nColumnCount;
+ m_aAccessibleChildren.assign( nCount, 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, ::vcl::BBTYPE_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( ::vcl::AccessibleBrowseBoxObjType _eType, sal_Int32 _nPos ) const
+{
+ OUString aRetText;
+ switch( _eType )
+ {
+ case ::vcl::BBTYPE_BROWSEBOX:
+ case ::vcl::BBTYPE_TABLE:
+ case ::vcl::BBTYPE_COLUMNHEADERBAR:
+ // should be empty now (see #i63983)
+ aRetText.clear();
+ break;
+
+ case ::vcl::BBTYPE_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 ::vcl::BBTYPE_CHECKBOXCELL:
+ {
+ break; // checkbox cells have no name
+ }
+ case ::vcl::BBTYPE_COLUMNHEADERCELL:
+ {
+ aRetText = m_pImpl->m_pHeaderBar->GetItemText( m_pImpl->m_pHeaderBar->GetItemId( static_cast<sal_uInt16>(_nPos) ) );
+ break;
+ }
+
+ case ::vcl::BBTYPE_ROWHEADERBAR:
+ case ::vcl::BBTYPE_ROWHEADERCELL:
+ aRetText = "error";
+ break;
+
+ default:
+ OSL_FAIL("BrowseBox::GetAccessibleName: invalid enum!");
+ }
+ return aRetText;
+}
+
+OUString SvHeaderTabListBox::GetAccessibleObjectDescription( ::vcl::AccessibleBrowseBoxObjType _eType, sal_Int32 _nPos ) const
+{
+ OUString aRetText;
+
+ if( _eType == ::vcl::BBTYPE_TABLECELL && _nPos != -1 )
+ {
+ const OUString sVar1( "%1" );
+ const OUString sVar2( "%2" );
+
+ 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( sVar1, 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( sVar2, sColHeader );
+ aRetText = aText;
+ }
+ }
+
+ return aRetText;
+}
+
+void SvHeaderTabListBox::FillAccessibleStateSet( ::utl::AccessibleStateSetHelper& _rStateSet, ::vcl::AccessibleBrowseBoxObjType _eType ) const
+{
+ switch( _eType )
+ {
+ case ::vcl::BBTYPE_BROWSEBOX:
+ case ::vcl::BBTYPE_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 == ::vcl::BBTYPE_TABLE )
+ {
+
+ if ( AreChildrenTransient() )
+ _rStateSet.AddState( AccessibleStateType::MANAGES_DESCENDANTS );
+ _rStateSet.AddState( AccessibleStateType::MULTI_SELECTABLE );
+ }
+ break;
+ }
+
+ case ::vcl::BBTYPE_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 ::vcl::BBTYPE_ROWHEADERCELL:
+ case ::vcl::BBTYPE_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 );
+ if ( AreChildrenTransient() )
+ _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, MetricVector& rVector )
+{
+ return Control::GetGlyphBoundRects( rOrigin, rStr, nIndex, nLen, rVector );
+}
+
+tools::Rectangle SvHeaderTabListBox::GetWindowExtentsRelative( 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 ) );
+ MetricVector aRects;
+ if ( GetGlyphBoundRects(Point(0,0), sText, 0, sText.getLength(), aRects) )
+ {
+ sal_Int32 nPos = 0;
+ for (auto const& rectangle : aRects)
+ {
+ if( rectangle.IsInside(_rPoint) )
+ return nPos;
+ ++nPos;
+ }
+ }
+
+ return -1;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/treelist/treelistbox.cxx b/vcl/source/treelist/treelistbox.cxx
index ec0244ce5157..c1269b26c174 100644
--- a/vcl/source/treelist/treelistbox.cxx
+++ b/vcl/source/treelist/treelistbox.cxx
@@ -3587,12 +3587,23 @@ void SvTreeListBox::EnableContextMenuHandling()
pImpl->bContextMenuHandling = true;
}
-void SvTreeListBox::EnableList( bool _bEnable )
+css::uno::Reference< XAccessible > SvTreeListBox::CreateAccessible()
{
- // call base class method
- Window::Enable(_bEnable);
- // then invalidate
- Invalidate(tools::Rectangle(Point(), GetSizePixel()));
+ vcl::Window* pParent = GetAccessibleParentWindow();
+ DBG_ASSERT( pParent, "SvTreeListBox::CreateAccessible - accessible parent not found" );
+
+ css::uno::Reference< XAccessible > xAccessible;
+ if ( pParent )
+ {
+ css::uno::Reference< XAccessible > xAccParent = pParent->GetAccessible();
+ if ( xAccParent.is() )
+ {
+ // need to be done here to get the vclxwindow later on in the accessible
+ css::uno::Reference< css::awt::XWindowPeer > xTemp(GetComponentInterface());
+ xAccessible = pImpl->m_aFactoryAccess.getFactory().createAccessibleTreeListBox( *this, xAccParent );
+ }
+ }
+ return xAccessible;
}
void SvTreeListBox::FillAccessibleEntryStateSet( SvTreeListEntry* pEntry, ::utl::AccessibleStateSetHelper& rStateSet ) const
diff --git a/vcl/source/window/builder.cxx b/vcl/source/window/builder.cxx
index 6e782336f75f..acd8195b4a1b 100644
--- a/vcl/source/window/builder.cxx
+++ b/vcl/source/window/builder.cxx
@@ -36,11 +36,11 @@
#include <vcl/prgsbar.hxx>
#include <vcl/scrbar.hxx>
#include <vcl/svapp.hxx>
+#include <vcl/svtabbx.hxx>
#include <vcl/tabctrl.hxx>
#include <vcl/tabpage.hxx>
#include <vcl/throbber.hxx>
#include <vcl/toolbox.hxx>
-#include <vcl/treelistbox.hxx>
#include <vcl/treelistentry.hxx>
#include <vcl/vclmedit.hxx>
#include <vcl/settings.hxx>
@@ -518,7 +518,7 @@ VclBuilder::VclBuilder(vcl::Window *pParent, const OUString& sUIDir, const OUStr
vcl::Window* pTarget = get<vcl::Window>(elem.m_sID);
ListBox *pListBoxTarget = dynamic_cast<ListBox*>(pTarget);
ComboBox *pComboBoxTarget = dynamic_cast<ComboBox*>(pTarget);
- SvTreeListBox *pTreeBoxTarget = dynamic_cast<SvTreeListBox*>(pTarget);
+ SvTabListBox *pTreeBoxTarget = dynamic_cast<SvTabListBox*>(pTarget);
// pStore may be empty
const ListStore *pStore = get_model_by_name(elem.m_sValue.toUtf8());
SAL_WARN_IF(!pListBoxTarget && !pComboBoxTarget && !pTreeBoxTarget, "vcl", "missing elements of combobox");
@@ -1872,10 +1872,10 @@ VclPtr<vcl::Window> VclBuilder::makeObject(vcl::Window *pParent, const OString &
else if (name == "GtkTreeView")
{
//To-Do
- //a) make SvTreeListBox the default target for GtkTreeView
+ //a) make SvTabListBox the default target for GtkTreeView
//b) remove the non-drop down mode of ListBox and convert
- // everything over to SvTreeListBox
- //c) remove the users of makeSvTreeListBox
+ // everything over to SvTabListBox
+ //c) remove the users of makeSvTabListBox and makeSvTreeListBox
extractModel(id, rMap);
WinBits nWinStyle = WB_CLIPCHILDREN|WB_LEFT|WB_VCENTER|WB_3DLOOK|WB_SIMPLEMODE;
if (m_bLegacy)
@@ -1884,7 +1884,7 @@ VclPtr<vcl::Window> VclBuilder::makeObject(vcl::Window *pParent, const OString &
if (!sBorder.isEmpty())
nWinStyle |= WB_BORDER;
}
- //ListBox/SvTreeListBox manages its own scrolling,
+ //ListBox/SvTabListBox manages its own scrolling,
vcl::Window *pRealParent = prepareWidgetOwnScrolling(pParent, nWinStyle);
if (pRealParent != pParent)
nWinStyle |= WB_BORDER;
@@ -1892,7 +1892,7 @@ VclPtr<vcl::Window> VclBuilder::makeObject(vcl::Window *pParent, const OString &
xWindow = VclPtr<ListBox>::Create(pRealParent, nWinStyle);
else
{
- VclPtrInstance<SvTreeListBox> xBox(pRealParent, nWinStyle | WB_HASBUTTONS | WB_HASBUTTONSATROOT);
+ VclPtrInstance<SvTabListBox> xBox(pRealParent, nWinStyle);
xBox->SetNoAutoCurEntry(true);
xBox->SetHighlightRange(); // select over the whole width
xWindow = xBox;
@@ -4081,7 +4081,7 @@ void VclBuilder::mungeModel(ListBox &rTarget, const ListStore &rStore, sal_uInt1
rTarget.SelectEntryPos(nActiveId);
}
-void VclBuilder::mungeModel(SvTreeListBox &rTarget, const ListStore &rStore, sal_uInt16 nActiveId)
+void VclBuilder::mungeModel(SvTabListBox &rTarget, const ListStore &rStore, sal_uInt16 nActiveId)
{
for (auto const& entry : rStore.m_aEntries)
{