summaryrefslogtreecommitdiffstats
path: root/framework/source/layoutmanager/toolbarlayoutmanager.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'framework/source/layoutmanager/toolbarlayoutmanager.cxx')
-rw-r--r--framework/source/layoutmanager/toolbarlayoutmanager.cxx4116
1 files changed, 4116 insertions, 0 deletions
diff --git a/framework/source/layoutmanager/toolbarlayoutmanager.cxx b/framework/source/layoutmanager/toolbarlayoutmanager.cxx
new file mode 100644
index 000000000..34b2b0899
--- /dev/null
+++ b/framework/source/layoutmanager/toolbarlayoutmanager.cxx
@@ -0,0 +1,4116 @@
+/* -*- 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 "toolbarlayoutmanager.hxx"
+#include <uiconfiguration/windowstateproperties.hxx>
+#include <uielement/addonstoolbarwrapper.hxx>
+#include "helpers.hxx"
+#include <services/layoutmanager.hxx>
+#include <strings.hrc>
+#include <classes/fwkresid.hxx>
+
+#include <com/sun/star/awt/PosSize.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/ui/UIElementType.hpp>
+#include <com/sun/star/container/XNameReplace.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/ui/XUIElementSettings.hpp>
+#include <com/sun/star/ui/XUIFunctionListener.hpp>
+
+#include <comphelper/propertyvalue.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <o3tl/string_view.hxx>
+#include <unotools/cmdoptions.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <toolkit/helper/convert.hxx>
+#include <utility>
+#include <vcl/i18nhelp.hxx>
+#include <vcl/dockingarea.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <sal/log.hxx>
+#include <tools/gen.hxx>
+
+
+using namespace ::com::sun::star;
+
+namespace framework
+{
+
+ToolbarLayoutManager::ToolbarLayoutManager(
+ uno::Reference< uno::XComponentContext > xContext,
+ uno::Reference< ui::XUIElementFactory > xUIElementFactory,
+ LayoutManager* pParentLayouter ):
+ m_xContext(std::move( xContext)),
+ m_xUIElementFactoryManager(std::move( xUIElementFactory )),
+ m_pParentLayouter( pParentLayouter ),
+ m_aDockingArea(0, 0, 0, 0),
+ m_aDockingAreaOffsets(0, 0, 0, 0),
+ m_eDockOperation( DOCKOP_ON_COLROW ),
+ m_ePreviewDetection( PREVIEWFRAME_UNKNOWN ),
+ m_bComponentAttached( false ),
+ m_bLayoutDirty( false ),
+ m_bGlobalSettings( false ),
+ m_bDockingInProgress( false ),
+ m_bLayoutInProgress( false ),
+ m_bToolbarCreation( false )
+{
+}
+
+ToolbarLayoutManager::~ToolbarLayoutManager()
+{
+ m_pGlobalSettings.reset();
+ m_pAddonOptions.reset();
+}
+
+// XInterface
+
+void SAL_CALL ToolbarLayoutManager::acquire() noexcept
+{
+ OWeakObject::acquire();
+}
+
+void SAL_CALL ToolbarLayoutManager::release() noexcept
+{
+ OWeakObject::release();
+}
+
+uno::Any SAL_CALL ToolbarLayoutManager::queryInterface( const uno::Type & rType )
+{
+ uno::Any a = ::cppu::queryInterface( rType,
+ static_cast< awt::XDockableWindowListener* >(this),
+ static_cast< ui::XUIConfigurationListener* >(this),
+ static_cast< awt::XWindowListener* >(this));
+
+ if ( a.hasValue() )
+ return a;
+
+ return OWeakObject::queryInterface( rType );
+}
+
+void SAL_CALL ToolbarLayoutManager::disposing( const lang::EventObject& aEvent )
+{
+ if ( aEvent.Source == m_xFrame )
+ {
+ // Reset all internal references
+ reset();
+ implts_destroyDockingAreaWindows();
+ }
+}
+
+awt::Rectangle ToolbarLayoutManager::getDockingArea()
+{
+ SolarMutexResettableGuard aWriteLock;
+ tools::Rectangle aNewDockingArea( m_aDockingArea );
+ aWriteLock.clear();
+
+ if ( isLayoutDirty() )
+ aNewDockingArea = implts_calcDockingArea();
+
+ aWriteLock.reset();
+ m_aDockingArea = aNewDockingArea;
+ aWriteLock.clear();
+
+ return putRectangleValueToAWT(aNewDockingArea);
+}
+
+void ToolbarLayoutManager::setDockingArea( const awt::Rectangle& rDockingArea )
+{
+ SolarMutexGuard g;
+ m_aDockingArea = putAWTToRectangle( rDockingArea );
+ m_bLayoutDirty = true;
+}
+
+void ToolbarLayoutManager::implts_setDockingAreaWindowSizes( const awt::Rectangle& rBorderSpace )
+{
+ SolarMutexClearableGuard aReadLock;
+ tools::Rectangle aDockOffsets = m_aDockingAreaOffsets;
+ uno::Reference< awt::XWindow2 > xContainerWindow( m_xContainerWindow );
+ uno::Reference< awt::XWindow > xTopDockAreaWindow( m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_TOP)] );
+ uno::Reference< awt::XWindow > xBottomDockAreaWindow( m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_BOTTOM)] );
+ uno::Reference< awt::XWindow > xLeftDockAreaWindow( m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_LEFT)] );
+ uno::Reference< awt::XWindow > xRightDockAreaWindow( m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_RIGHT)] );
+ aReadLock.clear();
+
+ uno::Reference< awt::XDevice > xDevice( xContainerWindow, uno::UNO_QUERY );
+
+ // Convert relative size to output size.
+ awt::Rectangle aRectangle = xContainerWindow->getPosSize();
+ awt::DeviceInfo aInfo = xDevice->getInfo();
+ awt::Size aContainerClientSize( aRectangle.Width - aInfo.LeftInset - aInfo.RightInset ,
+ aRectangle.Height - aInfo.TopInset - aInfo.BottomInset );
+ tools::Long aStatusBarHeight = aDockOffsets.GetHeight();
+
+ sal_Int32 nLeftRightDockingAreaHeight( aContainerClientSize.Height );
+ if ( rBorderSpace.Y >= 0 )
+ {
+ // Top docking area window
+ xTopDockAreaWindow->setPosSize( 0, 0, aContainerClientSize.Width, rBorderSpace.Y, awt::PosSize::POSSIZE );
+ xTopDockAreaWindow->setVisible( true );
+ nLeftRightDockingAreaHeight -= rBorderSpace.Y;
+ }
+
+ if ( rBorderSpace.Height >= 0 )
+ {
+ // Bottom docking area window
+ sal_Int32 nBottomPos = std::max( sal_Int32( aContainerClientSize.Height - rBorderSpace.Height - aStatusBarHeight + 1 ), sal_Int32( 0 ));
+ sal_Int32 nHeight = ( nBottomPos == 0 ) ? 0 : rBorderSpace.Height;
+
+ xBottomDockAreaWindow->setPosSize( 0, nBottomPos, aContainerClientSize.Width, nHeight, awt::PosSize::POSSIZE );
+ xBottomDockAreaWindow->setVisible( true );
+ nLeftRightDockingAreaHeight -= nHeight - 1;
+ }
+
+ nLeftRightDockingAreaHeight -= aStatusBarHeight;
+ if ( rBorderSpace.X >= 0 || nLeftRightDockingAreaHeight > 0 )
+ {
+ // Left docking area window
+ // We also have to change our right docking area window if the top or bottom area has changed. They have a higher priority!
+ sal_Int32 nHeight = std::max<sal_Int32>( 0, nLeftRightDockingAreaHeight );
+
+ xLeftDockAreaWindow->setPosSize( 0, rBorderSpace.Y, rBorderSpace.X, nHeight, awt::PosSize::POSSIZE );
+ xLeftDockAreaWindow->setVisible( true );
+ }
+ if ( rBorderSpace.Width >= 0 || nLeftRightDockingAreaHeight > 0 )
+ {
+ // Right docking area window
+ // We also have to change our right docking area window if the top or bottom area has changed. They have a higher priority!
+ sal_Int32 nLeftPos = std::max<sal_Int32>( 0, aContainerClientSize.Width - rBorderSpace.Width );
+ sal_Int32 nHeight = std::max<sal_Int32>( 0, nLeftRightDockingAreaHeight );
+ sal_Int32 nWidth = ( nLeftPos == 0 ) ? 0 : rBorderSpace.Width;
+
+ xRightDockAreaWindow->setPosSize( nLeftPos, rBorderSpace.Y, nWidth, nHeight, awt::PosSize::POSSIZE );
+ xRightDockAreaWindow->setVisible( true );
+ }
+}
+
+
+void ToolbarLayoutManager::doLayout(const ::Size& aContainerSize)
+{
+ SolarMutexResettableGuard aWriteLock;
+ bool bLayoutInProgress( m_bLayoutInProgress );
+ m_bLayoutInProgress = true;
+ awt::Rectangle aDockingArea = putRectangleValueToAWT( m_aDockingArea );
+ aWriteLock.clear();
+
+ if ( bLayoutInProgress )
+ return;
+
+ // Retrieve row/column dependent data from all docked user-interface elements
+ for ( sal_Int32 i = 0; i < DOCKINGAREAS_COUNT; i++ )
+ {
+ bool bReverse( isReverseOrderDockingArea( i ));
+ std::vector< SingleRowColumnWindowData > aRowColumnsWindowData;
+
+ implts_getDockingAreaElementInfos( static_cast<ui::DockingArea>(i), aRowColumnsWindowData );
+
+ sal_Int32 nOffset( 0 );
+ const sal_uInt32 nCount = aRowColumnsWindowData.size();
+ for ( sal_uInt32 j = 0; j < nCount; ++j )
+ {
+ sal_uInt32 nIndex = bReverse ? nCount-j-1 : j;
+ implts_calcWindowPosSizeOnSingleRowColumn( i, nOffset, aRowColumnsWindowData[nIndex], aContainerSize );
+ nOffset += aRowColumnsWindowData[j].nStaticSize;
+ }
+ }
+
+ implts_setDockingAreaWindowSizes( aDockingArea );
+
+ aWriteLock.reset();
+ m_bLayoutDirty = false;
+ m_bLayoutInProgress = false;
+ aWriteLock.clear();
+}
+
+bool ToolbarLayoutManager::implts_isParentWindowVisible() const
+{
+ SolarMutexGuard g;
+ bool bVisible( false );
+ if ( m_xContainerWindow.is() )
+ bVisible = m_xContainerWindow->isVisible();
+
+ return bVisible;
+}
+
+tools::Rectangle ToolbarLayoutManager::implts_calcDockingArea()
+{
+ SolarMutexClearableGuard aReadLock;
+ UIElementVector aWindowVector( m_aUIElements );
+ aReadLock.clear();
+
+ tools::Rectangle aBorderSpace;
+ sal_Int32 nCurrRowColumn( 0 );
+ sal_Int32 nCurrPos( 0 );
+ ui::DockingArea nCurrDockingArea( ui::DockingArea_DOCKINGAREA_TOP );
+ std::vector< sal_Int32 > aRowColumnSizes[DOCKINGAREAS_COUNT];
+
+ // initialize rectangle with zero values!
+ aBorderSpace.setWidth(0);
+ aBorderSpace.setHeight(0);
+
+ aRowColumnSizes[static_cast<int>(nCurrDockingArea)].clear();
+ aRowColumnSizes[static_cast<int>(nCurrDockingArea)].push_back( 0 );
+
+ for (auto const& window : aWindowVector)
+ {
+ if ( window.m_xUIElement.is() )
+ {
+ uno::Reference< awt::XWindow > xWindow( window.m_xUIElement->getRealInterface(), uno::UNO_QUERY );
+ uno::Reference< awt::XDockableWindow > xDockWindow( xWindow, uno::UNO_QUERY );
+ if ( xWindow.is() && xDockWindow.is() )
+ {
+ SolarMutexGuard aGuard;
+
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow );
+ if ( pWindow && !xDockWindow->isFloating() && window.m_bVisible && !window.m_bMasterHide )
+ {
+ awt::Rectangle aPosSize = xWindow->getPosSize();
+ if ( window.m_aDockedData.m_nDockedArea != nCurrDockingArea )
+ {
+ nCurrDockingArea = window.m_aDockedData.m_nDockedArea;
+ nCurrRowColumn = 0;
+ nCurrPos = 0;
+ aRowColumnSizes[static_cast<int>(nCurrDockingArea)].clear();
+ aRowColumnSizes[static_cast<int>(nCurrDockingArea)].push_back( 0 );
+ }
+
+ if ( window.m_aDockedData.m_nDockedArea == nCurrDockingArea )
+ {
+ if ( isHorizontalDockingArea( window.m_aDockedData.m_nDockedArea ))
+ {
+ if ( window.m_aDockedData.m_aPos.Y > nCurrPos )
+ {
+ ++nCurrRowColumn;
+ nCurrPos = window.m_aDockedData.m_aPos.Y;
+ aRowColumnSizes[static_cast<int>(nCurrDockingArea)].push_back( 0 );
+ }
+
+ if ( aPosSize.Height > aRowColumnSizes[static_cast<int>(nCurrDockingArea)][nCurrRowColumn] )
+ aRowColumnSizes[static_cast<int>(nCurrDockingArea)][nCurrRowColumn] = aPosSize.Height;
+ }
+ else
+ {
+ if ( window.m_aDockedData.m_aPos.X > nCurrPos )
+ {
+ ++nCurrRowColumn;
+ nCurrPos = window.m_aDockedData.m_aPos.X;
+ aRowColumnSizes[static_cast<int>(nCurrDockingArea)].push_back( 0 );
+ }
+
+ if ( aPosSize.Width > aRowColumnSizes[static_cast<int>(nCurrDockingArea)][nCurrRowColumn] )
+ aRowColumnSizes[static_cast<int>(nCurrDockingArea)][nCurrRowColumn] = aPosSize.Width;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Sum up max heights from every row/column
+ if ( !aWindowVector.empty() )
+ {
+ for ( sal_Int32 i = 0; i <= sal_Int32(ui::DockingArea_DOCKINGAREA_RIGHT); i++ )
+ {
+ sal_Int32 nSize( 0 );
+ const sal_uInt32 nCount = aRowColumnSizes[i].size();
+ for ( sal_uInt32 j = 0; j < nCount; j++ )
+ nSize += aRowColumnSizes[i][j];
+
+ if ( i == sal_Int32(ui::DockingArea_DOCKINGAREA_TOP) )
+ aBorderSpace.SetTop( nSize );
+ else if ( i == sal_Int32(ui::DockingArea_DOCKINGAREA_BOTTOM) )
+ aBorderSpace.SetBottom( nSize );
+ else if ( i == sal_Int32(ui::DockingArea_DOCKINGAREA_LEFT) )
+ aBorderSpace.SetLeft( nSize );
+ else
+ aBorderSpace.SetRight( nSize );
+ }
+ }
+
+ return aBorderSpace;
+}
+
+void ToolbarLayoutManager::reset()
+{
+ {
+ SolarMutexGuard aWriteLock;
+ m_xModuleCfgMgr.clear();
+ m_xDocCfgMgr.clear();
+ m_ePreviewDetection = PREVIEWFRAME_UNKNOWN;
+ m_bComponentAttached = false;
+ }
+
+ destroyToolbars();
+ resetDockingArea();
+}
+
+void ToolbarLayoutManager::attach(
+ const uno::Reference< frame::XFrame >& xFrame,
+ const uno::Reference< ui::XUIConfigurationManager >& xModuleCfgMgr,
+ const uno::Reference< ui::XUIConfigurationManager >& xDocCfgMgr,
+ const uno::Reference< container::XNameAccess >& xPersistentWindowState )
+{
+ // reset toolbar manager if we lose our current frame
+ if ( m_xFrame.is() && m_xFrame != xFrame )
+ reset();
+
+ SolarMutexGuard g;
+ m_xFrame = xFrame;
+ m_xModuleCfgMgr = xModuleCfgMgr;
+ m_xDocCfgMgr = xDocCfgMgr;
+ m_xPersistentWindowState = xPersistentWindowState;
+ m_bComponentAttached = true;
+}
+
+bool ToolbarLayoutManager::isPreviewFrame()
+{
+ SolarMutexGuard g;
+ if (m_ePreviewDetection == PREVIEWFRAME_UNKNOWN)
+ {
+ uno::Reference< frame::XFrame > xFrame( m_xFrame );
+
+ uno::Reference< frame::XModel > xModel( impl_getModelFromFrame( xFrame ));
+
+ m_ePreviewDetection = (implts_isPreviewModel( xModel ) ? PREVIEWFRAME_YES : PREVIEWFRAME_NO);
+ }
+ return m_ePreviewDetection == PREVIEWFRAME_YES;
+}
+
+void ToolbarLayoutManager::createStaticToolbars()
+{
+ resetDockingArea();
+ implts_createCustomToolBars();
+ implts_createAddonsToolBars();
+ implts_createNonContextSensitiveToolBars();
+ implts_sortUIElements();
+}
+
+bool ToolbarLayoutManager::requestToolbar( const OUString& rResourceURL )
+{
+ if (isPreviewFrame())
+ return false; // no toolbars for preview frame!
+
+ bool bNotify( false );
+ bool bMustCallCreate( false );
+ uno::Reference< ui::XUIElement > xUIElement;
+
+ UIElement aRequestedToolbar = impl_findToolbar( rResourceURL );
+ if ( aRequestedToolbar.m_aName != rResourceURL )
+ {
+ bMustCallCreate = true;
+ aRequestedToolbar.m_aName = rResourceURL;
+ aRequestedToolbar.m_aType = UIRESOURCETYPE_TOOLBAR;
+ aRequestedToolbar.m_xUIElement = xUIElement;
+ implts_readWindowStateData( rResourceURL, aRequestedToolbar );
+ }
+
+ xUIElement = aRequestedToolbar.m_xUIElement;
+ if ( !xUIElement.is() )
+ bMustCallCreate = true;
+
+ bool bCreateOrShowToolbar( aRequestedToolbar.m_bVisible && !aRequestedToolbar.m_bMasterHide );
+
+ if ( bCreateOrShowToolbar )
+ bNotify = bMustCallCreate ? createToolbar( rResourceURL ) : showToolbar( rResourceURL );
+
+ return bNotify;
+}
+
+bool ToolbarLayoutManager::createToolbar( const OUString& rResourceURL )
+{
+ bool bNotify( false );
+
+ uno::Reference<frame::XFrame> xFrame;
+ uno::Reference<awt::XWindow2> xContainerWindow;
+ {
+ SolarMutexGuard aReadLock;
+ xFrame.set(m_xFrame);
+ xContainerWindow.set(m_xContainerWindow);
+ }
+
+ if ( !xFrame.is() || !xContainerWindow.is() )
+ return false;
+
+ UIElement aToolbarElement = implts_findToolbar( rResourceURL );
+ if ( !aToolbarElement.m_xUIElement.is() )
+ {
+ uno::Reference< ui::XUIElement > xUIElement;
+
+ uno::Sequence< beans::PropertyValue > aPropSeq{
+ comphelper::makePropertyValue("Frame", xFrame),
+ comphelper::makePropertyValue("Persistent", true)
+ };
+ uno::Reference<ui::XUIElementFactory> xUIElementFactory;
+ {
+ SolarMutexGuard aReadLock;
+ xUIElementFactory.set(m_xUIElementFactoryManager);
+ }
+
+ implts_setToolbarCreation();
+ try
+ {
+ if ( xUIElementFactory.is() )
+ xUIElement = xUIElementFactory->createUIElement( rResourceURL, aPropSeq );
+ }
+ catch (const container::NoSuchElementException&)
+ {
+ }
+ catch (const lang::IllegalArgumentException&)
+ {
+ }
+ implts_setToolbarCreation( false );
+
+ if ( xUIElement.is() )
+ {
+ uno::Reference< awt::XWindow > xWindow( xUIElement->getRealInterface(), uno::UNO_QUERY );
+ uno::Reference< awt::XDockableWindow > xDockWindow( xWindow, uno::UNO_QUERY );
+ if ( xDockWindow.is() && xWindow.is() )
+ {
+ try
+ {
+ xDockWindow->addDockableWindowListener( uno::Reference< awt::XDockableWindowListener >(this) );
+ xWindow->addWindowListener( uno::Reference< awt::XWindowListener >(this) );
+ xDockWindow->enableDocking( true );
+ }
+ catch (const uno::Exception&)
+ {
+ }
+ }
+
+ bool bVisible = false;
+ bool bFloating = false;
+
+ /* SAFE AREA ----------------------------------------------------------------------------------------------- */
+ {
+ SolarMutexClearableGuard aWriteLock;
+
+ UIElement& rElement = impl_findToolbar(rResourceURL);
+ if (rElement.m_xUIElement.is())
+ {
+ // somebody else must have created it while we released
+ // the SolarMutex - just dispose our new instance and
+ // do nothing. (We have to dispose either the new or the
+ // existing m_xUIElement.)
+ aWriteLock.clear();
+ uno::Reference<lang::XComponent> const xC(xUIElement, uno::UNO_QUERY);
+ xC->dispose();
+ return false;
+ }
+ if (!rElement.m_aName.isEmpty())
+ {
+ // Reuse a local entry so we are able to use the latest
+ // UI changes for this document.
+ implts_setElementData(rElement, xDockWindow);
+ rElement.m_xUIElement = xUIElement;
+ bVisible = rElement.m_bVisible;
+ bFloating = rElement.m_bFloating;
+ }
+ else
+ {
+ // Create new UI element and try to read its state data
+ UIElement aNewToolbar(rResourceURL, UIRESOURCETYPE_TOOLBAR, xUIElement);
+ implts_readWindowStateData(rResourceURL, aNewToolbar);
+ implts_setElementData(aNewToolbar, xDockWindow);
+ implts_insertToolbar(aNewToolbar);
+ bVisible = aNewToolbar.m_bVisible;
+ bFloating = rElement.m_bFloating;
+ }
+ }
+ /* SAFE AREA ----------------------------------------------------------------------------------------------- */
+
+ // set toolbar menu style according to customize command state
+ SvtCommandOptions aCmdOptions;
+
+ SolarMutexGuard aGuard;
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow );
+ if ( pWindow && pWindow->GetType() == WindowType::TOOLBOX )
+ {
+ ToolBox* pToolbar = static_cast<ToolBox *>(pWindow.get());
+ ToolBoxMenuType nMenuType = pToolbar->GetMenuType();
+ if ( aCmdOptions.Lookup( SvtCommandOptions::CMDOPTION_DISABLED, "ConfigureDialog" ))
+ pToolbar->SetMenuType( nMenuType & ~ToolBoxMenuType::Customize );
+ else
+ pToolbar->SetMenuType( nMenuType | ToolBoxMenuType::Customize );
+ }
+ bNotify = true;
+
+ implts_sortUIElements();
+
+ if ( bVisible && !bFloating )
+ implts_setLayoutDirty();
+ }
+ }
+
+ return bNotify;
+}
+
+bool ToolbarLayoutManager::destroyToolbar( std::u16string_view rResourceURL )
+{
+ uno::Reference< lang::XComponent > xComponent;
+
+ bool bNotify( false );
+ bool bMustBeSorted( false );
+ bool bMustLayouted( false );
+ bool bMustBeDestroyed( !o3tl::starts_with(rResourceURL, u"private:resource/toolbar/addon_") );
+
+ {
+ SolarMutexGuard aWriteLock;
+ for (auto & elem : m_aUIElements)
+ {
+ if (elem.m_aName == rResourceURL)
+ {
+ xComponent.set(elem.m_xUIElement, uno::UNO_QUERY);
+ if (bMustBeDestroyed)
+ elem.m_xUIElement.clear();
+ else
+ elem.m_bVisible = false;
+ break;
+ }
+ }
+ }
+
+ uno::Reference< ui::XUIElement > xUIElement( xComponent, uno::UNO_QUERY );
+ if ( xUIElement.is() )
+ {
+ uno::Reference< awt::XWindow > xWindow( xUIElement->getRealInterface(), uno::UNO_QUERY );
+ uno::Reference< awt::XDockableWindow > xDockWindow( xWindow, uno::UNO_QUERY );
+
+ if ( bMustBeDestroyed )
+ {
+ try
+ {
+ if ( xWindow.is() )
+ xWindow->removeWindowListener( uno::Reference< awt::XWindowListener >(this) );
+ }
+ catch (const uno::Exception&)
+ {
+ }
+
+ try
+ {
+ if ( xDockWindow.is() )
+ xDockWindow->removeDockableWindowListener( uno::Reference< awt::XDockableWindowListener >(this) );
+ }
+ catch (const uno::Exception&)
+ {
+ }
+ }
+ else
+ {
+ if ( xWindow.is() )
+ xWindow->setVisible( false );
+ bNotify = true;
+ }
+
+ if ( !xDockWindow->isFloating() )
+ bMustLayouted = true;
+ bMustBeSorted = true;
+ }
+
+ if ( bMustBeDestroyed )
+ {
+ if ( xComponent.is() )
+ xComponent->dispose();
+ bNotify = true;
+ }
+
+ if ( bMustLayouted )
+ implts_setLayoutDirty();
+
+ if ( bMustBeSorted )
+ implts_sortUIElements();
+
+ return bNotify;
+}
+
+void ToolbarLayoutManager::destroyToolbars()
+{
+ UIElementVector aUIElementVector;
+ implts_getUIElementVectorCopy( aUIElementVector );
+
+ {
+ SolarMutexGuard aWriteLock;
+ m_aUIElements.clear();
+ m_bLayoutDirty = true;
+ }
+
+ for (auto const& elem : aUIElementVector)
+ {
+ uno::Reference< lang::XComponent > xComponent( elem.m_xUIElement, uno::UNO_QUERY );
+ if ( xComponent.is() )
+ xComponent->dispose();
+ }
+}
+
+bool ToolbarLayoutManager::showToolbar( std::u16string_view rResourceURL )
+{
+ UIElement aUIElement = implts_findToolbar( rResourceURL );
+
+ SolarMutexGuard aGuard;
+ vcl::Window* pWindow = getWindowFromXUIElement( aUIElement.m_xUIElement );
+
+ // Addons appear to need to be populated at start, but we don't
+ // want to populate them with (scaled) images until later.
+ AddonsToolBarWrapper *pAddOns;
+ pAddOns = dynamic_cast<AddonsToolBarWrapper *>( aUIElement.m_xUIElement.get());
+ if (pAddOns)
+ pAddOns->populateImages();
+
+ if ( pWindow )
+ {
+ if ( !aUIElement.m_bFloating )
+ implts_setLayoutDirty();
+ else
+ pWindow->Show( true, ShowFlags::NoFocusChange | ShowFlags::NoActivate );
+
+ aUIElement.m_bVisible = true;
+ implts_writeWindowStateData( aUIElement );
+ implts_setToolbar( aUIElement );
+ implts_sortUIElements();
+ return true;
+ }
+
+ return false;
+}
+
+bool ToolbarLayoutManager::hideToolbar( std::u16string_view rResourceURL )
+{
+ UIElement aUIElement = implts_findToolbar( rResourceURL );
+
+ SolarMutexGuard aGuard;
+ vcl::Window* pWindow = getWindowFromXUIElement( aUIElement.m_xUIElement );
+ if ( pWindow )
+ {
+ pWindow->Show( false );
+ if ( !aUIElement.m_bFloating )
+ implts_setLayoutDirty();
+
+ aUIElement.m_bVisible = false;
+ implts_writeWindowStateData( aUIElement );
+ implts_setToolbar( aUIElement );
+ return true;
+ }
+
+ return false;
+}
+
+void ToolbarLayoutManager::refreshToolbarsVisibility( bool bAutomaticToolbars )
+{
+ UIElementVector aUIElementVector;
+
+ if ( !bAutomaticToolbars )
+ return;
+
+ implts_getUIElementVectorCopy( aUIElementVector );
+
+ UIElement aUIElement;
+ SolarMutexGuard aGuard;
+ for (auto const& elem : aUIElementVector)
+ {
+ if ( implts_readWindowStateData( elem.m_aName, aUIElement ) &&
+ ( elem.m_bVisible != aUIElement.m_bVisible ) && !elem.m_bMasterHide )
+ {
+ SolarMutexGuard g;
+ UIElement& rUIElement = impl_findToolbar( elem.m_aName );
+ if ( rUIElement.m_aName == elem.m_aName )
+ {
+ rUIElement.m_bVisible = aUIElement.m_bVisible;
+ implts_setLayoutDirty();
+ }
+ }
+ }
+}
+
+void ToolbarLayoutManager::setFloatingToolbarsVisibility( bool bVisible )
+{
+ UIElementVector aUIElementVector;
+ implts_getUIElementVectorCopy( aUIElementVector );
+
+ SolarMutexGuard aGuard;
+ for (auto const& elem : aUIElementVector)
+ {
+ vcl::Window* pWindow = getWindowFromXUIElement( elem.m_xUIElement );
+ if ( pWindow && elem.m_bFloating )
+ {
+ if ( bVisible )
+ {
+ if ( elem.m_bVisible && !elem.m_bMasterHide )
+ pWindow->Show( true, ShowFlags::NoFocusChange | ShowFlags::NoActivate );
+ }
+ else
+ pWindow->Show( false );
+ }
+ }
+}
+
+void ToolbarLayoutManager::setVisible( bool bVisible )
+{
+ UIElementVector aUIElementVector;
+ implts_getUIElementVectorCopy( aUIElementVector );
+
+ SolarMutexGuard aGuard;
+ for (auto & elem : aUIElementVector)
+ {
+ if (!elem.m_bFloating)
+ {
+ elem.m_bMasterHide = !bVisible;
+ implts_setToolbar(elem);
+ implts_setLayoutDirty();
+ }
+
+ vcl::Window* pWindow = getWindowFromXUIElement( elem.m_xUIElement );
+ if ( pWindow )
+ {
+ bool bSetVisible( elem.m_bVisible && bVisible );
+ if ( !bSetVisible )
+ pWindow->Hide();
+ else
+ {
+ if ( elem.m_bFloating )
+ pWindow->Show(true, ShowFlags::NoFocusChange | ShowFlags::NoActivate );
+ }
+ }
+ }
+
+ if ( !bVisible )
+ resetDockingArea();
+}
+
+bool ToolbarLayoutManager::dockToolbar( std::u16string_view rResourceURL, ui::DockingArea eDockingArea, const awt::Point& aPos )
+{
+ UIElement aUIElement = implts_findToolbar( rResourceURL );
+
+ if ( !aUIElement.m_xUIElement.is() )
+ return false;
+
+ try
+ {
+ uno::Reference< awt::XWindow > xWindow( aUIElement.m_xUIElement->getRealInterface(), uno::UNO_QUERY );
+ uno::Reference< awt::XDockableWindow > xDockWindow( xWindow, uno::UNO_QUERY );
+ if ( xDockWindow.is() )
+ {
+ if ( eDockingArea != ui::DockingArea_DOCKINGAREA_DEFAULT )
+ aUIElement.m_aDockedData.m_nDockedArea = eDockingArea;
+
+ if ( !isDefaultPos( aPos ))
+ aUIElement.m_aDockedData.m_aPos = aPos;
+
+ if ( !xDockWindow->isFloating() )
+ {
+ vcl::Window* pWindow( nullptr );
+ ToolBox* pToolBox( nullptr );
+
+ {
+ SolarMutexGuard aGuard;
+ pWindow = VCLUnoHelper::GetWindow( xWindow );
+ if ( pWindow && pWindow->GetType() == WindowType::TOOLBOX )
+ {
+ pToolBox = static_cast<ToolBox *>(pWindow);
+
+ // We have to set the alignment of the toolbox. It's possible that the toolbox is moved from a
+ // horizontal to a vertical docking area!
+ pToolBox->SetAlign( ImplConvertAlignment( aUIElement.m_aDockedData.m_nDockedArea ));
+ }
+ }
+
+ if ( hasDefaultPosValue( aUIElement.m_aDockedData.m_aPos ))
+ {
+ // Docking on its default position without a preset position -
+ // we have to find a good place for it.
+ ::Size aSize;
+
+ SolarMutexGuard aGuard;
+ {
+ if (pToolBox)
+ aSize = pToolBox->CalcWindowSizePixel( 1, ImplConvertAlignment( aUIElement.m_aDockedData.m_nDockedArea ) );
+ else if (pWindow)
+ aSize = pWindow->GetSizePixel();
+ }
+
+ ::Point aPixelPos;
+ awt::Point aDockPos;
+ implts_findNextDockingPos(aUIElement.m_aDockedData.m_nDockedArea, aSize, aDockPos, aPixelPos );
+ aUIElement.m_aDockedData.m_aPos = aDockPos;
+ }
+ }
+
+ implts_setToolbar( aUIElement );
+
+ if ( xDockWindow->isFloating() )
+ {
+ // ATTENTION: This will call toggleFloatingMode() via notifications which
+ // sets the floating member of the UIElement correctly!
+ xDockWindow->setFloatingMode( false );
+ }
+ else
+ {
+ implts_writeWindowStateData( aUIElement );
+ implts_sortUIElements();
+
+ if ( aUIElement.m_bVisible )
+ implts_setLayoutDirty();
+ }
+ return true;
+ }
+ }
+ catch (const lang::DisposedException&)
+ {
+ }
+
+ return false;
+}
+
+bool ToolbarLayoutManager::dockAllToolbars()
+{
+ std::vector< OUString > aToolBarNameVector;
+
+ {
+ SolarMutexGuard aReadLock;
+ for (auto const& elem : m_aUIElements)
+ {
+ if (elem.m_aType == "toolbar" && elem.m_xUIElement.is() && elem.m_bFloating
+ && elem.m_bVisible)
+ aToolBarNameVector.push_back(elem.m_aName);
+ }
+ }
+
+ bool bResult(true);
+ const sal_uInt32 nCount = aToolBarNameVector.size();
+ for ( sal_uInt32 i = 0; i < nCount; ++i )
+ {
+ awt::Point aPoint;
+ aPoint.X = aPoint.Y = SAL_MAX_INT32;
+ bResult &= dockToolbar( aToolBarNameVector[i], ui::DockingArea_DOCKINGAREA_DEFAULT, aPoint );
+ }
+
+ return bResult;
+}
+
+void ToolbarLayoutManager::childWindowEvent( VclSimpleEvent const * pEvent )
+{
+ // To enable toolbar controllers to change their image when a sub-toolbar function
+ // is activated, we need this mechanism. We have NO connection between these toolbars
+ // anymore!
+ auto pWindowEvent = dynamic_cast< const VclWindowEvent* >(pEvent);
+ if (!pWindowEvent)
+ return;
+
+ if ( pEvent->GetId() == VclEventId::ToolboxSelect )
+ {
+ OUString aToolbarName;
+ OUString aCommand;
+ ToolBox* pToolBox = getToolboxPtr( pWindowEvent->GetWindow() );
+
+ if ( pToolBox )
+ {
+ aToolbarName = retrieveToolbarNameFromHelpURL( pToolBox );
+ ToolBoxItemId nId = pToolBox->GetCurItemId();
+ if ( nId > ToolBoxItemId(0) )
+ aCommand = pToolBox->GetItemCommand( nId );
+ }
+
+ if ( !aToolbarName.isEmpty() && !aCommand.isEmpty() )
+ {
+ SolarMutexClearableGuard aReadLock;
+ ::std::vector< uno::Reference< ui::XUIFunctionListener > > aListenerArray;
+
+ for (auto const& elem : m_aUIElements)
+ {
+ if ( elem.m_xUIElement.is() )
+ {
+ uno::Reference< ui::XUIFunctionListener > xListener( elem.m_xUIElement, uno::UNO_QUERY );
+ if ( xListener.is() )
+ aListenerArray.push_back( xListener );
+ }
+ }
+ aReadLock.clear();
+
+ const sal_uInt32 nCount = aListenerArray.size();
+ for ( sal_uInt32 i = 0; i < nCount; ++i )
+ {
+ try
+ {
+ aListenerArray[i]->functionExecute( aToolbarName, aCommand );
+ }
+ catch (const uno::RuntimeException&)
+ {
+ throw;
+ }
+ catch (const uno::Exception&)
+ {
+ }
+ }
+ }
+ }
+ else if ( pEvent->GetId() == VclEventId::ToolboxFormatChanged )
+ {
+ if ( !implts_isToolbarCreationActive() )
+ {
+ ToolBox* pToolBox = getToolboxPtr( pWindowEvent->GetWindow() );
+ if ( pToolBox )
+ {
+ OUString aToolbarName = retrieveToolbarNameFromHelpURL( pToolBox );
+ if ( !aToolbarName.isEmpty() )
+ {
+ OUString aToolbarUrl = "private:resource/toolbar/" + aToolbarName;
+
+ UIElement aToolbar = implts_findToolbar( aToolbarUrl );
+ if ( aToolbar.m_xUIElement.is() && !aToolbar.m_bFloating )
+ {
+ implts_setLayoutDirty();
+ m_pParentLayouter->requestLayout();
+ }
+ }
+ }
+ }
+ }
+}
+
+void ToolbarLayoutManager::resetDockingArea()
+{
+ SolarMutexClearableGuard aReadLock;
+ uno::Reference< awt::XWindow > xTopDockingWindow( m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_TOP)] );
+ uno::Reference< awt::XWindow > xLeftDockingWindow( m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_LEFT)] );
+ uno::Reference< awt::XWindow > xRightDockingWindow( m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_RIGHT)] );
+ uno::Reference< awt::XWindow > xBottomDockingWindow( m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_BOTTOM)] );
+ aReadLock.clear();
+
+ if ( xTopDockingWindow.is() )
+ xTopDockingWindow->setPosSize( 0, 0, 0, 0, awt::PosSize::POSSIZE );
+ if ( xLeftDockingWindow.is() )
+ xLeftDockingWindow->setPosSize( 0, 0, 0, 0, awt::PosSize::POSSIZE );
+ if ( xRightDockingWindow.is() )
+ xRightDockingWindow->setPosSize( 0, 0, 0, 0, awt::PosSize::POSSIZE );
+ if ( xBottomDockingWindow.is() )
+ xBottomDockingWindow->setPosSize( 0, 0, 0, 0, awt::PosSize::POSSIZE );
+}
+
+void ToolbarLayoutManager::setParentWindow(
+ const uno::Reference< awt::XWindowPeer >& xParentWindow )
+{
+ static const char DOCKINGAREASTRING[] = "dockingarea";
+
+ uno::Reference< awt::XWindow > xTopDockWindow( createToolkitWindow( m_xContext, xParentWindow, DOCKINGAREASTRING ), uno::UNO_QUERY );
+ uno::Reference< awt::XWindow > xLeftDockWindow( createToolkitWindow( m_xContext, xParentWindow, DOCKINGAREASTRING ), uno::UNO_QUERY );
+ uno::Reference< awt::XWindow > xRightDockWindow( createToolkitWindow( m_xContext, xParentWindow, DOCKINGAREASTRING ), uno::UNO_QUERY );
+ uno::Reference< awt::XWindow > xBottomDockWindow( createToolkitWindow( m_xContext, xParentWindow, DOCKINGAREASTRING ), uno::UNO_QUERY );
+
+ {
+ SolarMutexGuard aWriteLock;
+ m_xContainerWindow.set(xParentWindow, uno::UNO_QUERY);
+ m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_TOP)] = xTopDockWindow;
+ m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_LEFT)] = xLeftDockWindow;
+ m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_RIGHT)] = xRightDockWindow;
+ m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_BOTTOM)] = xBottomDockWindow;
+ }
+
+ if ( xParentWindow.is() )
+ {
+ SolarMutexGuard aGuard;
+ VclPtr< ::DockingAreaWindow > pWindow = dynamic_cast< ::DockingAreaWindow* >(VCLUnoHelper::GetWindow( xTopDockWindow ) );
+ if( pWindow )
+ pWindow->SetAlign( WindowAlign::Top );
+ pWindow = dynamic_cast< ::DockingAreaWindow* >(VCLUnoHelper::GetWindow( xBottomDockWindow ) );
+ if( pWindow )
+ pWindow->SetAlign( WindowAlign::Bottom );
+ pWindow = dynamic_cast< ::DockingAreaWindow* >(VCLUnoHelper::GetWindow( xLeftDockWindow ) );
+ if( pWindow )
+ pWindow->SetAlign( WindowAlign::Left );
+ pWindow = dynamic_cast< ::DockingAreaWindow* >(VCLUnoHelper::GetWindow( xRightDockWindow ) );
+ if( pWindow )
+ pWindow->SetAlign( WindowAlign::Right );
+ implts_reparentToolbars();
+ }
+ else
+ {
+ destroyToolbars();
+ resetDockingArea();
+ }
+}
+
+void ToolbarLayoutManager::setDockingAreaOffsets( const ::tools::Rectangle& rOffsets )
+{
+ SolarMutexGuard g;
+ m_aDockingAreaOffsets = rOffsets;
+ m_bLayoutDirty = true;
+}
+
+OUString ToolbarLayoutManager::implts_generateGenericAddonToolbarTitle( sal_Int32 nNumber ) const
+{
+ OUString aAddonGenericTitle(FwkResId(STR_TOOLBAR_TITLE_ADDON));
+ const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
+
+ OUString aNumStr = rI18nHelper.GetNum( nNumber, 0, false, false );
+ aAddonGenericTitle = aAddonGenericTitle.replaceFirst( "%num%", aNumStr );
+
+ return aAddonGenericTitle;
+}
+
+void ToolbarLayoutManager::implts_createAddonsToolBars()
+{
+ SolarMutexClearableGuard aWriteLock;
+ if ( !m_pAddonOptions )
+ m_pAddonOptions.reset( new AddonsOptions );
+
+ uno::Reference< ui::XUIElementFactory > xUIElementFactory( m_xUIElementFactoryManager );
+ uno::Reference< frame::XFrame > xFrame( m_xFrame );
+ aWriteLock.clear();
+
+ if (isPreviewFrame())
+ return; // no addon toolbars for preview frame!
+
+ uno::Sequence< uno::Sequence< beans::PropertyValue > > aAddonToolBarData;
+ uno::Reference< ui::XUIElement > xUIElement;
+
+ sal_uInt32 nCount = m_pAddonOptions->GetAddonsToolBarCount();
+
+ uno::Sequence< beans::PropertyValue > aPropSeq( 2 );
+ auto pPropSeq = aPropSeq.getArray();
+ pPropSeq[0].Name = "Frame";
+ pPropSeq[0].Value <<= xFrame;
+ pPropSeq[1].Name = "ConfigurationData";
+ for ( sal_uInt32 i = 0; i < nCount; i++ )
+ {
+ OUString aAddonToolBarName( "private:resource/toolbar/addon_" +
+ m_pAddonOptions->GetAddonsToolbarResourceName(i) );
+ aAddonToolBarData = m_pAddonOptions->GetAddonsToolBarPart( i );
+ pPropSeq[1].Value <<= aAddonToolBarData;
+
+ UIElement aElement = implts_findToolbar( aAddonToolBarName );
+
+ // #i79828
+ // It's now possible that we are called more than once. Be sure to not create
+ // add-on toolbars more than once!
+ if ( aElement.m_xUIElement.is() )
+ continue;
+
+ try
+ {
+ xUIElement = xUIElementFactory->createUIElement( aAddonToolBarName, aPropSeq );
+ if ( xUIElement.is() )
+ {
+ uno::Reference< awt::XDockableWindow > xDockWindow( xUIElement->getRealInterface(), uno::UNO_QUERY );
+ if ( xDockWindow.is() )
+ {
+ try
+ {
+ xDockWindow->addDockableWindowListener( uno::Reference< awt::XDockableWindowListener >(this) );
+ xDockWindow->enableDocking( true );
+ uno::Reference< awt::XWindow > xWindow( xDockWindow, uno::UNO_QUERY );
+ if ( xWindow.is() )
+ xWindow->addWindowListener( uno::Reference< awt::XWindowListener >(this) );
+ }
+ catch (const uno::Exception&)
+ {
+ }
+ }
+
+ OUString aGenericAddonTitle = implts_generateGenericAddonToolbarTitle( i+1 );
+
+ if ( !aElement.m_aName.isEmpty() )
+ {
+ // Reuse a local entry so we are able to use the latest
+ // UI changes for this document.
+ implts_setElementData( aElement, xDockWindow );
+ aElement.m_xUIElement = xUIElement;
+ if ( aElement.m_aUIName.isEmpty() )
+ {
+ aElement.m_aUIName = aGenericAddonTitle;
+ implts_writeWindowStateData( aElement );
+ }
+ }
+ else
+ {
+ // Create new UI element and try to read its state data
+ UIElement aNewToolbar( aAddonToolBarName, "toolbar", xUIElement );
+ aNewToolbar.m_bFloating = true;
+ implts_readWindowStateData( aAddonToolBarName, aNewToolbar );
+ implts_setElementData( aNewToolbar, xDockWindow );
+ if ( aNewToolbar.m_aUIName.isEmpty() )
+ {
+ aNewToolbar.m_aUIName = aGenericAddonTitle;
+ implts_writeWindowStateData( aNewToolbar );
+ }
+ implts_insertToolbar( aNewToolbar );
+ }
+
+ uno::Reference< awt::XWindow > xWindow( xDockWindow, uno::UNO_QUERY );
+ if ( xWindow.is() )
+ {
+ // Set generic title for add-on toolbar
+ SolarMutexGuard aGuard;
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow );
+ if ( pWindow->GetText().isEmpty() )
+ pWindow->SetText( aGenericAddonTitle );
+ if ( pWindow->GetType() == WindowType::TOOLBOX )
+ {
+ ToolBox* pToolbar = static_cast<ToolBox *>(pWindow.get());
+ pToolbar->SetMenuType();
+ }
+ }
+ }
+ }
+ catch (const container::NoSuchElementException&)
+ {
+ }
+ catch (const lang::IllegalArgumentException&)
+ {
+ }
+ }
+}
+
+void ToolbarLayoutManager::implts_createCustomToolBars()
+{
+ SolarMutexClearableGuard aReadLock;
+ if ( !m_bComponentAttached )
+ return;
+
+ uno::Reference< frame::XFrame > xFrame( m_xFrame );
+ uno::Reference< ui::XUIConfigurationManager > xModuleCfgMgr = m_xModuleCfgMgr;
+ uno::Reference< ui::XUIConfigurationManager > xDocCfgMgr = m_xDocCfgMgr;
+ aReadLock.clear();
+
+ if ( !xFrame.is() )
+ return;
+
+ if (isPreviewFrame())
+ return; // no custom toolbars for preview frame!
+
+ uno::Sequence< uno::Sequence< beans::PropertyValue > > aTbxSeq;
+ if ( xDocCfgMgr.is() )
+ {
+ aTbxSeq = xDocCfgMgr->getUIElementsInfo( ui::UIElementType::TOOLBAR );
+ implts_createCustomToolBars( aTbxSeq ); // first create all document based toolbars
+ }
+ if ( xModuleCfgMgr.is() )
+ {
+ aTbxSeq = xModuleCfgMgr->getUIElementsInfo( ui::UIElementType::TOOLBAR );
+ implts_createCustomToolBars( aTbxSeq ); // second create module based toolbars
+ }
+}
+
+void ToolbarLayoutManager::implts_createNonContextSensitiveToolBars()
+{
+ SolarMutexClearableGuard aReadLock;
+
+ if ( !m_xPersistentWindowState.is() || !m_xFrame.is() || !m_bComponentAttached )
+ return;
+
+ uno::Reference< container::XNameAccess > xPersistentWindowState( m_xPersistentWindowState );
+ aReadLock.clear();
+
+ if (isPreviewFrame())
+ return;
+
+ std::vector< OUString > aMakeVisibleToolbars;
+
+ try
+ {
+ const uno::Sequence< OUString > aToolbarNames = xPersistentWindowState->getElementNames();
+
+ if ( aToolbarNames.hasElements() )
+ {
+ OUString aElementType;
+ OUString aElementName;
+
+ aMakeVisibleToolbars.reserve(aToolbarNames.getLength());
+
+ SolarMutexGuard g;
+
+ for ( OUString const & aName : aToolbarNames )
+ {
+ parseResourceURL( aName, aElementType, aElementName );
+
+ // Check that we only create:
+ // - Toolbars (the statusbar is also member of the persistent window state)
+ // - Not custom toolbars, there are created with their own method (implts_createCustomToolbars)
+ if ( aElementType.equalsIgnoreAsciiCase("toolbar") &&
+ aElementName.indexOf( "custom_" ) == -1 )
+ {
+ UIElement aNewToolbar = implts_findToolbar( aName );
+ bool bFound = ( aNewToolbar.m_aName == aName );
+ if ( !bFound )
+ implts_readWindowStateData( aName, aNewToolbar );
+
+ if ( aNewToolbar.m_bVisible && !aNewToolbar.m_bContextSensitive )
+ {
+ if ( !bFound )
+ implts_insertToolbar( aNewToolbar );
+ aMakeVisibleToolbars.push_back( aName );
+ }
+ }
+ }
+ }
+ }
+ catch (const uno::RuntimeException&)
+ {
+ throw;
+ }
+ catch (const uno::Exception&)
+ {
+ }
+
+ for (auto const& rURL : aMakeVisibleToolbars)
+ {
+ requestToolbar(rURL);
+ }
+}
+
+void ToolbarLayoutManager::implts_createCustomToolBars( const uno::Sequence< uno::Sequence< beans::PropertyValue > >& aTbxSeqSeq )
+{
+ for ( const uno::Sequence< beans::PropertyValue >& rTbxSeq : aTbxSeqSeq )
+ {
+ OUString aTbxResName;
+ OUString aTbxTitle;
+ for ( const beans::PropertyValue& rProp : rTbxSeq )
+ {
+ if ( rProp.Name == "ResourceURL" )
+ rProp.Value >>= aTbxResName;
+ else if ( rProp.Name == "UIName" )
+ rProp.Value >>= aTbxTitle;
+ }
+
+ // Only create custom toolbars. Their name have to start with "custom_"!
+ if ( !aTbxResName.isEmpty() && ( aTbxResName.indexOf( "custom_" ) != -1 ) )
+ implts_createCustomToolBar( aTbxResName, aTbxTitle );
+ }
+}
+
+void ToolbarLayoutManager::implts_createCustomToolBar( const OUString& aTbxResName, const OUString& aTitle )
+{
+ if ( aTbxResName.isEmpty() )
+ return;
+
+ if ( !createToolbar( aTbxResName ) )
+ SAL_WARN("fwk.uielement", "ToolbarLayoutManager cannot create custom toolbar");
+
+ uno::Reference< ui::XUIElement > xUIElement = getToolbar( aTbxResName );
+
+ if ( !aTitle.isEmpty() && xUIElement.is() )
+ {
+ SolarMutexGuard aGuard;
+
+ vcl::Window* pWindow = getWindowFromXUIElement( xUIElement );
+ if ( pWindow )
+ pWindow->SetText( aTitle );
+ }
+}
+
+void ToolbarLayoutManager::implts_reparentToolbars()
+{
+ SolarMutexClearableGuard aWriteLock;
+ UIElementVector aUIElementVector = m_aUIElements;
+ VclPtr<vcl::Window> pContainerWindow = VCLUnoHelper::GetWindow( m_xContainerWindow );
+ VclPtr<vcl::Window> pTopDockWindow = VCLUnoHelper::GetWindow( m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_TOP)] );
+ VclPtr<vcl::Window> pBottomDockWindow = VCLUnoHelper::GetWindow( m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_BOTTOM)] );
+ VclPtr<vcl::Window> pLeftDockWindow = VCLUnoHelper::GetWindow( m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_LEFT)] );
+ VclPtr<vcl::Window> pRightDockWindow = VCLUnoHelper::GetWindow( m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_RIGHT)] );
+ aWriteLock.clear();
+
+ SolarMutexGuard aGuard;
+ if ( !pContainerWindow )
+ return;
+
+ for (auto const& elem : aUIElementVector)
+ {
+ uno::Reference< ui::XUIElement > xUIElement( elem.m_xUIElement );
+ if ( xUIElement.is() )
+ {
+ uno::Reference< awt::XWindow > xWindow;
+ try
+ {
+ // We have to retrieve the window reference with try/catch as it is
+ // possible that all elements have been disposed!
+ xWindow.set( xUIElement->getRealInterface(), uno::UNO_QUERY );
+ }
+ catch (const uno::RuntimeException&)
+ {
+ throw;
+ }
+ catch (const uno::Exception&)
+ {
+ }
+
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow );
+ if ( pWindow )
+ {
+ // Reparent our child windows according to their current state.
+ if ( elem.m_bFloating )
+ pWindow->SetParent( pContainerWindow );
+ else
+ {
+ if ( elem.m_aDockedData.m_nDockedArea == ui::DockingArea_DOCKINGAREA_TOP )
+ pWindow->SetParent( pTopDockWindow );
+ else if ( elem.m_aDockedData.m_nDockedArea == ui::DockingArea_DOCKINGAREA_BOTTOM )
+ pWindow->SetParent( pBottomDockWindow );
+ else if ( elem.m_aDockedData.m_nDockedArea == ui::DockingArea_DOCKINGAREA_LEFT )
+ pWindow->SetParent( pLeftDockWindow );
+ else
+ pWindow->SetParent( pRightDockWindow );
+ }
+ }
+ }
+ }
+}
+
+void ToolbarLayoutManager::implts_setToolbarCreation( bool bStart )
+{
+ SolarMutexGuard g;
+ m_bToolbarCreation = bStart;
+}
+
+bool ToolbarLayoutManager::implts_isToolbarCreationActive()
+{
+ SolarMutexGuard g;
+ return m_bToolbarCreation;
+}
+
+void ToolbarLayoutManager::implts_setElementData( UIElement& rElement, const uno::Reference< awt::XDockableWindow >& rDockWindow )
+{
+ SolarMutexClearableGuard aReadLock;
+ bool bShowElement( rElement.m_bVisible && !rElement.m_bMasterHide && implts_isParentWindowVisible() );
+ aReadLock.clear();
+
+ uno::Reference< awt::XWindow2 > xWindow( rDockWindow, uno::UNO_QUERY );
+
+ vcl::Window* pWindow( nullptr );
+ ToolBox* pToolBox( nullptr );
+
+ if ( !(rDockWindow.is() && xWindow.is()) )
+ return;
+
+ {
+ SolarMutexGuard aGuard;
+ pWindow = VCLUnoHelper::GetWindow( xWindow );
+ if ( pWindow )
+ {
+ OUString aText = pWindow->GetText();
+ if ( aText.isEmpty() )
+ pWindow->SetText( rElement.m_aUIName );
+ if ( rElement.m_bNoClose )
+ pWindow->SetStyle( pWindow->GetStyle() & ~WB_CLOSEABLE );
+ if ( pWindow->GetType() == WindowType::TOOLBOX )
+ pToolBox = static_cast<ToolBox *>(pWindow);
+ }
+ if ( pToolBox )
+ {
+ pToolBox->SetButtonType( rElement.m_nStyle );
+ if ( rElement.m_bNoClose )
+ pToolBox->SetFloatStyle( pToolBox->GetFloatStyle() & ~WB_CLOSEABLE );
+ }
+ }
+
+ if ( rElement.m_bFloating )
+ {
+ if ( pWindow )
+ {
+ SolarMutexGuard aGuard;
+ OUString aText = pWindow->GetText();
+ if ( aText.isEmpty() )
+ pWindow->SetText( rElement.m_aUIName );
+ }
+
+ awt::Point aPos(rElement.m_aFloatingData.m_aPos);
+ bool bWriteData( false );
+ bool bUndefPos = hasDefaultPosValue( rElement.m_aFloatingData.m_aPos );
+ bool bSetSize = ( rElement.m_aFloatingData.m_aSize.Width != 0 &&
+ rElement.m_aFloatingData.m_aSize.Height != 0 );
+ rDockWindow->setFloatingMode( true );
+ if ( bUndefPos )
+ {
+ aPos = implts_findNextCascadeFloatingPos();
+ rElement.m_aFloatingData.m_aPos = aPos; // set new cascaded position
+ bWriteData = true;
+ }
+
+ if( bSetSize )
+ xWindow->setOutputSize(rElement.m_aFloatingData.m_aSize);
+ else
+ {
+ if( pToolBox )
+ {
+ // set an optimal initial floating size
+ SolarMutexGuard aGuard;
+ ::Size aSize( pToolBox->CalcFloatingWindowSizePixel() );
+ pToolBox->SetOutputSizePixel( aSize );
+ }
+ }
+
+ // #i60882# IMPORTANT: Set position after size as it is
+ // possible that we position some part of the toolbar
+ // outside of the desktop. A default constructed toolbar
+ // always has one line. Now VCL automatically
+ // position the toolbar back into the desktop. Therefore
+ // we resize the toolbar with the new (wrong) position.
+ // To fix this problem we have to set the size BEFORE the
+ // position.
+ xWindow->setPosSize( aPos.X, aPos.Y, 0, 0, awt::PosSize::POS );
+
+ if ( bWriteData )
+ implts_writeWindowStateData( rElement );
+ if ( bShowElement && pWindow )
+ {
+ SolarMutexGuard aGuard;
+ pWindow->Show( true, ShowFlags::NoFocusChange | ShowFlags::NoActivate );
+ }
+ }
+ else
+ {
+ bool bSetSize( false );
+ ::Point aPixelPos;
+ ::Size aSize;
+
+ if ( pToolBox )
+ {
+ SolarMutexGuard aGuard;
+ pToolBox->SetAlign( ImplConvertAlignment(rElement.m_aDockedData.m_nDockedArea ) );
+ pToolBox->SetLineCount( 1 );
+ rDockWindow->setFloatingMode( false );
+ if ( rElement.m_aDockedData.m_bLocked )
+ rDockWindow->lock();
+ aSize = pToolBox->CalcWindowSizePixel();
+ bSetSize = true;
+
+ if ( isDefaultPos( rElement.m_aDockedData.m_aPos ))
+ {
+ awt::Point aDockPos;
+ implts_findNextDockingPos( rElement.m_aDockedData.m_nDockedArea, aSize, aDockPos, aPixelPos );
+ rElement.m_aDockedData.m_aPos = aDockPos;
+ }
+ }
+
+ xWindow->setPosSize( aPixelPos.X(), aPixelPos.Y(), 0, 0, awt::PosSize::POS );
+ if( bSetSize )
+ xWindow->setOutputSize( AWTSize( aSize) );
+
+ if ( pWindow )
+ {
+ SolarMutexGuard aGuard;
+ if ( !bShowElement )
+ pWindow->Hide();
+ }
+ }
+}
+
+void ToolbarLayoutManager::implts_destroyDockingAreaWindows()
+{
+ SolarMutexClearableGuard aWriteLock;
+ uno::Reference< awt::XWindow > xTopDockingWindow( m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_TOP)] );
+ uno::Reference< awt::XWindow > xLeftDockingWindow( m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_LEFT)] );
+ uno::Reference< awt::XWindow > xRightDockingWindow( m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_RIGHT)] );
+ uno::Reference< awt::XWindow > xBottomDockingWindow( m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_BOTTOM)] );
+ m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_TOP)].clear();
+ m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_LEFT)].clear();
+ m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_RIGHT)].clear();
+ m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_BOTTOM)].clear();
+ aWriteLock.clear();
+
+ // destroy windows
+ xTopDockingWindow->dispose();
+ xLeftDockingWindow->dispose();
+ xRightDockingWindow->dispose();
+ xBottomDockingWindow->dispose();
+}
+
+// persistence methods
+
+bool ToolbarLayoutManager::implts_readWindowStateData( const OUString& aName, UIElement& rElementData )
+{
+ return LayoutManager::readWindowStateData( aName, rElementData, m_xPersistentWindowState,
+ m_pGlobalSettings, m_bGlobalSettings, m_xContext );
+}
+
+void ToolbarLayoutManager::implts_writeWindowStateData( const UIElement& rElementData )
+{
+ SolarMutexClearableGuard aWriteLock;
+ uno::Reference< container::XNameAccess > xPersistentWindowState( m_xPersistentWindowState );
+ aWriteLock.clear();
+
+ bool bPersistent( false );
+ uno::Reference< beans::XPropertySet > xPropSet( rElementData.m_xUIElement, uno::UNO_QUERY );
+ if ( xPropSet.is() )
+ {
+ try
+ {
+ // Check persistent flag of the user interface element
+ xPropSet->getPropertyValue("Persistent") >>= bPersistent;
+ }
+ catch (const beans::UnknownPropertyException&)
+ {
+ bPersistent = true; // Non-configurable elements should at least store their dimension/position
+ }
+ catch (const lang::WrappedTargetException&)
+ {
+ }
+ }
+
+ if ( !(bPersistent && xPersistentWindowState.is()) )
+ return;
+
+ try
+ {
+ uno::Sequence<beans::PropertyValue> aWindowState{
+ comphelper::makePropertyValue(WINDOWSTATE_PROPERTY_DOCKED, !rElementData.m_bFloating),
+ comphelper::makePropertyValue(WINDOWSTATE_PROPERTY_VISIBLE, rElementData.m_bVisible),
+ comphelper::makePropertyValue(WINDOWSTATE_PROPERTY_DOCKINGAREA,
+ rElementData.m_aDockedData.m_nDockedArea),
+ comphelper::makePropertyValue(WINDOWSTATE_PROPERTY_DOCKPOS,
+ rElementData.m_aDockedData.m_aPos),
+ comphelper::makePropertyValue(WINDOWSTATE_PROPERTY_POS,
+ rElementData.m_aFloatingData.m_aPos),
+ comphelper::makePropertyValue(WINDOWSTATE_PROPERTY_SIZE,
+ rElementData.m_aFloatingData.m_aSize),
+ comphelper::makePropertyValue(WINDOWSTATE_PROPERTY_UINAME, rElementData.m_aUIName),
+ comphelper::makePropertyValue(WINDOWSTATE_PROPERTY_LOCKED,
+ rElementData.m_aDockedData.m_bLocked),
+ comphelper::makePropertyValue(WINDOWSTATE_PROPERTY_STYLE,
+ static_cast<sal_uInt16>(rElementData.m_nStyle))
+ };
+
+ OUString aName = rElementData.m_aName;
+ if ( xPersistentWindowState->hasByName( aName ))
+ {
+ uno::Reference< container::XNameReplace > xReplace( xPersistentWindowState, uno::UNO_QUERY );
+ xReplace->replaceByName( aName, uno::Any( aWindowState ));
+ }
+ else
+ {
+ uno::Reference< container::XNameContainer > xInsert( xPersistentWindowState, uno::UNO_QUERY );
+ xInsert->insertByName( aName, uno::Any( aWindowState ));
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ }
+}
+
+/******************************************************************************
+ LOOKUP PART FOR TOOLBARS
+******************************************************************************/
+
+UIElement& ToolbarLayoutManager::impl_findToolbar( std::u16string_view aName )
+{
+ static UIElement aEmptyElement;
+
+ SolarMutexGuard g;
+ for (auto & elem : m_aUIElements)
+ {
+ if ( elem.m_aName == aName )
+ return elem;
+ }
+
+ return aEmptyElement;
+}
+
+UIElement ToolbarLayoutManager::implts_findToolbar( std::u16string_view aName )
+{
+ SolarMutexGuard g;
+ return impl_findToolbar( aName );
+}
+
+UIElement ToolbarLayoutManager::implts_findToolbar( const uno::Reference< uno::XInterface >& xToolbar )
+{
+ UIElement aToolbar;
+
+ SolarMutexGuard g;
+ for (auto const& elem : m_aUIElements)
+ {
+ if ( elem.m_xUIElement.is() )
+ {
+ uno::Reference< uno::XInterface > xIfac( elem.m_xUIElement->getRealInterface(), uno::UNO_QUERY );
+ if ( xIfac == xToolbar )
+ {
+ aToolbar = elem;
+ break;
+ }
+ }
+ }
+
+ return aToolbar;
+}
+
+uno::Reference< awt::XWindow > ToolbarLayoutManager::implts_getXWindow( std::u16string_view aName )
+{
+ uno::Reference< awt::XWindow > xWindow;
+
+ SolarMutexGuard g;
+ for (auto const& elem : m_aUIElements)
+ {
+ if ( elem.m_aName == aName && elem.m_xUIElement.is() )
+ {
+ xWindow.set( elem.m_xUIElement->getRealInterface(), uno::UNO_QUERY );
+ break;
+ }
+ }
+
+ return xWindow;
+}
+
+vcl::Window* ToolbarLayoutManager::implts_getWindow( std::u16string_view aName )
+{
+ uno::Reference< awt::XWindow > xWindow = implts_getXWindow( aName );
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow );
+
+ return pWindow;
+}
+
+bool ToolbarLayoutManager::implts_insertToolbar( const UIElement& rUIElement )
+{
+ UIElement aTempData;
+ bool bFound( false );
+ bool bResult( false );
+
+ aTempData = implts_findToolbar( rUIElement.m_aName );
+ if ( aTempData.m_aName == rUIElement.m_aName )
+ bFound = true;
+
+ if ( !bFound )
+ {
+ SolarMutexGuard g;
+ m_aUIElements.push_back( rUIElement );
+ bResult = true;
+ }
+
+ return bResult;
+}
+
+void ToolbarLayoutManager::implts_setToolbar( const UIElement& rUIElement )
+{
+ SolarMutexGuard g;
+ UIElement& rData = impl_findToolbar( rUIElement.m_aName );
+ if ( rData.m_aName == rUIElement.m_aName )
+ rData = rUIElement;
+ else
+ m_aUIElements.push_back( rUIElement );
+}
+
+/******************************************************************************
+ LAYOUT CODE PART FOR TOOLBARS
+******************************************************************************/
+
+awt::Point ToolbarLayoutManager::implts_findNextCascadeFloatingPos()
+{
+ const sal_Int32 nHotZoneX = 50;
+ const sal_Int32 nHotZoneY = 50;
+ const sal_Int32 nCascadeIndentX = 15;
+ const sal_Int32 nCascadeIndentY = 15;
+
+ SolarMutexClearableGuard aReadLock;
+ uno::Reference< awt::XWindow2 > xContainerWindow( m_xContainerWindow );
+ uno::Reference< awt::XWindow > xTopDockingWindow( m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_TOP)] );
+ uno::Reference< awt::XWindow > xLeftDockingWindow( m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_LEFT)] );
+ aReadLock.clear();
+
+ awt::Point aStartPos( nCascadeIndentX, nCascadeIndentY );
+ awt::Point aCurrPos( aStartPos );
+
+ if ( xContainerWindow.is() )
+ {
+ SolarMutexGuard aGuard;
+ VclPtr<vcl::Window> pContainerWindow = VCLUnoHelper::GetWindow( xContainerWindow );
+ if ( pContainerWindow )
+ aStartPos = AWTPoint(pContainerWindow->OutputToScreenPixel(VCLPoint(aStartPos)));
+ }
+
+ // Determine size of top and left docking area
+ awt::Rectangle aTopRect( xTopDockingWindow->getPosSize() );
+ awt::Rectangle aLeftRect( xLeftDockingWindow->getPosSize() );
+
+ aStartPos.X += aLeftRect.Width + nCascadeIndentX;
+ aStartPos.Y += aTopRect.Height + nCascadeIndentY;
+ aCurrPos = aStartPos;
+
+ // Try to find a cascaded position for the new floating window
+ for (auto const& elem : m_aUIElements)
+ {
+ if ( elem.m_xUIElement.is() )
+ {
+ uno::Reference< awt::XDockableWindow > xDockWindow( elem.m_xUIElement->getRealInterface(), uno::UNO_QUERY );
+ uno::Reference< awt::XWindow > xWindow( xDockWindow, uno::UNO_QUERY );
+ if ( xDockWindow.is() && xDockWindow->isFloating() )
+ {
+ SolarMutexGuard aGuard;
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow );
+ if ( pWindow && pWindow->IsVisible() )
+ {
+ awt::Rectangle aFloatRect = xWindow->getPosSize();
+ if ((( aFloatRect.X - nHotZoneX ) <= aCurrPos.X ) &&
+ ( aFloatRect.X >= aCurrPos.X ) &&
+ (( aFloatRect.Y - nHotZoneY ) <= aCurrPos.Y ) &&
+ ( aFloatRect.Y >= aCurrPos.Y ))
+ {
+ aCurrPos.X = aFloatRect.X + nCascadeIndentX;
+ aCurrPos.Y = aFloatRect.Y + nCascadeIndentY;
+ }
+ }
+ }
+ }
+ }
+
+ return aCurrPos;
+}
+
+void ToolbarLayoutManager::implts_sortUIElements()
+{
+ SolarMutexGuard g;
+
+ std::stable_sort( m_aUIElements.begin(), m_aUIElements.end()); // first created element should first
+
+ // We have to reset our temporary flags.
+ for (auto & elem : m_aUIElements)
+ elem.m_bUserActive = false;
+}
+
+void ToolbarLayoutManager::implts_getUIElementVectorCopy( UIElementVector& rCopy )
+{
+ SolarMutexGuard g;
+ rCopy = m_aUIElements;
+}
+
+::Size ToolbarLayoutManager::implts_getTopBottomDockingAreaSizes()
+{
+ ::Size aSize;
+ uno::Reference< awt::XWindow > xTopDockingAreaWindow;
+ uno::Reference< awt::XWindow > xBottomDockingAreaWindow;
+
+ {
+ SolarMutexGuard aReadLock;
+ xTopDockingAreaWindow = m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_TOP)];
+ xBottomDockingAreaWindow = m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_BOTTOM)];
+ }
+
+ if ( xTopDockingAreaWindow.is() )
+ aSize.setWidth( xTopDockingAreaWindow->getPosSize().Height );
+ if ( xBottomDockingAreaWindow.is() )
+ aSize.setHeight( xBottomDockingAreaWindow->getPosSize().Height );
+
+ return aSize;
+}
+
+void ToolbarLayoutManager::implts_getDockingAreaElementInfos( ui::DockingArea eDockingArea, std::vector< SingleRowColumnWindowData >& rRowColumnsWindowData )
+{
+ std::vector< UIElement > aWindowVector;
+
+ if (( eDockingArea < ui::DockingArea_DOCKINGAREA_TOP ) || ( eDockingArea > ui::DockingArea_DOCKINGAREA_RIGHT ))
+ eDockingArea = ui::DockingArea_DOCKINGAREA_TOP;
+
+ uno::Reference< awt::XWindow > xDockAreaWindow;
+
+ /* SAFE AREA ----------------------------------------------------------------------------------------------- */
+ {
+ SolarMutexGuard aReadLock;
+ aWindowVector.reserve(m_aUIElements.size());
+ xDockAreaWindow = m_xDockAreaWindows[static_cast<int>(eDockingArea)];
+ for (auto const& elem : m_aUIElements)
+ {
+ if (elem.m_aDockedData.m_nDockedArea == eDockingArea && elem.m_bVisible)
+ {
+ uno::Reference<ui::XUIElement> xUIElement(elem.m_xUIElement);
+ if (xUIElement.is())
+ {
+ uno::Reference<awt::XWindow> xWindow(xUIElement->getRealInterface(),
+ uno::UNO_QUERY);
+ uno::Reference<awt::XDockableWindow> xDockWindow(xWindow, uno::UNO_QUERY);
+ if (xDockWindow.is())
+ {
+ if (!elem.m_bFloating)
+ {
+ // docked windows
+ aWindowVector.push_back(elem);
+ }
+ else
+ {
+ // floating windows
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(xWindow);
+ DockingManager* pDockMgr = vcl::Window::GetDockingManager();
+ if (pDockMgr != nullptr)
+ {
+ SystemWindow* pFloatingWindow = pDockMgr->GetFloatingWindow(pWindow);
+ if (pFloatingWindow)
+ {
+ // update the position data of the floating window
+ if (pFloatingWindow->UpdatePositionData())
+ {
+ awt::Rectangle aTmpRect = xWindow->getPosSize();
+ UIElement uiElem = elem;
+ uiElem.m_aFloatingData.m_aPos
+ = awt::Point(aTmpRect.X, aTmpRect.Y);
+ implts_setToolbar(uiElem);
+ implts_writeWindowStateData(uiElem);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ /* SAFE AREA ----------------------------------------------------------------------------------------------- */
+
+ rRowColumnsWindowData.clear();
+
+ // Collect data from windows that are on the same row/column
+ sal_Int32 j;
+ sal_Int32 nIndex( 0 );
+ sal_Int32 nLastPos( 0 );
+ sal_Int32 nCurrPos( -1 );
+ sal_Int32 nLastRowColPixelPos( 0 );
+ awt::Rectangle aDockAreaRect;
+
+ if ( xDockAreaWindow.is() )
+ aDockAreaRect = xDockAreaWindow->getPosSize();
+
+ if ( eDockingArea == ui::DockingArea_DOCKINGAREA_TOP )
+ nLastRowColPixelPos = 0;
+ else if ( eDockingArea == ui::DockingArea_DOCKINGAREA_BOTTOM )
+ nLastRowColPixelPos = aDockAreaRect.Height;
+ else if ( eDockingArea == ui::DockingArea_DOCKINGAREA_LEFT )
+ nLastRowColPixelPos = 0;
+ else
+ nLastRowColPixelPos = aDockAreaRect.Width;
+
+ const sal_uInt32 nCount = aWindowVector.size();
+ for ( j = 0; j < sal_Int32( nCount); j++ )
+ {
+ const UIElement& rElement = aWindowVector[j];
+ uno::Reference< awt::XWindow > xWindow;
+ uno::Reference< ui::XUIElement > xUIElement( rElement.m_xUIElement );
+ awt::Rectangle aPosSize;
+
+ if ( !lcl_checkUIElement(xUIElement,aPosSize,xWindow) )
+ continue;
+ if ( isHorizontalDockingArea( eDockingArea ))
+ {
+ if ( nCurrPos == -1 )
+ {
+ nCurrPos = rElement.m_aDockedData.m_aPos.Y;
+ nLastPos = 0;
+
+ SingleRowColumnWindowData aRowColumnWindowData;
+ aRowColumnWindowData.nRowColumn = nCurrPos;
+ rRowColumnsWindowData.push_back( aRowColumnWindowData );
+ }
+
+ sal_Int32 nSpace( 0 );
+ if ( rElement.m_aDockedData.m_aPos.Y != nCurrPos )
+ {
+ if ( eDockingArea == ui::DockingArea_DOCKINGAREA_TOP )
+ nLastRowColPixelPos += rRowColumnsWindowData[nIndex].nStaticSize;
+ else
+ nLastRowColPixelPos -= rRowColumnsWindowData[nIndex].nStaticSize;
+ ++nIndex;
+ nLastPos = 0;
+ nCurrPos = rElement.m_aDockedData.m_aPos.Y;
+ SingleRowColumnWindowData aRowColumnWindowData;
+ aRowColumnWindowData.nRowColumn = nCurrPos;
+ rRowColumnsWindowData.push_back( aRowColumnWindowData );
+ }
+
+ // Calc space before an element and store it
+ nSpace = ( rElement.m_aDockedData.m_aPos.X - nLastPos );
+ if ( rElement.m_aDockedData.m_aPos.X >= nLastPos )
+ {
+ rRowColumnsWindowData[nIndex].nSpace += nSpace;
+ nLastPos = rElement.m_aDockedData.m_aPos.X + aPosSize.Width;
+ }
+ else
+ {
+ nSpace = 0;
+ nLastPos += aPosSize.Width;
+ }
+ rRowColumnsWindowData[nIndex].aRowColumnSpace.push_back( nSpace );
+
+ rRowColumnsWindowData[nIndex].aRowColumnWindows.push_back( xWindow );
+ rRowColumnsWindowData[nIndex].aUIElementNames.push_back( rElement.m_aName );
+ rRowColumnsWindowData[nIndex].aRowColumnWindowSizes.emplace_back(
+ rElement.m_aDockedData.m_aPos.X,
+ rElement.m_aDockedData.m_aPos.Y,
+ aPosSize.Width,
+ aPosSize.Height );
+ if ( rRowColumnsWindowData[nIndex].nStaticSize < aPosSize.Height )
+ rRowColumnsWindowData[nIndex].nStaticSize = aPosSize.Height;
+ if ( eDockingArea == ui::DockingArea_DOCKINGAREA_TOP )
+ rRowColumnsWindowData[nIndex].aRowColumnRect = awt::Rectangle( 0, nLastRowColPixelPos,
+ aDockAreaRect.Width, aPosSize.Height );
+ else
+ rRowColumnsWindowData[nIndex].aRowColumnRect = awt::Rectangle( 0, ( nLastRowColPixelPos - aPosSize.Height ),
+ aDockAreaRect.Width, aPosSize.Height );
+ rRowColumnsWindowData[nIndex].nVarSize += aPosSize.Width + nSpace;
+ }
+ else
+ {
+ if ( nCurrPos == -1 )
+ {
+ nCurrPos = rElement.m_aDockedData.m_aPos.X;
+ nLastPos = 0;
+
+ SingleRowColumnWindowData aRowColumnWindowData;
+ aRowColumnWindowData.nRowColumn = nCurrPos;
+ rRowColumnsWindowData.push_back( aRowColumnWindowData );
+ }
+
+ sal_Int32 nSpace( 0 );
+ if ( rElement.m_aDockedData.m_aPos.X != nCurrPos )
+ {
+ if ( eDockingArea == ui::DockingArea_DOCKINGAREA_LEFT )
+ nLastRowColPixelPos += rRowColumnsWindowData[nIndex].nStaticSize;
+ else
+ nLastRowColPixelPos -= rRowColumnsWindowData[nIndex].nStaticSize;
+ ++nIndex;
+ nLastPos = 0;
+ nCurrPos = rElement.m_aDockedData.m_aPos.X;
+ SingleRowColumnWindowData aRowColumnWindowData;
+ aRowColumnWindowData.nRowColumn = nCurrPos;
+ rRowColumnsWindowData.push_back( aRowColumnWindowData );
+ }
+
+ // Calc space before an element and store it
+ nSpace = ( rElement.m_aDockedData.m_aPos.Y - nLastPos );
+ if ( rElement.m_aDockedData.m_aPos.Y > nLastPos )
+ {
+ rRowColumnsWindowData[nIndex].nSpace += nSpace;
+ nLastPos = rElement.m_aDockedData.m_aPos.Y + aPosSize.Height;
+ }
+ else
+ {
+ nSpace = 0;
+ nLastPos += aPosSize.Height;
+ }
+ rRowColumnsWindowData[nIndex].aRowColumnSpace.push_back( nSpace );
+
+ rRowColumnsWindowData[nIndex].aRowColumnWindows.push_back( xWindow );
+ rRowColumnsWindowData[nIndex].aUIElementNames.push_back( rElement.m_aName );
+ rRowColumnsWindowData[nIndex].aRowColumnWindowSizes.emplace_back(
+ rElement.m_aDockedData.m_aPos.X,
+ rElement.m_aDockedData.m_aPos.Y,
+ aPosSize.Width,
+ aPosSize.Height );
+ if ( rRowColumnsWindowData[nIndex].nStaticSize < aPosSize.Width )
+ rRowColumnsWindowData[nIndex].nStaticSize = aPosSize.Width;
+ if ( eDockingArea == ui::DockingArea_DOCKINGAREA_LEFT )
+ rRowColumnsWindowData[nIndex].aRowColumnRect = awt::Rectangle( nLastRowColPixelPos, 0,
+ aPosSize.Width, aDockAreaRect.Height );
+ else
+ rRowColumnsWindowData[nIndex].aRowColumnRect = awt::Rectangle( ( nLastRowColPixelPos - aPosSize.Width ), 0,
+ aPosSize.Width, aDockAreaRect.Height );
+ rRowColumnsWindowData[nIndex].nVarSize += aPosSize.Height + nSpace;
+ }
+ }
+}
+
+void ToolbarLayoutManager::implts_getDockingAreaElementInfoOnSingleRowCol( ui::DockingArea eDockingArea, sal_Int32 nRowCol, SingleRowColumnWindowData& rRowColumnWindowData )
+{
+ std::vector< UIElement > aWindowVector;
+
+ if (( eDockingArea < ui::DockingArea_DOCKINGAREA_TOP ) || ( eDockingArea > ui::DockingArea_DOCKINGAREA_RIGHT ))
+ eDockingArea = ui::DockingArea_DOCKINGAREA_TOP;
+
+ bool bHorzDockArea = isHorizontalDockingArea( eDockingArea );
+
+ /* SAFE AREA ----------------------------------------------------------------------------------------------- */
+ {
+ SolarMutexGuard aReadLock;
+ for (auto const& elem : m_aUIElements)
+ {
+ if (elem.m_aDockedData.m_nDockedArea == eDockingArea)
+ {
+ bool bSameRowCol = bHorzDockArea ? (elem.m_aDockedData.m_aPos.Y == nRowCol)
+ : (elem.m_aDockedData.m_aPos.X == nRowCol);
+ uno::Reference<ui::XUIElement> xUIElement(elem.m_xUIElement);
+
+ if (bSameRowCol && xUIElement.is())
+ {
+ uno::Reference<awt::XWindow> xWindow(xUIElement->getRealInterface(),
+ uno::UNO_QUERY);
+ if (xWindow.is())
+ {
+ SolarMutexGuard aGuard;
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(xWindow);
+ uno::Reference<awt::XDockableWindow> xDockWindow(xWindow, uno::UNO_QUERY);
+ if (pWindow && elem.m_bVisible && xDockWindow.is() && !elem.m_bFloating)
+ aWindowVector.push_back(elem); // docked windows
+ }
+ }
+ }
+ }
+ }
+ /* SAFE AREA ----------------------------------------------------------------------------------------------- */
+
+ // Initialize structure
+ rRowColumnWindowData.aUIElementNames.clear();
+ rRowColumnWindowData.aRowColumnWindows.clear();
+ rRowColumnWindowData.aRowColumnWindowSizes.clear();
+ rRowColumnWindowData.aRowColumnSpace.clear();
+ rRowColumnWindowData.nVarSize = 0;
+ rRowColumnWindowData.nStaticSize = 0;
+ rRowColumnWindowData.nSpace = 0;
+ rRowColumnWindowData.nRowColumn = nRowCol;
+
+ // Collect data from windows that are on the same row/column
+ sal_Int32 j;
+ sal_Int32 nLastPos( 0 );
+
+ const sal_uInt32 nCount = aWindowVector.size();
+ for ( j = 0; j < sal_Int32( nCount); j++ )
+ {
+ const UIElement& rElement = aWindowVector[j];
+ uno::Reference< awt::XWindow > xWindow;
+ uno::Reference< ui::XUIElement > xUIElement( rElement.m_xUIElement );
+ awt::Rectangle aPosSize;
+ if ( !lcl_checkUIElement(xUIElement,aPosSize,xWindow) )
+ continue;
+
+ sal_Int32 nSpace;
+ if ( isHorizontalDockingArea( eDockingArea ))
+ {
+ nSpace = ( rElement.m_aDockedData.m_aPos.X - nLastPos );
+
+ // Calc space before an element and store it
+ if ( rElement.m_aDockedData.m_aPos.X > nLastPos )
+ rRowColumnWindowData.nSpace += nSpace;
+ else
+ nSpace = 0;
+
+ nLastPos = rElement.m_aDockedData.m_aPos.X + aPosSize.Width;
+
+ rRowColumnWindowData.aRowColumnWindowSizes.emplace_back(
+ rElement.m_aDockedData.m_aPos.X, rElement.m_aDockedData.m_aPos.Y,
+ aPosSize.Width, aPosSize.Height );
+ if ( rRowColumnWindowData.nStaticSize < aPosSize.Height )
+ rRowColumnWindowData.nStaticSize = aPosSize.Height;
+ rRowColumnWindowData.nVarSize += aPosSize.Width;
+ }
+ else
+ {
+ // Calc space before an element and store it
+ nSpace = ( rElement.m_aDockedData.m_aPos.Y - nLastPos );
+ if ( rElement.m_aDockedData.m_aPos.Y > nLastPos )
+ rRowColumnWindowData.nSpace += nSpace;
+ else
+ nSpace = 0;
+
+ nLastPos = rElement.m_aDockedData.m_aPos.Y + aPosSize.Height;
+
+ rRowColumnWindowData.aRowColumnWindowSizes.emplace_back(
+ rElement.m_aDockedData.m_aPos.X, rElement.m_aDockedData.m_aPos.Y,
+ aPosSize.Width, aPosSize.Height );
+ if ( rRowColumnWindowData.nStaticSize < aPosSize.Width )
+ rRowColumnWindowData.nStaticSize = aPosSize.Width;
+ rRowColumnWindowData.nVarSize += aPosSize.Height;
+ }
+
+ rRowColumnWindowData.aUIElementNames.push_back( rElement.m_aName );
+ rRowColumnWindowData.aRowColumnWindows.push_back( xWindow );
+ rRowColumnWindowData.aRowColumnSpace.push_back( nSpace );
+ rRowColumnWindowData.nVarSize += nSpace;
+ }
+}
+
+::tools::Rectangle ToolbarLayoutManager::implts_getWindowRectFromRowColumn(
+ ui::DockingArea DockingArea,
+ const SingleRowColumnWindowData& rRowColumnWindowData,
+ const ::Point& rMousePos,
+ std::u16string_view rExcludeElementName )
+{
+ ::tools::Rectangle aWinRect;
+
+ if (( DockingArea < ui::DockingArea_DOCKINGAREA_TOP ) || ( DockingArea > ui::DockingArea_DOCKINGAREA_RIGHT ))
+ DockingArea = ui::DockingArea_DOCKINGAREA_TOP;
+
+ if ( rRowColumnWindowData.aRowColumnWindows.empty() )
+ return aWinRect;
+ else
+ {
+ SolarMutexClearableGuard aReadLock;
+ VclPtr<vcl::Window> pContainerWindow( VCLUnoHelper::GetWindow( m_xContainerWindow ));
+ VclPtr<vcl::Window> pDockingAreaWindow( VCLUnoHelper::GetWindow( m_xDockAreaWindows[static_cast<int>(DockingArea)] ));
+ aReadLock.clear();
+
+ // Calc correct position of the column/row rectangle to be able to compare it with mouse pos/tracking rect
+ SolarMutexGuard aGuard;
+
+ // Retrieve output size from container Window
+ if ( pDockingAreaWindow && pContainerWindow )
+ {
+ const sal_uInt32 nCount = rRowColumnWindowData.aRowColumnWindows.size();
+ for ( sal_uInt32 i = 0; i < nCount; i++ )
+ {
+ awt::Rectangle aWindowRect = rRowColumnWindowData.aRowColumnWindows[i]->getPosSize();
+ ::tools::Rectangle aRect( aWindowRect.X, aWindowRect.Y, aWindowRect.X+aWindowRect.Width, aWindowRect.Y+aWindowRect.Height );
+ aRect.SetPos( pContainerWindow->ScreenToOutputPixel( pDockingAreaWindow->OutputToScreenPixel( aRect.TopLeft() )));
+ if ( aRect.Contains( rMousePos ))
+ {
+ // Check if we have found the excluded element. If yes, we have to provide an empty rectangle.
+ // We prevent that a toolbar cannot be moved when the mouse pointer is inside its own rectangle!
+ if ( rExcludeElementName != rRowColumnWindowData.aUIElementNames[i] )
+ return aRect;
+ else
+ break;
+ }
+ }
+ }
+ }
+
+ return aWinRect;
+}
+
+::tools::Rectangle ToolbarLayoutManager::implts_determineFrontDockingRect(
+ ui::DockingArea eDockingArea,
+ sal_Int32 nRowCol,
+ const ::tools::Rectangle& rDockedElementRect,
+ std::u16string_view rMovedElementName,
+ const ::tools::Rectangle& rMovedElementRect )
+{
+ SingleRowColumnWindowData aRowColumnWindowData;
+
+ bool bHorzDockArea( isHorizontalDockingArea( eDockingArea ));
+ implts_getDockingAreaElementInfoOnSingleRowCol( eDockingArea, nRowCol, aRowColumnWindowData );
+ if ( aRowColumnWindowData.aRowColumnWindows.empty() )
+ return rMovedElementRect;
+ else
+ {
+ sal_Int32 nSpace( 0 );
+ ::tools::Rectangle aFrontDockingRect( rMovedElementRect );
+ const sal_uInt32 nCount = aRowColumnWindowData.aRowColumnWindows.size();
+ for ( sal_uInt32 i = 0; i < nCount; i++ )
+ {
+ if ( bHorzDockArea )
+ {
+ if ( aRowColumnWindowData.aRowColumnWindowSizes[i].X >= rDockedElementRect.Left() )
+ {
+ nSpace += aRowColumnWindowData.aRowColumnSpace[i];
+ break;
+ }
+ else if ( aRowColumnWindowData.aUIElementNames[i] == rMovedElementName )
+ nSpace += aRowColumnWindowData.aRowColumnWindowSizes[i].Width +
+ aRowColumnWindowData.aRowColumnSpace[i];
+ else
+ nSpace = 0;
+ }
+ else
+ {
+ if ( aRowColumnWindowData.aRowColumnWindowSizes[i].Y >= rDockedElementRect.Top() )
+ {
+ nSpace += aRowColumnWindowData.aRowColumnSpace[i];
+ break;
+ }
+ else if ( aRowColumnWindowData.aUIElementNames[i] == rMovedElementName )
+ nSpace += aRowColumnWindowData.aRowColumnWindowSizes[i].Height +
+ aRowColumnWindowData.aRowColumnSpace[i];
+ else
+ nSpace = 0;
+ }
+ }
+
+ if ( nSpace > 0 )
+ {
+ sal_Int32 nMove = std::min( nSpace, static_cast<sal_Int32>(aFrontDockingRect.getWidth()) );
+ if ( bHorzDockArea )
+ aFrontDockingRect.Move( -nMove, 0 );
+ else
+ aFrontDockingRect.Move( 0, -nMove );
+ }
+
+ return aFrontDockingRect;
+ }
+}
+
+void ToolbarLayoutManager::implts_findNextDockingPos( ui::DockingArea DockingArea, const ::Size& aUIElementSize, awt::Point& rVirtualPos, ::Point& rPixelPos )
+{
+ SolarMutexClearableGuard aReadLock;
+ if (( DockingArea < ui::DockingArea_DOCKINGAREA_TOP ) || ( DockingArea > ui::DockingArea_DOCKINGAREA_RIGHT ))
+ DockingArea = ui::DockingArea_DOCKINGAREA_TOP;
+ uno::Reference< awt::XWindow > xDockingWindow( m_xDockAreaWindows[static_cast<int>(DockingArea)] );
+ ::Size aDockingWinSize;
+
+ // Retrieve output size from container Window
+ vcl::Window* pDockingWindow = VCLUnoHelper::GetWindow( xDockingWindow );
+ if ( pDockingWindow )
+ aDockingWinSize = pDockingWindow->GetOutputSizePixel();
+ aReadLock.clear();
+
+ sal_Int32 nFreeRowColPixelPos( 0 );
+ sal_Int32 nMaxSpace( 0 );
+ sal_Int32 nNeededSpace( 0 );
+ sal_Int32 nTopDockingAreaSize( 0 );
+
+ if ( isHorizontalDockingArea( DockingArea ))
+ {
+ nMaxSpace = aDockingWinSize.Width();
+ nNeededSpace = aUIElementSize.Width();
+ }
+ else
+ {
+ nMaxSpace = aDockingWinSize.Height();
+ nNeededSpace = aUIElementSize.Height();
+ nTopDockingAreaSize = implts_getTopBottomDockingAreaSizes().Width();
+ }
+
+ std::vector< SingleRowColumnWindowData > aRowColumnsWindowData;
+
+ implts_getDockingAreaElementInfos( DockingArea, aRowColumnsWindowData );
+ sal_Int32 nPixelPos( 0 );
+ const sal_uInt32 nCount = aRowColumnsWindowData.size();
+ for ( sal_uInt32 i = 0; i < nCount; i++ )
+ {
+ SingleRowColumnWindowData& rRowColumnWindowData = aRowColumnsWindowData[i];
+
+ if (( DockingArea == ui::DockingArea_DOCKINGAREA_BOTTOM ) ||
+ ( DockingArea == ui::DockingArea_DOCKINGAREA_RIGHT ))
+ nPixelPos += rRowColumnWindowData.nStaticSize;
+
+ if ((( nMaxSpace - rRowColumnWindowData.nVarSize ) >= nNeededSpace ) ||
+ ( rRowColumnWindowData.nSpace >= nNeededSpace ))
+ {
+ // Check current row where we can find the needed space
+ sal_Int32 nCurrPos( 0 );
+ const sal_uInt32 nWindowSizesCount = rRowColumnWindowData.aRowColumnWindowSizes.size();
+ for ( sal_uInt32 j = 0; j < nWindowSizesCount; j++ )
+ {
+ awt::Rectangle rRect = rRowColumnWindowData.aRowColumnWindowSizes[j];
+ sal_Int32& rSpace = rRowColumnWindowData.aRowColumnSpace[j];
+ if ( isHorizontalDockingArea( DockingArea ))
+ {
+ if ( rSpace >= nNeededSpace )
+ {
+ rVirtualPos = awt::Point( nCurrPos, rRowColumnWindowData.nRowColumn );
+ if ( DockingArea == ui::DockingArea_DOCKINGAREA_TOP )
+ rPixelPos = ::Point( nCurrPos, nPixelPos );
+ else
+ rPixelPos = ::Point( nCurrPos, aDockingWinSize.Height() - nPixelPos );
+ return;
+ }
+ nCurrPos = rRect.X + rRect.Width;
+ }
+ else
+ {
+ if ( rSpace >= nNeededSpace )
+ {
+ rVirtualPos = awt::Point( rRowColumnWindowData.nRowColumn, nCurrPos );
+ if ( DockingArea == ui::DockingArea_DOCKINGAREA_LEFT )
+ rPixelPos = ::Point( nPixelPos, nTopDockingAreaSize + nCurrPos );
+ else
+ rPixelPos = ::Point( aDockingWinSize.Width() - nPixelPos , nTopDockingAreaSize + nCurrPos );
+ return;
+ }
+ nCurrPos = rRect.Y + rRect.Height;
+ }
+ }
+
+ if (( nCurrPos + nNeededSpace ) <= nMaxSpace )
+ {
+ if ( isHorizontalDockingArea( DockingArea ))
+ {
+ rVirtualPos = awt::Point( nCurrPos, rRowColumnWindowData.nRowColumn );
+ if ( DockingArea == ui::DockingArea_DOCKINGAREA_TOP )
+ rPixelPos = ::Point( nCurrPos, nPixelPos );
+ else
+ rPixelPos = ::Point( nCurrPos, aDockingWinSize.Height() - nPixelPos );
+ return;
+ }
+ else
+ {
+ rVirtualPos = awt::Point( rRowColumnWindowData.nRowColumn, nCurrPos );
+ if ( DockingArea == ui::DockingArea_DOCKINGAREA_LEFT )
+ rPixelPos = ::Point( nPixelPos, nTopDockingAreaSize + nCurrPos );
+ else
+ rPixelPos = ::Point( aDockingWinSize.Width() - nPixelPos , nTopDockingAreaSize + nCurrPos );
+ return;
+ }
+ }
+ }
+
+ if (( DockingArea == ui::DockingArea_DOCKINGAREA_TOP ) || ( DockingArea == ui::DockingArea_DOCKINGAREA_LEFT ))
+ nPixelPos += rRowColumnWindowData.nStaticSize;
+ }
+
+ sal_Int32 nNextFreeRowCol( 0 );
+ sal_Int32 nRowColumnsCount = aRowColumnsWindowData.size();
+ if ( nRowColumnsCount > 0 )
+ nNextFreeRowCol = aRowColumnsWindowData[nRowColumnsCount-1].nRowColumn+1;
+ else
+ nNextFreeRowCol = 0;
+
+ if ( nNextFreeRowCol == 0 )
+ {
+ if ( DockingArea == ui::DockingArea_DOCKINGAREA_BOTTOM )
+ nFreeRowColPixelPos = aDockingWinSize.Height() - aUIElementSize.Height();
+ else if ( DockingArea == ui::DockingArea_DOCKINGAREA_RIGHT )
+ nFreeRowColPixelPos = aDockingWinSize.Width() - aUIElementSize.Width();
+ }
+
+ if ( isHorizontalDockingArea( DockingArea ))
+ {
+ rVirtualPos = awt::Point( 0, nNextFreeRowCol );
+ if ( DockingArea == ui::DockingArea_DOCKINGAREA_TOP )
+ rPixelPos = ::Point( 0, nFreeRowColPixelPos );
+ else
+ rPixelPos = ::Point( 0, aDockingWinSize.Height() - nFreeRowColPixelPos );
+ }
+ else
+ {
+ rVirtualPos = awt::Point( nNextFreeRowCol, 0 );
+ rPixelPos = ::Point( aDockingWinSize.Width() - nFreeRowColPixelPos, 0 );
+ }
+}
+
+void ToolbarLayoutManager::implts_calcWindowPosSizeOnSingleRowColumn(
+ sal_Int32 nDockingArea,
+ sal_Int32 nOffset,
+ SingleRowColumnWindowData& rRowColumnWindowData,
+ const ::Size& rContainerSize )
+{
+ sal_Int32 nDiff(0);
+ sal_Int32 nRCSpace( rRowColumnWindowData.nSpace );
+ sal_Int32 nContainerClientSize(0);
+
+ if ( rRowColumnWindowData.aRowColumnWindows.empty() )
+ return;
+
+ if ( isHorizontalDockingArea( nDockingArea ))
+ {
+ nContainerClientSize = rContainerSize.Width();
+ nDiff = nContainerClientSize - rRowColumnWindowData.nVarSize;
+ }
+ else
+ {
+ sal_Int32 nTopDockingAreaSize = implts_getTopBottomDockingAreaSizes().Width();
+ sal_Int32 nBottomDockingAreaSize = implts_getTopBottomDockingAreaSizes().Height();
+ nContainerClientSize = ( rContainerSize.Height() - nTopDockingAreaSize - nBottomDockingAreaSize );
+ nDiff = nContainerClientSize - rRowColumnWindowData.nVarSize;
+ }
+
+ const sal_uInt32 nCount = rRowColumnWindowData.aRowColumnWindowSizes.size();
+ if (( nDiff < 0 ) && ( nRCSpace > 0 ))
+ {
+ // First we try to reduce the size of blank space before/behind docked windows
+ sal_Int32 i = nCount - 1;
+ while ( i >= 0 )
+ {
+ sal_Int32 nSpace = rRowColumnWindowData.aRowColumnSpace[i];
+ if ( nSpace >= -nDiff )
+ {
+ if ( isHorizontalDockingArea( nDockingArea ))
+ {
+ // Try to move this and all user elements behind with the calculated difference
+ for ( sal_uInt32 j = i; j < nCount; j++ )
+ rRowColumnWindowData.aRowColumnWindowSizes[j].X += nDiff;
+ }
+ else
+ {
+ // Try to move this and all user elements behind with the calculated difference
+ for ( sal_uInt32 j = i; j < nCount; j++ )
+ rRowColumnWindowData.aRowColumnWindowSizes[j].Y += nDiff;
+ }
+ nDiff = 0;
+
+ break;
+ }
+ else if ( nSpace > 0 )
+ {
+ if ( isHorizontalDockingArea( nDockingArea ))
+ {
+ // Try to move this and all user elements behind with the calculated difference
+ for ( sal_uInt32 j = i; j < nCount; j++ )
+ rRowColumnWindowData.aRowColumnWindowSizes[j].X -= nSpace;
+ }
+ else
+ {
+ // Try to move this and all user elements behind with the calculated difference
+ for ( sal_uInt32 j = i; j < nCount; j++ )
+ rRowColumnWindowData.aRowColumnWindowSizes[j].Y -= nSpace;
+ }
+ nDiff += nSpace;
+ }
+ --i;
+ }
+ }
+
+ // Check if we have to reduce further
+ if ( nDiff < 0 )
+ {
+ // Now we have to reduce the size of certain docked windows
+ sal_Int32 i = sal_Int32( nCount - 1 );
+ while ( i >= 0 )
+ {
+ awt::Rectangle& rWinRect = rRowColumnWindowData.aRowColumnWindowSizes[i];
+ ::Size aMinSize;
+
+ SolarMutexGuard aGuard;
+ {
+ uno::Reference< awt::XWindow > xWindow = rRowColumnWindowData.aRowColumnWindows[i];
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow );
+ if ( pWindow && pWindow->GetType() == WindowType::TOOLBOX )
+ aMinSize = static_cast<ToolBox *>(pWindow.get())->CalcMinimumWindowSizePixel();
+ }
+
+ if ( !aMinSize.IsEmpty() )
+ {
+ if ( isHorizontalDockingArea( nDockingArea ))
+ {
+ sal_Int32 nMaxReducation = rWinRect.Width - aMinSize.Width();
+ if ( nMaxReducation >= -nDiff )
+ {
+ rWinRect.Width = rWinRect.Width + nDiff;
+ nDiff = 0;
+ }
+ else
+ {
+ rWinRect.Width = aMinSize.Width();
+ nDiff += nMaxReducation;
+ }
+
+ // Try to move this and all user elements behind with the calculated difference
+ for ( sal_uInt32 j = i; j < nCount; j++ )
+ rRowColumnWindowData.aRowColumnWindowSizes[j].X += nDiff;
+ }
+ else
+ {
+ sal_Int32 nMaxReducation = rWinRect.Height - aMinSize.Height();
+ if ( nMaxReducation >= -nDiff )
+ {
+ rWinRect.Height = rWinRect.Height + nDiff;
+ nDiff = 0;
+ }
+ else
+ {
+ rWinRect.Height = aMinSize.Height();
+ nDiff += nMaxReducation;
+ }
+
+ // Try to move this and all user elements behind with the calculated difference
+ for ( sal_uInt32 j = i; j < nCount; j++ )
+ rRowColumnWindowData.aRowColumnWindowSizes[j].Y += nDiff;
+ }
+ }
+
+ if ( nDiff >= 0 )
+ break;
+
+ --i;
+ }
+ }
+
+ SolarMutexClearableGuard aReadLock;
+ VclPtr<vcl::Window> pDockAreaWindow = VCLUnoHelper::GetWindow( m_xDockAreaWindows[nDockingArea] );
+ aReadLock.clear();
+
+ sal_Int32 nCurrPos( 0 );
+
+ SolarMutexGuard aGuard;
+ for ( sal_uInt32 i = 0; i < nCount; i++ )
+ {
+ uno::Reference< awt::XWindow > xWindow = rRowColumnWindowData.aRowColumnWindows[i];
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow );
+ vcl::Window* pOldParentWindow = pWindow->GetParent();
+
+ if ( pDockAreaWindow != pOldParentWindow )
+ pWindow->SetParent( pDockAreaWindow );
+
+ awt::Rectangle aWinRect = rRowColumnWindowData.aRowColumnWindowSizes[i];
+ if ( isHorizontalDockingArea( nDockingArea ))
+ {
+ if ( aWinRect.X < nCurrPos )
+ aWinRect.X = nCurrPos;
+ pWindow->SetPosSizePixel( ::Point( aWinRect.X, nOffset ), ::Size( aWinRect.Width, rRowColumnWindowData.nStaticSize ));
+ pWindow->Show( true, ShowFlags::NoFocusChange | ShowFlags::NoActivate );
+ nCurrPos += ( aWinRect.X - nCurrPos ) + aWinRect.Width;
+ }
+ else
+ {
+ if ( aWinRect.Y < nCurrPos )
+ aWinRect.Y = nCurrPos;
+ pWindow->SetPosSizePixel( ::Point( nOffset, aWinRect.Y ), ::Size( rRowColumnWindowData.nStaticSize, aWinRect.Height ));
+ pWindow->Show( true, ShowFlags::NoFocusChange | ShowFlags::NoActivate );
+ nCurrPos += ( aWinRect.Y - nCurrPos ) + aWinRect.Height;
+ }
+ }
+}
+
+void ToolbarLayoutManager::implts_setLayoutDirty()
+{
+ SolarMutexGuard g;
+ m_bLayoutDirty = true;
+}
+
+void ToolbarLayoutManager::implts_setLayoutInProgress( bool bInProgress )
+{
+ SolarMutexGuard g;
+ m_bLayoutInProgress = bInProgress;
+}
+
+::tools::Rectangle ToolbarLayoutManager::implts_calcHotZoneRect( const ::tools::Rectangle& rRect, sal_Int32 nHotZoneOffset )
+{
+ ::tools::Rectangle aRect( rRect );
+
+ aRect.AdjustLeft( -nHotZoneOffset );
+ aRect.AdjustTop( -nHotZoneOffset );
+ aRect.AdjustRight(nHotZoneOffset );
+ aRect.AdjustBottom(nHotZoneOffset );
+
+ return aRect;
+}
+
+void ToolbarLayoutManager::implts_calcDockingPosSize(
+ UIElement& rUIElement,
+ DockingOperation& rDockingOperation,
+ ::tools::Rectangle& rTrackingRect,
+ const Point& rMousePos )
+{
+ SolarMutexResettableGuard aReadLock;
+ uno::Reference< awt::XWindow2 > xContainerWindow( m_xContainerWindow );
+ ::Size aContainerWinSize;
+ vcl::Window* pContainerWindow( nullptr );
+ ::tools::Rectangle aDockingAreaOffsets( m_aDockingAreaOffsets );
+ aReadLock.clear();
+
+ if ( !rUIElement.m_xUIElement.is() )
+ {
+ rTrackingRect = ::tools::Rectangle();
+ return;
+ }
+
+ {
+ // Retrieve output size from container Window
+ SolarMutexGuard aGuard;
+ pContainerWindow = VCLUnoHelper::GetWindow( xContainerWindow );
+ aContainerWinSize = pContainerWindow->GetOutputSizePixel();
+ }
+
+ vcl::Window* pDockingAreaWindow( nullptr );
+ uno::Reference< awt::XWindow > xWindow( rUIElement.m_xUIElement->getRealInterface(), uno::UNO_QUERY );
+ uno::Reference< awt::XWindow > xDockingAreaWindow;
+ ::tools::Rectangle aTrackingRect( rTrackingRect );
+ ui::DockingArea eDockedArea( rUIElement.m_aDockedData.m_nDockedArea );
+ sal_Int32 nTopDockingAreaSize( implts_getTopBottomDockingAreaSizes().Width() );
+ sal_Int32 nBottomDockingAreaSize( implts_getTopBottomDockingAreaSizes().Height() );
+ bool bHorizontalDockArea(( eDockedArea == ui::DockingArea_DOCKINGAREA_TOP ) ||
+ ( eDockedArea == ui::DockingArea_DOCKINGAREA_BOTTOM ));
+ sal_Int32 nMaxLeftRightDockAreaSize = aContainerWinSize.Height() -
+ nTopDockingAreaSize -
+ nBottomDockingAreaSize -
+ aDockingAreaOffsets.Top() -
+ aDockingAreaOffsets.Bottom();
+ ::tools::Rectangle aDockingAreaRect;
+
+ aReadLock.reset();
+ xDockingAreaWindow = m_xDockAreaWindows[static_cast<int>(eDockedArea)];
+ aReadLock.clear();
+
+ {
+ SolarMutexGuard aGuard;
+ pDockingAreaWindow = VCLUnoHelper::GetWindow( xDockingAreaWindow );
+ VclPtr<vcl::Window> pDockWindow = VCLUnoHelper::GetWindow( xWindow );
+ ToolBox* pToolBox( nullptr );
+ if ( pDockWindow && pDockWindow->GetType() == WindowType::TOOLBOX )
+ pToolBox = static_cast<ToolBox *>(pDockWindow.get());
+
+ aDockingAreaRect = ::tools::Rectangle( pDockingAreaWindow->GetPosPixel(), pDockingAreaWindow->GetSizePixel() );
+ if ( pToolBox )
+ {
+ // docked toolbars always have one line
+ ::Size aSize = pToolBox->CalcWindowSizePixel( 1, ImplConvertAlignment( eDockedArea ) );
+ aTrackingRect.SetSize( ::Size( aSize.Width(), aSize.Height() ));
+ }
+ }
+
+ // default docking operation, dock on the given row/column
+ bool bOpOutsideOfDockingArea( !aDockingAreaRect.Contains( rMousePos ));
+
+ std::vector< SingleRowColumnWindowData > aRowColumnsWindowData;
+
+ rDockingOperation = DOCKOP_ON_COLROW;
+ implts_getDockingAreaElementInfos( eDockedArea, aRowColumnsWindowData );
+
+ // determine current first row/column and last row/column
+ sal_Int32 nMaxRowCol( -1 );
+ sal_Int32 nMinRowCol( SAL_MAX_INT32 );
+ const sal_uInt32 nCount = aRowColumnsWindowData.size();
+ for ( sal_uInt32 i = 0; i < nCount; i++ )
+ {
+ if ( aRowColumnsWindowData[i].nRowColumn > nMaxRowCol )
+ nMaxRowCol = aRowColumnsWindowData[i].nRowColumn;
+ if ( aRowColumnsWindowData[i].nRowColumn < nMinRowCol )
+ nMinRowCol = aRowColumnsWindowData[i].nRowColumn;
+ }
+
+ if ( !bOpOutsideOfDockingArea )
+ {
+ // docking inside our docking area
+ sal_Int32 nIndex( -1 );
+ sal_Int32 nRowCol( -1 );
+ ::tools::Rectangle aWindowRect;
+ ::tools::Rectangle aRowColumnRect;
+
+ const sal_uInt32 nWindowDataCount = aRowColumnsWindowData.size();
+ for ( sal_uInt32 i = 0; i < nWindowDataCount; i++ )
+ {
+ ::tools::Rectangle aRect( aRowColumnsWindowData[i].aRowColumnRect.X,
+ aRowColumnsWindowData[i].aRowColumnRect.Y,
+ aRowColumnsWindowData[i].aRowColumnRect.X + aRowColumnsWindowData[i].aRowColumnRect.Width,
+ aRowColumnsWindowData[i].aRowColumnRect.Y + aRowColumnsWindowData[i].aRowColumnRect.Height );
+
+ {
+ // Calc correct position of the column/row rectangle to be able to compare it with mouse pos/tracking rect
+ SolarMutexGuard aGuard;
+ aRect.SetPos( pContainerWindow->ScreenToOutputPixel( pDockingAreaWindow->OutputToScreenPixel( aRect.TopLeft() )));
+ }
+
+ bool bIsInsideRowCol( aRect.Contains( rMousePos ) );
+ if ( bIsInsideRowCol )
+ {
+ nIndex = i;
+ nRowCol = aRowColumnsWindowData[i].nRowColumn;
+ rDockingOperation = implts_determineDockingOperation( eDockedArea, aRect, rMousePos );
+ aWindowRect = implts_getWindowRectFromRowColumn( eDockedArea, aRowColumnsWindowData[i], rMousePos, rUIElement.m_aName );
+ aRowColumnRect = aRect;
+ break;
+ }
+ }
+
+ OSL_ENSURE( ( nIndex >= 0 ) && ( nRowCol >= 0 ), "Impossible case - no row/column found but mouse pointer is inside our docking area" );
+ if (( nIndex >= 0 ) && ( nRowCol >= 0 ))
+ {
+ if ( rDockingOperation == DOCKOP_ON_COLROW )
+ {
+ if ( !aWindowRect.IsEmpty())
+ {
+ // Tracking rect is on a row/column and mouse is over a docked toolbar.
+ // Determine if the tracking rect must be located before/after the docked toolbar.
+
+ ::tools::Rectangle aUIElementRect( aWindowRect );
+ sal_Int32 nMiddle( bHorizontalDockArea ? ( aWindowRect.Left() + aWindowRect.getWidth() / 2 ) :
+ ( aWindowRect.Top() + aWindowRect.getHeight() / 2 ));
+ bool bInsertBefore( bHorizontalDockArea ? ( rMousePos.X() < nMiddle ) : ( rMousePos.Y() < nMiddle ));
+ if ( bInsertBefore )
+ {
+ if ( bHorizontalDockArea )
+ {
+ sal_Int32 nSize = std::clamp( sal_Int32(aContainerWinSize.Width() - aWindowRect.Left()),
+ sal_Int32(0), sal_Int32(aTrackingRect.getWidth()) );
+ if ( nSize == 0 )
+ nSize = aWindowRect.getWidth();
+
+ aUIElementRect.SetSize( ::Size( nSize, aWindowRect.getHeight() ));
+ aWindowRect = implts_determineFrontDockingRect( eDockedArea, nRowCol, aWindowRect,rUIElement.m_aName, aUIElementRect );
+
+ // Set virtual position
+ rUIElement.m_aDockedData.m_aPos.X = aWindowRect.Left();
+ rUIElement.m_aDockedData.m_aPos.Y = nRowCol;
+ }
+ else
+ {
+ sal_Int32 nSize = std::clamp( sal_Int32(nTopDockingAreaSize + nMaxLeftRightDockAreaSize - aWindowRect.Top()),
+ sal_Int32(0), sal_Int32(aTrackingRect.getHeight()) );
+ if ( nSize == 0 )
+ nSize = aWindowRect.getHeight();
+
+ aUIElementRect.SetSize( ::Size( aWindowRect.getWidth(), nSize ));
+ aWindowRect = implts_determineFrontDockingRect( eDockedArea, nRowCol, aWindowRect, rUIElement.m_aName, aUIElementRect );
+
+ // Set virtual position
+ sal_Int32 nPosY = pDockingAreaWindow->ScreenToOutputPixel(
+ pContainerWindow->OutputToScreenPixel( aWindowRect.TopLeft() )).Y();
+ rUIElement.m_aDockedData.m_aPos.X = nRowCol;
+ rUIElement.m_aDockedData.m_aPos.Y = nPosY;
+ }
+
+ rTrackingRect = aWindowRect;
+ return;
+ }
+ else
+ {
+ if ( bHorizontalDockArea )
+ {
+ sal_Int32 nSize = ::std::clamp( sal_Int32(aContainerWinSize.Width() - aWindowRect.Right()),
+ sal_Int32(0), sal_Int32(aTrackingRect.getWidth()) );
+ if ( nSize == 0 )
+ {
+ aUIElementRect.SetPos( ::Point( aContainerWinSize.Width() - aTrackingRect.getWidth(), aWindowRect.Top() ));
+ aUIElementRect.SetSize( ::Size( aTrackingRect.getWidth(), aWindowRect.getHeight() ));
+ rUIElement.m_aDockedData.m_aPos.X = aUIElementRect.Left();
+
+ }
+ else
+ {
+ aUIElementRect.SetPos( ::Point( aWindowRect.Right(), aWindowRect.Top() ));
+ aUIElementRect.SetSize( ::Size( nSize, aWindowRect.getHeight() ));
+ rUIElement.m_aDockedData.m_aPos.X = aWindowRect.Right();
+ }
+
+ // Set virtual position
+ rUIElement.m_aDockedData.m_aPos.Y = nRowCol;
+ }
+ else
+ {
+ sal_Int32 nSize = std::clamp( sal_Int32(nTopDockingAreaSize + nMaxLeftRightDockAreaSize - aWindowRect.Bottom()),
+ sal_Int32(0), sal_Int32(aTrackingRect.getHeight()) );
+ aUIElementRect.SetPos( ::Point( aWindowRect.Left(), aWindowRect.Bottom() ));
+ aUIElementRect.SetSize( ::Size( aWindowRect.getWidth(), nSize ));
+
+ // Set virtual position
+ sal_Int32 nPosY( 0 );
+ {
+ SolarMutexGuard aGuard;
+ nPosY = pDockingAreaWindow->ScreenToOutputPixel(
+ pContainerWindow->OutputToScreenPixel( aWindowRect.BottomRight() )).Y();
+ }
+ rUIElement.m_aDockedData.m_aPos.X = nRowCol;
+ rUIElement.m_aDockedData.m_aPos.Y = nPosY;
+ }
+
+ rTrackingRect = aUIElementRect;
+ return;
+ }
+ }
+ else
+ {
+ implts_setTrackingRect( eDockedArea, rMousePos, aTrackingRect );
+ rTrackingRect = implts_calcTrackingAndElementRect(
+ eDockedArea, nRowCol, rUIElement,
+ aTrackingRect, aRowColumnRect, aContainerWinSize );
+ return;
+ }
+ }
+ else
+ {
+ if ((( nRowCol == nMinRowCol ) && ( rDockingOperation == DOCKOP_BEFORE_COLROW )) ||
+ (( nRowCol == nMaxRowCol ) && ( rDockingOperation == DOCKOP_AFTER_COLROW )))
+ bOpOutsideOfDockingArea = true;
+ else
+ {
+ // handle docking before/after a row
+ implts_setTrackingRect( eDockedArea, rMousePos, aTrackingRect );
+ rTrackingRect = implts_calcTrackingAndElementRect(
+ eDockedArea, nRowCol, rUIElement,
+ aTrackingRect, aRowColumnRect, aContainerWinSize );
+
+ sal_Int32 nOffsetX( 0 );
+ sal_Int32 nOffsetY( 0 );
+ if ( bHorizontalDockArea )
+ nOffsetY = sal_Int32( floor( aRowColumnRect.getHeight() / 2.0 + 0.5 ));
+ else
+ nOffsetX = sal_Int32( floor( aRowColumnRect.getWidth() / 2.0 + 0.5 ));
+
+ if ( rDockingOperation == DOCKOP_BEFORE_COLROW )
+ {
+ if (( eDockedArea == ui::DockingArea_DOCKINGAREA_TOP ) || ( eDockedArea == ui::DockingArea_DOCKINGAREA_LEFT ))
+ {
+ // Docking before/after means move track rectangle half column/row.
+ // As left and top are ordered 0...n instead of right and bottom
+ // which uses n...0, we have to use negative values for top/left.
+ nOffsetX *= -1;
+ nOffsetY *= -1;
+ }
+ }
+ else
+ {
+ if (( eDockedArea == ui::DockingArea_DOCKINGAREA_BOTTOM ) || ( eDockedArea == ui::DockingArea_DOCKINGAREA_RIGHT ))
+ {
+ // Docking before/after means move track rectangle half column/row.
+ // As left and top are ordered 0...n instead of right and bottom
+ // which uses n...0, we have to use negative values for top/left.
+ nOffsetX *= -1;
+ nOffsetY *= -1;
+ }
+ nRowCol++;
+ }
+
+ if ( bHorizontalDockArea )
+ rUIElement.m_aDockedData.m_aPos.Y = nRowCol;
+ else
+ rUIElement.m_aDockedData.m_aPos.X = nRowCol;
+
+ rTrackingRect.Move( nOffsetX, nOffsetY );
+ rTrackingRect.SetSize( aTrackingRect.GetSize() );
+ }
+ }
+ }
+ }
+
+ // Docking outside of our docking window area =>
+ // Users want to dock before/after first/last docked element or to an empty docking area
+ if ( !bOpOutsideOfDockingArea )
+ return;
+
+ // set correct size for docking
+ implts_setTrackingRect( eDockedArea, rMousePos, aTrackingRect );
+ rTrackingRect = aTrackingRect;
+
+ if ( bHorizontalDockArea )
+ {
+ sal_Int32 nPosX( std::max( sal_Int32( rTrackingRect.Left()), sal_Int32( 0 )));
+ if (( nPosX + rTrackingRect.getWidth()) > aContainerWinSize.Width() )
+ nPosX = std::min( nPosX,
+ std::max( sal_Int32( aContainerWinSize.Width() - rTrackingRect.getWidth() ),
+ sal_Int32( 0 )));
+
+ sal_Int32 nSize = std::min( aContainerWinSize.Width(), rTrackingRect.getWidth() );
+ sal_Int32 nDockHeight = std::max( static_cast<sal_Int32>(aDockingAreaRect.getHeight()), sal_Int32( 0 ));
+ if ( nDockHeight == 0 )
+ {
+ sal_Int32 nPosY( std::max( aDockingAreaRect.Top(), aDockingAreaRect.Bottom() ));
+ if ( eDockedArea == ui::DockingArea_DOCKINGAREA_BOTTOM )
+ nPosY -= rTrackingRect.getHeight();
+ rTrackingRect.SetPos( Point( nPosX, nPosY ));
+ rUIElement.m_aDockedData.m_aPos.Y = 0;
+ }
+ else if ( rMousePos.Y() < ( aDockingAreaRect.Top() + ( nDockHeight / 2 )))
+ {
+ rTrackingRect.SetPos( Point( nPosX, aDockingAreaRect.Top() - rTrackingRect.getHeight() ));
+ if ( eDockedArea == ui::DockingArea_DOCKINGAREA_TOP )
+ rUIElement.m_aDockedData.m_aPos.Y = 0;
+ else
+ rUIElement.m_aDockedData.m_aPos.Y = ( nMaxRowCol >= 0 ) ? nMaxRowCol+1 : 0;
+ rDockingOperation = DOCKOP_BEFORE_COLROW;
+ }
+ else
+ {
+ rTrackingRect.SetPos( Point( nPosX, aDockingAreaRect.Bottom() ));
+ if ( eDockedArea == ui::DockingArea_DOCKINGAREA_TOP )
+ rUIElement.m_aDockedData.m_aPos.Y = ( nMaxRowCol >= 0 ) ? nMaxRowCol+1 : 0;
+ else
+ rUIElement.m_aDockedData.m_aPos.Y = 0;
+ rDockingOperation = DOCKOP_AFTER_COLROW;
+ }
+ rTrackingRect.setWidth( nSize );
+
+ {
+ SolarMutexGuard aGuard;
+ nPosX = pDockingAreaWindow->ScreenToOutputPixel(
+ pContainerWindow->OutputToScreenPixel( rTrackingRect.TopLeft() )).X();
+ }
+ rUIElement.m_aDockedData.m_aPos.X = nPosX;
+ }
+ else
+ {
+ sal_Int32 nMaxDockingAreaHeight = std::max<sal_Int32>( 0, nMaxLeftRightDockAreaSize );
+ sal_Int32 nPosY( std::max<sal_Int32>( aTrackingRect.Top(), nTopDockingAreaSize ));
+ if (( nPosY + aTrackingRect.getHeight()) > ( nTopDockingAreaSize + nMaxDockingAreaHeight ))
+ nPosY = std::min( nPosY,
+ std::max<sal_Int32>( nTopDockingAreaSize + ( nMaxDockingAreaHeight - aTrackingRect.getHeight() ),
+ nTopDockingAreaSize ));
+
+ sal_Int32 nSize = std::min( nMaxDockingAreaHeight, static_cast<sal_Int32>(aTrackingRect.getHeight()) );
+ sal_Int32 nDockWidth = std::max( static_cast<sal_Int32>(aDockingAreaRect.getWidth()), sal_Int32( 0 ));
+ if ( nDockWidth == 0 )
+ {
+ sal_Int32 nPosX( std::max( aDockingAreaRect.Left(), aDockingAreaRect.Right() ));
+ if ( eDockedArea == ui::DockingArea_DOCKINGAREA_RIGHT )
+ nPosX -= rTrackingRect.getWidth();
+ rTrackingRect.SetPos( Point( nPosX, nPosY ));
+ rUIElement.m_aDockedData.m_aPos.X = 0;
+ }
+ else if ( rMousePos.X() < ( aDockingAreaRect.Left() + ( nDockWidth / 2 )))
+ {
+ rTrackingRect.SetPos( Point( aDockingAreaRect.Left() - rTrackingRect.getWidth(), nPosY ));
+ if ( eDockedArea == ui::DockingArea_DOCKINGAREA_LEFT )
+ rUIElement.m_aDockedData.m_aPos.X = 0;
+ else
+ rUIElement.m_aDockedData.m_aPos.X = ( nMaxRowCol >= 0 ) ? nMaxRowCol+1 : 0;
+ rDockingOperation = DOCKOP_BEFORE_COLROW;
+ }
+ else
+ {
+ rTrackingRect.SetPos( Point( aDockingAreaRect.Right(), nPosY ));
+ if ( eDockedArea == ui::DockingArea_DOCKINGAREA_LEFT )
+ rUIElement.m_aDockedData.m_aPos.X = ( nMaxRowCol >= 0 ) ? nMaxRowCol+1 : 0;
+ else
+ rUIElement.m_aDockedData.m_aPos.X = 0;
+ rDockingOperation = DOCKOP_AFTER_COLROW;
+ }
+ rTrackingRect.setHeight( nSize );
+
+ {
+ SolarMutexGuard aGuard;
+ nPosY = pDockingAreaWindow->ScreenToOutputPixel(
+ pContainerWindow->OutputToScreenPixel( rTrackingRect.TopLeft() )).Y();
+ }
+ rUIElement.m_aDockedData.m_aPos.Y = nPosY;
+ }
+}
+
+framework::ToolbarLayoutManager::DockingOperation ToolbarLayoutManager::implts_determineDockingOperation(
+ ui::DockingArea DockingArea,
+ const ::tools::Rectangle& rRowColRect,
+ const Point& rMousePos )
+{
+ constexpr sal_Int32 nHorzVerticalRegionSize = 6;
+ constexpr sal_Int32 nHorzVerticalMoveRegion = 4;
+
+ if ( rRowColRect.Contains( rMousePos ))
+ {
+ if ( isHorizontalDockingArea( DockingArea ))
+ {
+ sal_Int32 nRegion = rRowColRect.getHeight() / nHorzVerticalRegionSize;
+ sal_Int32 nPosY = rRowColRect.Top() + nRegion;
+
+ if ( rMousePos.Y() < nPosY )
+ return ( DockingArea == ui::DockingArea_DOCKINGAREA_TOP ) ? DOCKOP_BEFORE_COLROW : DOCKOP_AFTER_COLROW;
+ else if ( rMousePos.Y() < ( nPosY + nRegion*nHorzVerticalMoveRegion ))
+ return DOCKOP_ON_COLROW;
+ else
+ return ( DockingArea == ui::DockingArea_DOCKINGAREA_TOP ) ? DOCKOP_AFTER_COLROW : DOCKOP_BEFORE_COLROW;
+ }
+ else
+ {
+ sal_Int32 nRegion = rRowColRect.getWidth() / nHorzVerticalRegionSize;
+ sal_Int32 nPosX = rRowColRect.Left() + nRegion;
+
+ if ( rMousePos.X() < nPosX )
+ return ( DockingArea == ui::DockingArea_DOCKINGAREA_LEFT ) ? DOCKOP_BEFORE_COLROW : DOCKOP_AFTER_COLROW;
+ else if ( rMousePos.X() < ( nPosX + nRegion*nHorzVerticalMoveRegion ))
+ return DOCKOP_ON_COLROW;
+ else
+ return ( DockingArea == ui::DockingArea_DOCKINGAREA_LEFT ) ? DOCKOP_AFTER_COLROW : DOCKOP_BEFORE_COLROW;
+ }
+ }
+ else
+ return DOCKOP_ON_COLROW;
+}
+
+::tools::Rectangle ToolbarLayoutManager::implts_calcTrackingAndElementRect(
+ ui::DockingArea eDockingArea,
+ sal_Int32 nRowCol,
+ UIElement& rUIElement,
+ const ::tools::Rectangle& rTrackingRect,
+ const ::tools::Rectangle& rRowColumnRect,
+ const ::Size& rContainerWinSize )
+{
+ SolarMutexResettableGuard aReadGuard;
+ ::tools::Rectangle aDockingAreaOffsets( m_aDockingAreaOffsets );
+ aReadGuard.clear();
+
+ bool bHorizontalDockArea( isHorizontalDockingArea( eDockingArea ));
+
+ sal_Int32 nTopDockingAreaSize( implts_getTopBottomDockingAreaSizes().Width() );
+ sal_Int32 nBottomDockingAreaSize( implts_getTopBottomDockingAreaSizes().Height() );
+
+ sal_Int32 nMaxLeftRightDockAreaSize = rContainerWinSize.Height() -
+ nTopDockingAreaSize -
+ nBottomDockingAreaSize -
+ aDockingAreaOffsets.Top() -
+ aDockingAreaOffsets.Bottom();
+
+ ::tools::Rectangle aTrackingRect( rTrackingRect );
+ if ( bHorizontalDockArea )
+ {
+ sal_Int32 nPosX( std::max( sal_Int32( rTrackingRect.Left()), sal_Int32( 0 )));
+ if (( nPosX + rTrackingRect.getWidth()) > rContainerWinSize.Width() )
+ nPosX = std::min( nPosX,
+ std::max( sal_Int32( rContainerWinSize.Width() - rTrackingRect.getWidth() ),
+ sal_Int32( 0 )));
+
+ sal_Int32 nSize = std::min( rContainerWinSize.Width(), rTrackingRect.getWidth() );
+
+ aTrackingRect.SetPos( ::Point( nPosX, rRowColumnRect.Top() ));
+ aTrackingRect.setWidth( nSize );
+ aTrackingRect.setHeight( rRowColumnRect.getHeight() );
+
+ // Set virtual position
+ rUIElement.m_aDockedData.m_aPos.X = nPosX;
+ rUIElement.m_aDockedData.m_aPos.Y = nRowCol;
+ }
+ else
+ {
+ sal_Int32 nMaxDockingAreaHeight = std::max<sal_Int32>( 0, nMaxLeftRightDockAreaSize );
+
+ sal_Int32 nPosY( std::max<sal_Int32>( aTrackingRect.Top(), nTopDockingAreaSize ));
+ if (( nPosY + aTrackingRect.getHeight()) > ( nTopDockingAreaSize + nMaxDockingAreaHeight ))
+ nPosY = std::min( nPosY,
+ std::max<sal_Int32>( nTopDockingAreaSize + ( nMaxDockingAreaHeight - aTrackingRect.getHeight() ),
+ nTopDockingAreaSize ));
+
+ sal_Int32 nSize = std::min( nMaxDockingAreaHeight, static_cast<sal_Int32>(aTrackingRect.getHeight()) );
+
+ aTrackingRect.SetPos( ::Point( rRowColumnRect.Left(), nPosY ));
+ aTrackingRect.setWidth( rRowColumnRect.getWidth() );
+ aTrackingRect.setHeight( nSize );
+
+ aReadGuard.reset();
+ uno::Reference< awt::XWindow > xDockingAreaWindow( m_xDockAreaWindows[static_cast<int>(eDockingArea)] );
+ uno::Reference< awt::XWindow2 > xContainerWindow( m_xContainerWindow );
+ aReadGuard.clear();
+
+ sal_Int32 nDockPosY( 0 );
+ {
+ SolarMutexGuard aGuard;
+ vcl::Window* pDockingAreaWindow = VCLUnoHelper::GetWindow( xDockingAreaWindow );
+ VclPtr<vcl::Window> pContainerWindow = VCLUnoHelper::GetWindow( xContainerWindow );
+ nDockPosY = pDockingAreaWindow->ScreenToOutputPixel( pContainerWindow->OutputToScreenPixel( ::Point( 0, nPosY ))).Y();
+ }
+
+ // Set virtual position
+ rUIElement.m_aDockedData.m_aPos.X = nRowCol;
+ rUIElement.m_aDockedData.m_aPos.Y = nDockPosY;
+ }
+
+ return aTrackingRect;
+}
+
+void ToolbarLayoutManager::implts_setTrackingRect( ui::DockingArea eDockingArea, const ::Point& rMousePos, ::tools::Rectangle& rTrackingRect )
+{
+ ::Point aPoint( rTrackingRect.TopLeft());
+ if ( isHorizontalDockingArea( eDockingArea ))
+ aPoint.setX( rMousePos.X() );
+ else
+ aPoint.setY( rMousePos.Y() );
+ rTrackingRect.SetPos( aPoint );
+}
+
+void ToolbarLayoutManager::implts_renumberRowColumnData(
+ ui::DockingArea eDockingArea,
+ const UIElement& rUIElement )
+{
+ SolarMutexClearableGuard aReadLock;
+ uno::Reference< container::XNameAccess > xPersistentWindowState( m_xPersistentWindowState );
+ aReadLock.clear();
+
+ bool bHorzDockingArea( isHorizontalDockingArea( eDockingArea ));
+ sal_Int32 nRowCol( bHorzDockingArea ? rUIElement.m_aDockedData.m_aPos.Y : rUIElement.m_aDockedData.m_aPos.X );
+
+ /* SAFE AREA ----------------------------------------------------------------------------------------------- */
+ {
+ SolarMutexGuard aWriteLock;
+ for (auto& elem : m_aUIElements)
+ {
+ if ((elem.m_aDockedData.m_nDockedArea == eDockingArea)
+ && (elem.m_aName != rUIElement.m_aName))
+ {
+ // Don't change toolbars without a valid docking position!
+ if (isDefaultPos(elem.m_aDockedData.m_aPos))
+ continue;
+
+ sal_Int32 nWindowRowCol
+ = bHorzDockingArea ? elem.m_aDockedData.m_aPos.Y : elem.m_aDockedData.m_aPos.X;
+ if (nWindowRowCol >= nRowCol)
+ {
+ if (bHorzDockingArea)
+ elem.m_aDockedData.m_aPos.Y += 1;
+ else
+ elem.m_aDockedData.m_aPos.X += 1;
+ }
+ }
+ }
+ }
+ /* SAFE AREA ----------------------------------------------------------------------------------------------- */
+
+ // We have to change the persistent window state part
+ if ( !xPersistentWindowState.is() )
+ return;
+
+ try
+ {
+ const uno::Sequence< OUString > aWindowElements = xPersistentWindowState->getElementNames();
+ for ( OUString const & rWindowElementName : aWindowElements )
+ {
+ if ( rUIElement.m_aName != rWindowElementName )
+ {
+ try
+ {
+ uno::Sequence< beans::PropertyValue > aPropValueSeq;
+ awt::Point aDockedPos;
+ ui::DockingArea nDockedArea( ui::DockingArea_DOCKINGAREA_DEFAULT );
+
+ xPersistentWindowState->getByName( rWindowElementName ) >>= aPropValueSeq;
+ for ( beans::PropertyValue const & rProp : std::as_const(aPropValueSeq) )
+ {
+ if ( rProp.Name == WINDOWSTATE_PROPERTY_DOCKINGAREA )
+ rProp.Value >>= nDockedArea;
+ else if ( rProp.Name == WINDOWSTATE_PROPERTY_DOCKPOS )
+ rProp.Value >>= aDockedPos;
+ }
+
+ // Don't change toolbars without a valid docking position!
+ if ( isDefaultPos( aDockedPos ))
+ continue;
+
+ sal_Int32 nWindowRowCol = bHorzDockingArea ? aDockedPos.Y : aDockedPos.X;
+ if (( nDockedArea == eDockingArea ) && ( nWindowRowCol >= nRowCol ))
+ {
+ if ( bHorzDockingArea )
+ aDockedPos.Y += 1;
+ else
+ aDockedPos.X += 1;
+
+ uno::Reference< container::XNameReplace > xReplace( xPersistentWindowState, uno::UNO_QUERY );
+ xReplace->replaceByName( rWindowElementName, css::uno::Any( aPropValueSeq ));
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ }
+ }
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ }
+}
+
+// XWindowListener
+
+void SAL_CALL ToolbarLayoutManager::windowResized( const awt::WindowEvent& aEvent )
+{
+ SolarMutexClearableGuard aWriteLock;
+ bool bLocked( m_bDockingInProgress );
+ bool bLayoutInProgress( m_bLayoutInProgress );
+ aWriteLock.clear();
+
+ // Do not do anything if we are in the middle of a docking process. This would interfere all other
+ // operations. We will store the new position and size in the docking handlers.
+ // Do not do anything if we are in the middle of our layouting process. We will adapt the position
+ // and size of the user interface elements.
+ if ( bLocked || bLayoutInProgress )
+ return;
+
+ bool bNotify( false );
+ uno::Reference< awt::XWindow > xWindow( aEvent.Source, uno::UNO_QUERY );
+
+ UIElement aUIElement = implts_findToolbar( aEvent.Source );
+ if ( aUIElement.m_xUIElement.is() )
+ {
+ if ( aUIElement.m_bFloating )
+ {
+ uno::Reference< awt::XWindow2 > xWindow2( xWindow, uno::UNO_QUERY );
+
+ if( xWindow2.is() )
+ {
+ awt::Rectangle aPos = xWindow2->getPosSize();
+ awt::Size aSize = xWindow2->getOutputSize(); // always use output size for consistency
+ bool bVisible = xWindow2->isVisible();
+
+ // update element data
+ aUIElement.m_aFloatingData.m_aPos = awt::Point(aPos.X, aPos.Y);
+ aUIElement.m_aFloatingData.m_aSize = aSize;
+ aUIElement.m_bVisible = bVisible;
+ }
+
+ implts_writeWindowStateData( aUIElement );
+ }
+ else
+ {
+ implts_setLayoutDirty();
+ bNotify = true;
+ }
+ }
+
+ if ( bNotify )
+ m_pParentLayouter->requestLayout();
+}
+
+void SAL_CALL ToolbarLayoutManager::windowMoved( const awt::WindowEvent& /*aEvent*/ )
+{
+}
+
+void SAL_CALL ToolbarLayoutManager::windowShown( const lang::EventObject& /*aEvent*/ )
+{
+}
+
+void SAL_CALL ToolbarLayoutManager::windowHidden( const lang::EventObject& /*aEvent*/ )
+{
+}
+
+// XDockableWindowListener
+
+void SAL_CALL ToolbarLayoutManager::startDocking( const awt::DockingEvent& e )
+{
+ bool bWinFound( false );
+
+ SolarMutexClearableGuard aReadGuard;
+ uno::Reference< awt::XWindow2 > xWindow( e.Source, uno::UNO_QUERY );
+ aReadGuard.clear();
+
+ UIElement aUIElement = implts_findToolbar( e.Source );
+
+ if ( aUIElement.m_xUIElement.is() && xWindow.is() )
+ {
+ bWinFound = true;
+ uno::Reference< awt::XDockableWindow > xDockWindow( xWindow, uno::UNO_QUERY );
+ if ( xDockWindow->isFloating() )
+ {
+ awt::Rectangle aPos = xWindow->getPosSize();
+ awt::Size aSize = xWindow->getOutputSize();
+
+ aUIElement.m_aFloatingData.m_aPos = awt::Point(aPos.X, aPos.Y);
+ aUIElement.m_aFloatingData.m_aSize = aSize;
+
+ SolarMutexGuard aGuard;
+
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow );
+ if ( pWindow && pWindow->GetType() == WindowType::TOOLBOX )
+ {
+ ToolBox* pToolBox = static_cast<ToolBox *>(pWindow.get());
+ aUIElement.m_aFloatingData.m_nLines = pToolBox->GetFloatingLines();
+ aUIElement.m_aFloatingData.m_bIsHorizontal = isToolboxHorizontalAligned( pToolBox );
+ }
+ }
+ }
+
+ SolarMutexGuard g;
+ m_bDockingInProgress = bWinFound;
+ m_aDockUIElement = aUIElement;
+ m_aDockUIElement.m_bUserActive = true;
+}
+
+awt::DockingData SAL_CALL ToolbarLayoutManager::docking( const awt::DockingEvent& e )
+{
+ constexpr sal_Int32 MAGNETIC_DISTANCE_UNDOCK = 25;
+ constexpr sal_Int32 MAGNETIC_DISTANCE_DOCK = 20;
+
+ SolarMutexClearableGuard aReadLock;
+ awt::DockingData aDockingData;
+ uno::Reference< awt::XDockableWindow > xDockWindow( e.Source, uno::UNO_QUERY );
+ uno::Reference< awt::XWindow > xWindow( e.Source, uno::UNO_QUERY );
+ uno::Reference< awt::XWindow > xTopDockingWindow( m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_TOP)] );
+ uno::Reference< awt::XWindow > xLeftDockingWindow( m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_LEFT)] );
+ uno::Reference< awt::XWindow > xRightDockingWindow( m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_RIGHT)] );
+ uno::Reference< awt::XWindow > xBottomDockingWindow( m_xDockAreaWindows[int(ui::DockingArea_DOCKINGAREA_BOTTOM)] );
+ uno::Reference< awt::XWindow2 > xContainerWindow( m_xContainerWindow );
+ UIElement aUIDockingElement( m_aDockUIElement );
+
+ bool bDockingInProgress( m_bDockingInProgress );
+ aReadLock.clear();
+
+ if ( bDockingInProgress )
+ aDockingData.TrackingRectangle = e.TrackingRectangle;
+
+ if ( bDockingInProgress && xDockWindow.is() && xWindow.is() )
+ {
+ try
+ {
+ SolarMutexGuard aGuard;
+
+ DockingOperation eDockingOperation( DOCKOP_ON_COLROW );
+ ui::DockingArea eDockingArea( ui::DockingArea(-1) ); // none
+ sal_Int32 nMagneticZone( aUIDockingElement.m_bFloating ? MAGNETIC_DISTANCE_DOCK : MAGNETIC_DISTANCE_UNDOCK );
+ ::tools::Rectangle aTrackingRect( e.TrackingRectangle.X, e.TrackingRectangle.Y,
+ ( e.TrackingRectangle.X + e.TrackingRectangle.Width ),
+ ( e.TrackingRectangle.Y + e.TrackingRectangle.Height ));
+
+ awt::Rectangle aTmpRect = xTopDockingWindow->getPosSize();
+ ::tools::Rectangle aTopDockRect( aTmpRect.X, aTmpRect.Y, aTmpRect.Width, aTmpRect.Height );
+ ::tools::Rectangle aHotZoneTopDockRect( implts_calcHotZoneRect( aTopDockRect, nMagneticZone ));
+
+ aTmpRect = xBottomDockingWindow->getPosSize();
+ ::tools::Rectangle aBottomDockRect( aTmpRect.X, aTmpRect.Y, ( aTmpRect.X + aTmpRect.Width), ( aTmpRect.Y + aTmpRect.Height ));
+ ::tools::Rectangle aHotZoneBottomDockRect( implts_calcHotZoneRect( aBottomDockRect, nMagneticZone ));
+
+ aTmpRect = xLeftDockingWindow->getPosSize();
+ ::tools::Rectangle aLeftDockRect( aTmpRect.X, aTmpRect.Y, ( aTmpRect.X + aTmpRect.Width ), ( aTmpRect.Y + aTmpRect.Height ));
+ ::tools::Rectangle aHotZoneLeftDockRect( implts_calcHotZoneRect( aLeftDockRect, nMagneticZone ));
+
+ aTmpRect = xRightDockingWindow->getPosSize();
+ ::tools::Rectangle aRightDockRect( aTmpRect.X, aTmpRect.Y, ( aTmpRect.X + aTmpRect.Width ), ( aTmpRect.Y + aTmpRect.Height ));
+ ::tools::Rectangle aHotZoneRightDockRect( implts_calcHotZoneRect( aRightDockRect, nMagneticZone ));
+
+ VclPtr<vcl::Window> pContainerWindow( VCLUnoHelper::GetWindow( xContainerWindow ) );
+ ::Point aMousePos( pContainerWindow->ScreenToOutputPixel( ::Point( e.MousePos.X, e.MousePos.Y )));
+
+ if ( aHotZoneTopDockRect.Contains( aMousePos ))
+ eDockingArea = ui::DockingArea_DOCKINGAREA_TOP;
+ else if ( aHotZoneBottomDockRect.Contains( aMousePos ))
+ eDockingArea = ui::DockingArea_DOCKINGAREA_BOTTOM;
+ else if ( aHotZoneLeftDockRect.Contains( aMousePos ))
+ eDockingArea = ui::DockingArea_DOCKINGAREA_LEFT;
+ else if ( aHotZoneRightDockRect.Contains( aMousePos ))
+ eDockingArea = ui::DockingArea_DOCKINGAREA_RIGHT;
+
+ // Higher priority for movements inside the real docking area
+ if ( aTopDockRect.Contains( aMousePos ))
+ eDockingArea = ui::DockingArea_DOCKINGAREA_TOP;
+ else if ( aBottomDockRect.Contains( aMousePos ))
+ eDockingArea = ui::DockingArea_DOCKINGAREA_BOTTOM;
+ else if ( aLeftDockRect.Contains( aMousePos ))
+ eDockingArea = ui::DockingArea_DOCKINGAREA_LEFT;
+ else if ( aRightDockRect.Contains( aMousePos ))
+ eDockingArea = ui::DockingArea_DOCKINGAREA_RIGHT;
+
+ // Determine if we have a toolbar and set alignment according to the docking area!
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow );
+ ToolBox* pToolBox = nullptr;
+ if ( pWindow && pWindow->GetType() == WindowType::TOOLBOX )
+ pToolBox = static_cast<ToolBox *>(pWindow.get());
+
+ if ( eDockingArea != ui::DockingArea(-1) )
+ {
+ if ( eDockingArea == ui::DockingArea_DOCKINGAREA_TOP )
+ {
+ aUIDockingElement.m_aDockedData.m_nDockedArea = ui::DockingArea_DOCKINGAREA_TOP;
+ aUIDockingElement.m_bFloating = false;
+ }
+ else if ( eDockingArea == ui::DockingArea_DOCKINGAREA_BOTTOM )
+ {
+ aUIDockingElement.m_aDockedData.m_nDockedArea = ui::DockingArea_DOCKINGAREA_BOTTOM;
+ aUIDockingElement.m_bFloating = false;
+ }
+ else if ( eDockingArea == ui::DockingArea_DOCKINGAREA_LEFT )
+ {
+ aUIDockingElement.m_aDockedData.m_nDockedArea = ui::DockingArea_DOCKINGAREA_LEFT;
+ aUIDockingElement.m_bFloating = false;
+ }
+ else if ( eDockingArea == ui::DockingArea_DOCKINGAREA_RIGHT )
+ {
+ aUIDockingElement.m_aDockedData.m_nDockedArea = ui::DockingArea_DOCKINGAREA_RIGHT;
+ aUIDockingElement.m_bFloating = false;
+ }
+
+ ::Point aOutputPos = pContainerWindow->ScreenToOutputPixel( aTrackingRect.TopLeft() );
+ aTrackingRect.SetPos( aOutputPos );
+
+ ::tools::Rectangle aNewDockingRect( aTrackingRect );
+
+ implts_calcDockingPosSize( aUIDockingElement, eDockingOperation, aNewDockingRect, aMousePos );
+
+ ::Point aScreenPos = pContainerWindow->OutputToScreenPixel( aNewDockingRect.TopLeft() );
+ aDockingData.TrackingRectangle = awt::Rectangle( aScreenPos.X(), aScreenPos.Y(),
+ aNewDockingRect.getWidth(), aNewDockingRect.getHeight() );
+ }
+ else if (pToolBox)
+ {
+ bool bIsHorizontal = isToolboxHorizontalAligned( pToolBox );
+ awt::Size aFloatSize = aUIDockingElement.m_aFloatingData.m_aSize;
+ if ( aFloatSize.Width > 0 && aFloatSize.Height > 0 )
+ {
+ aUIDockingElement.m_aFloatingData.m_aPos = AWTPoint(pContainerWindow->ScreenToOutputPixel(VCLPoint(e.MousePos)));
+ aDockingData.TrackingRectangle.Height = aFloatSize.Height;
+ aDockingData.TrackingRectangle.Width = aFloatSize.Width;
+ }
+ else
+ {
+ aFloatSize = AWTSize(pToolBox->CalcWindowSizePixel());
+ if ( !bIsHorizontal )
+ {
+ // Floating toolbars are always horizontal aligned! We have to swap
+ // width/height if we have a vertical aligned toolbar.
+ sal_Int32 nTemp = aFloatSize.Height;
+ aFloatSize.Height = aFloatSize.Width;
+ aFloatSize.Width = nTemp;
+ }
+
+ aDockingData.TrackingRectangle.Height = aFloatSize.Height;
+ aDockingData.TrackingRectangle.Width = aFloatSize.Width;
+
+ // For the first time we don't have any data about the floating size of a toolbar.
+ // We calculate it and store it for later use.
+ aUIDockingElement.m_aFloatingData.m_aPos = AWTPoint(pContainerWindow->ScreenToOutputPixel(VCLPoint(e.MousePos)));
+ aUIDockingElement.m_aFloatingData.m_aSize = aFloatSize;
+ aUIDockingElement.m_aFloatingData.m_nLines = pToolBox->GetFloatingLines();
+ aUIDockingElement.m_aFloatingData.m_bIsHorizontal = isToolboxHorizontalAligned( pToolBox );
+ }
+ aDockingData.TrackingRectangle.X = e.MousePos.X;
+ aDockingData.TrackingRectangle.Y = e.MousePos.Y;
+ }
+
+ aDockingData.bFloating = ( eDockingArea == ui::DockingArea(-1) );
+
+ // Write current data to the member docking progress data
+ SolarMutexGuard g;
+ m_aDockUIElement.m_bFloating = aDockingData.bFloating;
+ if ( !aDockingData.bFloating )
+ {
+ m_aDockUIElement.m_aDockedData = aUIDockingElement.m_aDockedData;
+
+ m_eDockOperation = eDockingOperation;
+ }
+ else
+ m_aDockUIElement.m_aFloatingData = aUIDockingElement.m_aFloatingData;
+ }
+ catch (const uno::Exception&)
+ {
+ }
+ }
+
+ return aDockingData;
+}
+
+void SAL_CALL ToolbarLayoutManager::endDocking( const awt::EndDockingEvent& e )
+{
+ if (e.bCancelled)
+ return;
+
+ bool bDockingInProgress( false );
+ bool bStartDockFloated( false );
+ bool bFloating( false );
+ UIElement aUIDockingElement;
+
+ /* SAFE AREA ----------------------------------------------------------------------------------------------- */
+ SolarMutexResettableGuard aWriteLock;
+ bDockingInProgress = m_bDockingInProgress;
+ aUIDockingElement = m_aDockUIElement;
+ bFloating = aUIDockingElement.m_bFloating;
+
+ UIElement& rUIElement = impl_findToolbar( aUIDockingElement.m_aName );
+ if ( rUIElement.m_aName == aUIDockingElement.m_aName )
+ {
+ if ( aUIDockingElement.m_bFloating )
+ {
+ // Write last position into position data
+ uno::Reference< awt::XWindow > xWindow( aUIDockingElement.m_xUIElement->getRealInterface(), uno::UNO_QUERY );
+ rUIElement.m_aFloatingData = aUIDockingElement.m_aFloatingData;
+ awt::Rectangle aTmpRect = xWindow->getPosSize();
+ rUIElement.m_aFloatingData.m_aPos = awt::Point(aTmpRect.X, aTmpRect.Y);
+ // make changes also for our local data as we use it to make data persistent
+ aUIDockingElement.m_aFloatingData = rUIElement.m_aFloatingData;
+ }
+ else
+ {
+ rUIElement.m_aDockedData = aUIDockingElement.m_aDockedData;
+ rUIElement.m_aFloatingData.m_aSize = aUIDockingElement.m_aFloatingData.m_aSize;
+
+ if ( m_eDockOperation != DOCKOP_ON_COLROW )
+ {
+ // we have to renumber our row/column data to insert a new row/column
+ implts_renumberRowColumnData(aUIDockingElement.m_aDockedData.m_nDockedArea, aUIDockingElement );
+ }
+ }
+
+ bStartDockFloated = rUIElement.m_bFloating;
+ rUIElement.m_bFloating = m_aDockUIElement.m_bFloating;
+ rUIElement.m_bUserActive = true;
+ }
+
+ // reset member for next docking operation
+ m_aDockUIElement.m_xUIElement.clear();
+ m_eDockOperation = DOCKOP_ON_COLROW;
+ aWriteLock.clear();
+ /* SAFE AREA ----------------------------------------------------------------------------------------------- */
+
+ implts_writeWindowStateData( aUIDockingElement );
+
+ if ( bDockingInProgress )
+ {
+ SolarMutexGuard aGuard;
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( uno::Reference< awt::XWindow >( e.Source, uno::UNO_QUERY ));
+ ToolBox* pToolBox = nullptr;
+ if ( pWindow && pWindow->GetType() == WindowType::TOOLBOX )
+ pToolBox = static_cast<ToolBox *>(pWindow.get());
+
+ if ( pToolBox )
+ {
+ if( e.bFloating )
+ {
+ if ( aUIDockingElement.m_aFloatingData.m_bIsHorizontal )
+ pToolBox->SetAlign();
+ else
+ pToolBox->SetAlign( WindowAlign::Left );
+ }
+ else
+ {
+ ::Size aSize;
+
+ pToolBox->SetAlign( ImplConvertAlignment( aUIDockingElement.m_aDockedData.m_nDockedArea) );
+
+ // Docked toolbars have always one line
+ aSize = pToolBox->CalcWindowSizePixel( 1 );
+
+ // Lock layouting updates as our listener would be called due to SetSizePixel
+ pToolBox->SetOutputSizePixel( aSize );
+ }
+ }
+ }
+
+ implts_sortUIElements();
+
+ aWriteLock.reset();
+ m_bDockingInProgress = false;
+ m_bLayoutDirty = !bStartDockFloated || !bFloating;
+ bool bNotify = m_bLayoutDirty;
+ aWriteLock.clear();
+
+ if ( bNotify )
+ m_pParentLayouter->requestLayout();
+}
+
+sal_Bool SAL_CALL ToolbarLayoutManager::prepareToggleFloatingMode( const lang::EventObject& e )
+{
+ SolarMutexClearableGuard aReadLock;
+ bool bDockingInProgress = m_bDockingInProgress;
+ aReadLock.clear();
+
+ UIElement aUIDockingElement = implts_findToolbar( e.Source );
+ bool bWinFound( !aUIDockingElement.m_aName.isEmpty() );
+ uno::Reference< awt::XWindow > xWindow( e.Source, uno::UNO_QUERY );
+
+ if ( !bWinFound || !xWindow.is() )
+ return true;
+
+ if ( bDockingInProgress )
+ return true;
+
+ uno::Reference< awt::XDockableWindow > xDockWindow( xWindow, uno::UNO_QUERY );
+ if ( !xDockWindow->isFloating() )
+ return true;
+
+ {
+ SolarMutexGuard aGuard;
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow );
+ if ( pWindow && pWindow->GetType() == WindowType::TOOLBOX )
+ {
+ ToolBox* pToolBox = static_cast< ToolBox *>( pWindow.get() );
+ aUIDockingElement.m_aFloatingData.m_aPos = AWTPoint(pToolBox->GetPosPixel());
+ aUIDockingElement.m_aFloatingData.m_aSize = AWTSize(pToolBox->GetOutputSizePixel());
+ aUIDockingElement.m_aFloatingData.m_nLines = pToolBox->GetFloatingLines();
+ aUIDockingElement.m_aFloatingData.m_bIsHorizontal = isToolboxHorizontalAligned( pToolBox );
+ }
+ }
+
+ UIElement aUIElement = implts_findToolbar( aUIDockingElement.m_aName );
+ if ( aUIElement.m_aName == aUIDockingElement.m_aName )
+ implts_setToolbar( aUIDockingElement );
+
+ return true;
+}
+
+void SAL_CALL ToolbarLayoutManager::toggleFloatingMode( const lang::EventObject& e )
+{
+ UIElement aUIDockingElement;
+
+ SolarMutexResettableGuard aReadLock;
+ bool bDockingInProgress( m_bDockingInProgress );
+ if ( bDockingInProgress )
+ aUIDockingElement = m_aDockUIElement;
+ aReadLock.clear();
+
+ vcl::Window* pWindow( nullptr );
+ ToolBox* pToolBox( nullptr );
+ uno::Reference< awt::XWindow2 > xWindow;
+
+ {
+ SolarMutexGuard aGuard;
+ xWindow.set( e.Source, uno::UNO_QUERY );
+ pWindow = VCLUnoHelper::GetWindow( xWindow );
+
+ if ( pWindow && pWindow->GetType() == WindowType::TOOLBOX )
+ pToolBox = static_cast<ToolBox *>(pWindow);
+ }
+
+ if ( !bDockingInProgress )
+ {
+ aUIDockingElement = implts_findToolbar( e.Source );
+ bool bWinFound = !aUIDockingElement.m_aName.isEmpty();
+
+ if ( bWinFound && xWindow.is() )
+ {
+ aUIDockingElement.m_bFloating = !aUIDockingElement.m_bFloating;
+ aUIDockingElement.m_bUserActive = true;
+
+ implts_setLayoutInProgress();
+ if ( aUIDockingElement.m_bFloating )
+ {
+ SolarMutexGuard aGuard;
+ if ( pToolBox )
+ {
+ pToolBox->SetLineCount( aUIDockingElement.m_aFloatingData.m_nLines );
+ if ( aUIDockingElement.m_aFloatingData.m_bIsHorizontal )
+ pToolBox->SetAlign();
+ else
+ pToolBox->SetAlign( WindowAlign::Left );
+ }
+
+ bool bUndefPos = hasDefaultPosValue( aUIDockingElement.m_aFloatingData.m_aPos );
+ bool bSetSize = !hasEmptySize( aUIDockingElement.m_aFloatingData.m_aSize );
+
+ if ( bUndefPos )
+ aUIDockingElement.m_aFloatingData.m_aPos = implts_findNextCascadeFloatingPos();
+
+ if ( !bSetSize )
+ {
+ if ( pToolBox )
+ aUIDockingElement.m_aFloatingData.m_aSize = AWTSize(pToolBox->CalcFloatingWindowSizePixel());
+ else if ( pWindow )
+ aUIDockingElement.m_aFloatingData.m_aSize = AWTSize(pWindow->GetOutputSizePixel());
+ }
+
+ xWindow->setPosSize( aUIDockingElement.m_aFloatingData.m_aPos.X,
+ aUIDockingElement.m_aFloatingData.m_aPos.Y,
+ 0, 0, awt::PosSize::POS );
+ xWindow->setOutputSize(aUIDockingElement.m_aFloatingData.m_aSize);
+ }
+ else
+ {
+ if ( isDefaultPos( aUIDockingElement.m_aDockedData.m_aPos ))
+ {
+ // Docking on its default position without a preset position -
+ // we have to find a good place for it.
+ ::Point aPixelPos;
+ awt::Point aDockPos;
+ ::Size aSize;
+
+ {
+ SolarMutexGuard aGuard;
+ if ( pToolBox )
+ aSize = pToolBox->CalcWindowSizePixel( 1, ImplConvertAlignment( aUIDockingElement.m_aDockedData.m_nDockedArea ) );
+ else if ( pWindow )
+ aSize = pWindow->GetSizePixel();
+ }
+
+ implts_findNextDockingPos(aUIDockingElement.m_aDockedData.m_nDockedArea, aSize, aDockPos, aPixelPos );
+ aUIDockingElement.m_aDockedData.m_aPos = aDockPos;
+ }
+
+ SolarMutexGuard aGuard;
+ if ( pToolBox )
+ {
+ pToolBox->SetAlign( ImplConvertAlignment( aUIDockingElement.m_aDockedData.m_nDockedArea) );
+ ::Size aSize = pToolBox->CalcWindowSizePixel( 1 );
+ awt::Rectangle aRect = xWindow->getPosSize();
+ xWindow->setPosSize( aRect.X, aRect.Y, 0, 0, awt::PosSize::POS );
+ xWindow->setOutputSize( AWTSize( aSize ) );
+ }
+ }
+
+ implts_setLayoutInProgress( false );
+ implts_setToolbar( aUIDockingElement );
+ implts_writeWindowStateData( aUIDockingElement );
+ implts_sortUIElements();
+ implts_setLayoutDirty();
+
+ aReadLock.reset();
+ LayoutManager* pParentLayouter( m_pParentLayouter );
+ aReadLock.clear();
+
+ if ( pParentLayouter )
+ pParentLayouter->requestLayout();
+ }
+ }
+ else
+ {
+ SolarMutexGuard aGuard;
+ if ( pToolBox )
+ {
+ if ( aUIDockingElement.m_bFloating )
+ {
+ if ( aUIDockingElement.m_aFloatingData.m_bIsHorizontal )
+ pToolBox->SetAlign();
+ else
+ pToolBox->SetAlign( WindowAlign::Left );
+ }
+ else
+ pToolBox->SetAlign( ImplConvertAlignment( aUIDockingElement.m_aDockedData.m_nDockedArea) );
+ }
+ }
+}
+
+void SAL_CALL ToolbarLayoutManager::closed( const lang::EventObject& e )
+{
+ OUString aName;
+ UIElement aUIElement;
+
+ {
+ SolarMutexGuard aWriteLock;
+ for (auto& elem : m_aUIElements)
+ {
+ uno::Reference<ui::XUIElement> xUIElement(elem.m_xUIElement);
+ if (xUIElement.is())
+ {
+ uno::Reference<uno::XInterface> xIfac(xUIElement->getRealInterface(),
+ uno::UNO_QUERY);
+ if (xIfac == e.Source)
+ {
+ aName = elem.m_aName;
+
+ // user closes a toolbar =>
+ // context sensitive toolbar: only destroy toolbar and store state.
+ // non context sensitive toolbar: make it invisible, store state and destroy it.
+ if (!elem.m_bContextSensitive)
+ elem.m_bVisible = false;
+
+ aUIElement = elem;
+ break;
+ }
+ }
+ }
+ }
+
+ // destroy element
+ if ( aName.isEmpty() )
+ return;
+
+ implts_writeWindowStateData( aUIElement );
+ destroyToolbar( aName );
+
+ SolarMutexClearableGuard aReadLock;
+ bool bLayoutDirty = m_bLayoutDirty;
+ LayoutManager* pParentLayouter( m_pParentLayouter );
+ aReadLock.clear();
+
+ if ( bLayoutDirty && pParentLayouter )
+ pParentLayouter->requestLayout();
+}
+
+void SAL_CALL ToolbarLayoutManager::endPopupMode( const awt::EndPopupModeEvent& /*e*/ )
+{
+}
+
+// XUIConfigurationListener
+
+void SAL_CALL ToolbarLayoutManager::elementInserted( const ui::ConfigurationEvent& rEvent )
+{
+ UIElement aUIElement = implts_findToolbar( rEvent.ResourceURL );
+
+ uno::Reference< ui::XUIElementSettings > xElementSettings( aUIElement.m_xUIElement, uno::UNO_QUERY );
+ if ( xElementSettings.is() )
+ {
+ uno::Reference< beans::XPropertySet > xPropSet( xElementSettings, uno::UNO_QUERY );
+ if ( xPropSet.is() )
+ {
+ if ( rEvent.Source == uno::Reference< uno::XInterface >( m_xDocCfgMgr, uno::UNO_QUERY ))
+ xPropSet->setPropertyValue( "ConfigurationSource", css::uno::Any( m_xDocCfgMgr ));
+ }
+ xElementSettings->updateSettings();
+ }
+ else
+ {
+ OUString aElementType;
+ OUString aElementName;
+ parseResourceURL( rEvent.ResourceURL, aElementType, aElementName );
+ if ( aElementName.indexOf( "custom_" ) != -1 )
+ {
+ // custom toolbar must be directly created, shown and layouted!
+ createToolbar( rEvent.ResourceURL );
+ uno::Reference< ui::XUIElement > xUIElement = getToolbar( rEvent.ResourceURL );
+ if ( xUIElement.is() )
+ {
+ OUString aUIName;
+ uno::Reference< ui::XUIConfigurationManager > xCfgMgr;
+ uno::Reference< beans::XPropertySet > xPropSet;
+
+ try
+ {
+ xCfgMgr.set( rEvent.Source, uno::UNO_QUERY );
+ xPropSet.set( xCfgMgr->getSettings( rEvent.ResourceURL, false ), uno::UNO_QUERY );
+
+ if ( xPropSet.is() )
+ xPropSet->getPropertyValue("UIName") >>= aUIName;
+ }
+ catch (const container::NoSuchElementException&)
+ {
+ }
+ catch (const beans::UnknownPropertyException&)
+ {
+ }
+ catch (const lang::WrappedTargetException&)
+ {
+ }
+
+ {
+ SolarMutexGuard aGuard;
+ vcl::Window* pWindow = getWindowFromXUIElement( xUIElement );
+ if ( pWindow )
+ pWindow->SetText( aUIName );
+ }
+
+ showToolbar( rEvent.ResourceURL );
+ }
+ }
+ }
+}
+
+void SAL_CALL ToolbarLayoutManager::elementRemoved( const ui::ConfigurationEvent& rEvent )
+{
+ SolarMutexClearableGuard aReadLock;
+ uno::Reference< awt::XWindow > xContainerWindow = m_xContainerWindow;
+ uno::Reference< ui::XUIConfigurationManager > xModuleCfgMgr( m_xModuleCfgMgr );
+ uno::Reference< ui::XUIConfigurationManager > xDocCfgMgr( m_xDocCfgMgr );
+ aReadLock.clear();
+
+ UIElement aUIElement = implts_findToolbar( rEvent.ResourceURL );
+ uno::Reference< ui::XUIElementSettings > xElementSettings( aUIElement.m_xUIElement, uno::UNO_QUERY );
+ if ( !xElementSettings.is() )
+ return;
+
+ bool bNoSettings( false );
+ OUString aConfigSourcePropName( "ConfigurationSource" );
+ uno::Reference< uno::XInterface > xElementCfgMgr;
+ uno::Reference< beans::XPropertySet > xPropSet( xElementSettings, uno::UNO_QUERY );
+
+ if ( xPropSet.is() )
+ xPropSet->getPropertyValue( aConfigSourcePropName ) >>= xElementCfgMgr;
+
+ if ( !xElementCfgMgr.is() )
+ return;
+
+ // Check if the same UI configuration manager has changed => check further
+ if ( rEvent.Source == xElementCfgMgr )
+ {
+ // Same UI configuration manager where our element has its settings
+ if ( rEvent.Source == uno::Reference< uno::XInterface >( xDocCfgMgr, uno::UNO_QUERY ))
+ {
+ // document settings removed
+ if ( xModuleCfgMgr->hasSettings( rEvent.ResourceURL ))
+ {
+ xPropSet->setPropertyValue( aConfigSourcePropName, css::uno::Any( xModuleCfgMgr ));
+ xElementSettings->updateSettings();
+ return;
+ }
+ }
+
+ bNoSettings = true;
+ }
+
+ // No settings anymore, element must be destroyed
+ if ( xContainerWindow.is() && bNoSettings )
+ destroyToolbar( rEvent.ResourceURL );
+}
+
+void SAL_CALL ToolbarLayoutManager::elementReplaced( const ui::ConfigurationEvent& rEvent )
+{
+ UIElement aUIElement = implts_findToolbar( rEvent.ResourceURL );
+
+ uno::Reference< ui::XUIElementSettings > xElementSettings( aUIElement.m_xUIElement, uno::UNO_QUERY );
+ if ( !xElementSettings.is() )
+ return;
+
+ uno::Reference< uno::XInterface > xElementCfgMgr;
+ uno::Reference< beans::XPropertySet > xPropSet( xElementSettings, uno::UNO_QUERY );
+
+ if ( xPropSet.is() )
+ xPropSet->getPropertyValue( "ConfigurationSource" ) >>= xElementCfgMgr;
+
+ if ( !xElementCfgMgr.is() )
+ return;
+
+ // Check if the same UI configuration manager has changed => update settings
+ if ( rEvent.Source != xElementCfgMgr )
+ return;
+
+ xElementSettings->updateSettings();
+
+ SolarMutexClearableGuard aWriteLock;
+ bool bNotify = !aUIElement.m_bFloating;
+ m_bLayoutDirty = bNotify;
+ LayoutManager* pParentLayouter( m_pParentLayouter );
+ aWriteLock.clear();
+
+ if ( bNotify && pParentLayouter )
+ pParentLayouter->requestLayout();
+}
+
+uno::Reference< ui::XUIElement > ToolbarLayoutManager::getToolbar( std::u16string_view aName )
+{
+ return implts_findToolbar( aName ).m_xUIElement;
+}
+
+uno::Sequence< uno::Reference< ui::XUIElement > > ToolbarLayoutManager::getToolbars()
+{
+ uno::Sequence< uno::Reference< ui::XUIElement > > aSeq;
+
+ SolarMutexGuard g;
+ if ( !m_aUIElements.empty() )
+ {
+ sal_uInt32 nCount(0);
+ for (auto const& elem : m_aUIElements)
+ {
+ if ( elem.m_xUIElement.is() )
+ {
+ ++nCount;
+ aSeq.realloc( nCount );
+ aSeq.getArray()[nCount-1] = elem.m_xUIElement;
+ }
+ }
+ }
+
+ return aSeq;
+}
+
+bool ToolbarLayoutManager::floatToolbar( std::u16string_view rResourceURL )
+{
+ UIElement aUIElement = implts_findToolbar( rResourceURL );
+ if ( !aUIElement.m_xUIElement.is() )
+ return false;
+
+ try
+ {
+ uno::Reference< awt::XDockableWindow > xDockWindow( aUIElement.m_xUIElement->getRealInterface(), uno::UNO_QUERY );
+ if ( xDockWindow.is() && !xDockWindow->isFloating() )
+ {
+ aUIElement.m_bFloating = true;
+ implts_writeWindowStateData( aUIElement );
+ xDockWindow->setFloatingMode( true );
+
+ implts_setLayoutDirty();
+ implts_setToolbar( aUIElement );
+ return true;
+ }
+ }
+ catch (const lang::DisposedException&)
+ {
+ }
+
+ return false;
+}
+
+bool ToolbarLayoutManager::lockToolbar( std::u16string_view rResourceURL )
+{
+ UIElement aUIElement = implts_findToolbar( rResourceURL );
+ if ( !aUIElement.m_xUIElement.is() )
+ return false;
+
+ try
+ {
+ uno::Reference< awt::XDockableWindow > xDockWindow( aUIElement.m_xUIElement->getRealInterface(), uno::UNO_QUERY );
+ if ( xDockWindow.is() && !xDockWindow->isFloating() && !xDockWindow->isLocked() )
+ {
+ aUIElement.m_aDockedData.m_bLocked = true;
+ implts_writeWindowStateData( aUIElement );
+ xDockWindow->lock();
+
+ implts_setLayoutDirty();
+ implts_setToolbar( aUIElement );
+ return true;
+ }
+ }
+ catch (const lang::DisposedException&)
+ {
+ }
+
+ return false;
+}
+
+bool ToolbarLayoutManager::unlockToolbar( std::u16string_view rResourceURL )
+{
+ UIElement aUIElement = implts_findToolbar( rResourceURL );
+ if ( !aUIElement.m_xUIElement.is() )
+ return false;
+
+ try
+ {
+ uno::Reference< awt::XDockableWindow > xDockWindow( aUIElement.m_xUIElement->getRealInterface(), uno::UNO_QUERY );
+ if ( xDockWindow.is() && !xDockWindow->isFloating() && xDockWindow->isLocked() )
+ {
+ aUIElement.m_aDockedData.m_bLocked = false;
+ implts_writeWindowStateData( aUIElement );
+ xDockWindow->unlock();
+
+ implts_setLayoutDirty();
+ implts_setToolbar( aUIElement );
+ return true;
+ }
+ }
+ catch (const lang::DisposedException&)
+ {
+ }
+
+ return false;
+}
+
+bool ToolbarLayoutManager::isToolbarVisible( std::u16string_view rResourceURL )
+{
+ uno::Reference< awt::XWindow2 > xWindow2( implts_getXWindow( rResourceURL ), uno::UNO_QUERY );
+ return ( xWindow2.is() && xWindow2->isVisible() );
+}
+
+bool ToolbarLayoutManager::isToolbarFloating( std::u16string_view rResourceURL )
+{
+ uno::Reference< awt::XDockableWindow > xDockWindow( implts_getXWindow( rResourceURL ), uno::UNO_QUERY );
+ return ( xDockWindow.is() && xDockWindow->isFloating() );
+}
+
+bool ToolbarLayoutManager::isToolbarDocked( std::u16string_view rResourceURL )
+{
+ return !isToolbarFloating( rResourceURL );
+}
+
+bool ToolbarLayoutManager::isToolbarLocked( std::u16string_view rResourceURL )
+{
+ uno::Reference< awt::XDockableWindow > xDockWindow( implts_getXWindow( rResourceURL ), uno::UNO_QUERY );
+ return ( xDockWindow.is() && xDockWindow->isLocked() );
+}
+
+awt::Size ToolbarLayoutManager::getToolbarSize( std::u16string_view rResourceURL )
+{
+ vcl::Window* pWindow = implts_getWindow( rResourceURL );
+
+ SolarMutexGuard aGuard;
+ if ( pWindow )
+ {
+ ::Size aSize = pWindow->GetSizePixel();
+ awt::Size aWinSize;
+ aWinSize.Width = aSize.Width();
+ aWinSize.Height = aSize.Height();
+ return aWinSize;
+ }
+
+ return awt::Size();
+}
+
+awt::Point ToolbarLayoutManager::getToolbarPos( std::u16string_view rResourceURL )
+{
+ awt::Point aPos;
+ UIElement aUIElement = implts_findToolbar( rResourceURL );
+
+ uno::Reference< awt::XWindow > xWindow( implts_getXWindow( rResourceURL ));
+ if ( xWindow.is() )
+ {
+ if ( aUIElement.m_bFloating )
+ {
+ awt::Rectangle aRect = xWindow->getPosSize();
+ aPos.X = aRect.X;
+ aPos.Y = aRect.Y;
+ }
+ else
+ aPos = aUIElement.m_aDockedData.m_aPos;
+ }
+
+ return aPos;
+}
+
+void ToolbarLayoutManager::setToolbarSize( std::u16string_view rResourceURL, const awt::Size& aSize )
+{
+ uno::Reference< awt::XWindow2 > xWindow( implts_getXWindow( rResourceURL ), uno::UNO_QUERY );
+ uno::Reference< awt::XDockableWindow > xDockWindow( xWindow, uno::UNO_QUERY );
+ UIElement aUIElement = implts_findToolbar( rResourceURL );
+
+ if ( xWindow.is() && xDockWindow.is() && xDockWindow->isFloating() )
+ {
+ xWindow->setOutputSize( aSize );
+ aUIElement.m_aFloatingData.m_aSize = aSize;
+ implts_setToolbar( aUIElement );
+ implts_writeWindowStateData( aUIElement );
+ implts_sortUIElements();
+ }
+}
+
+void ToolbarLayoutManager::setToolbarPos( std::u16string_view rResourceURL, const awt::Point& aPos )
+{
+ uno::Reference< awt::XWindow > xWindow( implts_getXWindow( rResourceURL ));
+ uno::Reference< awt::XDockableWindow > xDockWindow( xWindow, uno::UNO_QUERY );
+ UIElement aUIElement = implts_findToolbar( rResourceURL );
+
+ if ( xWindow.is() && xDockWindow.is() && xDockWindow->isFloating() )
+ {
+ xWindow->setPosSize( aPos.X, aPos.Y, 0, 0, awt::PosSize::POS );
+ aUIElement.m_aFloatingData.m_aPos = aPos;
+ implts_setToolbar( aUIElement );
+ implts_writeWindowStateData( aUIElement );
+ implts_sortUIElements();
+ }
+}
+
+void ToolbarLayoutManager::setToolbarPosSize( std::u16string_view rResourceURL, const awt::Point& aPos, const awt::Size& aSize )
+{
+ setToolbarPos( rResourceURL, aPos );
+ setToolbarSize( rResourceURL, aSize );
+}
+
+} // namespace framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */