diff options
author | Caolán McNamara <caolanm@redhat.com> | 2018-11-17 21:37:50 +0000 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2018-11-21 22:08:04 +0100 |
commit | 47897fdd936d9b6e9ac8cb6110c79352ab080df7 (patch) | |
tree | c657b53080caa94590d1e9b1fd4383d6dc795728 /vcl/source | |
parent | cfa76f538a44d4396574ece59e8a3953c22c6eb7 (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.cxx | 60 | ||||
-rw-r--r-- | vcl/source/helper/svtaccessiblefactory.cxx | 270 | ||||
-rw-r--r-- | vcl/source/treelist/headbar.cxx | 1354 | ||||
-rw-r--r-- | vcl/source/treelist/svtabbx.cxx | 1155 | ||||
-rw-r--r-- | vcl/source/treelist/treelistbox.cxx | 21 | ||||
-rw-r--r-- | vcl/source/window/builder.cxx | 16 |
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) { |