/* -*- 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 <memory>
#include <config_feature_desktop.h>

#include <properties.h>
#include <services/layoutmanager.hxx>
#include "helpers.hxx"

#include <framework/sfxhelperfunctions.hxx>
#include <uielement/menubarwrapper.hxx>
#include <uielement/progressbarwrapper.hxx>
#include <uiconfiguration/globalsettings.hxx>
#include <uiconfiguration/windowstateproperties.hxx>
#include "toolbarlayoutmanager.hxx"

#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/PropertyAttribute.hpp>
#include <com/sun/star/frame/ModuleManager.hpp>
#include <com/sun/star/frame/XModel.hpp>
#include <com/sun/star/frame/FrameAction.hpp>
#include <com/sun/star/awt/PosSize.hpp>
#include <com/sun/star/awt/XDevice.hpp>
#include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp>
#include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
#include <com/sun/star/ui/theWindowStateConfiguration.hpp>
#include <com/sun/star/ui/theUIElementFactoryManager.hpp>
#include <com/sun/star/container/XNameReplace.hpp>
#include <com/sun/star/container/XNameContainer.hpp>
#include <com/sun/star/frame/LayoutManagerEvents.hpp>
#include <com/sun/star/frame/XDispatchProvider.hpp>
#include <com/sun/star/frame/DispatchHelper.hpp>
#include <com/sun/star/lang/DisposedException.hpp>
#include <com/sun/star/util/URLTransformer.hpp>

#include <comphelper/lok.hxx>
#include <comphelper/propertyvalue.hxx>
#include <vcl/status.hxx>
#include <vcl/settings.hxx>
#include <vcl/window.hxx>
#include <vcl/svapp.hxx>
#include <toolkit/helper/vclunohelper.hxx>
#include <toolkit/awt/vclxmenu.hxx>
#include <comphelper/uno3.hxx>
#include <officecfg/Office/Compatibility.hxx>

#include <rtl/ref.hxx>
#include <sal/log.hxx>
#include <o3tl/string_view.hxx>

#include <algorithm>

//      using namespace
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::util;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::ui;
using namespace ::com::sun::star::frame;

constexpr OUString STATUS_BAR_ALIAS = u"private:resource/statusbar/statusbar"_ustr;

namespace framework
{

IMPLEMENT_FORWARD_XTYPEPROVIDER2( LayoutManager, LayoutManager_Base, LayoutManager_PBase )
IMPLEMENT_FORWARD_XINTERFACE2( LayoutManager, LayoutManager_Base, LayoutManager_PBase )

LayoutManager::LayoutManager( const Reference< XComponentContext >& xContext ) :
         ::cppu::OBroadcastHelperVar< ::cppu::OMultiTypeInterfaceContainerHelper, ::cppu::OMultiTypeInterfaceContainerHelper::keyType >(m_aMutex)
        , LayoutManager_PBase( *static_cast< ::cppu::OBroadcastHelper* >(this) )
        , m_xContext( xContext )
        , m_xURLTransformer( URLTransformer::create(xContext) )
        , m_nLockCount( 0 )
        , m_bInplaceMenuSet( false )
        , m_bMenuVisible( true )
        , m_bVisible( true )
        , m_bParentWindowVisible( false )
        , m_bMustDoLayout( true )
#if HAVE_FEATURE_DESKTOP
        , m_bAutomaticToolbars( true )
#else
        , m_bAutomaticToolbars( false )
#endif
        , m_bHideCurrentUI( false )
        , m_bGlobalSettings( false )
        , m_bPreserveContentSize( false )
        , m_bMenuBarCloseButton( false )
        , m_xModuleManager( ModuleManager::create( xContext ))
        , m_xUIElementFactoryManager( ui::theUIElementFactoryManager::get(xContext) )
        , m_xPersistentWindowStateSupplier( ui::theWindowStateConfiguration::get( xContext ) )
        , m_aAsyncLayoutTimer( "framework::LayoutManager m_aAsyncLayoutTimer" )
        , m_aListenerContainer( m_aMutex )
        , m_bInSetCurrentUIVisibility( false )
{
    // Initialize statusbar member
    m_aStatusBarElement.m_aType = "statusbar";
    m_aStatusBarElement.m_aName = STATUS_BAR_ALIAS;

    if (!comphelper::LibreOfficeKit::isActive())
    {
        m_xToolbarManager = new ToolbarLayoutManager( xContext, Reference<XUIElementFactory>(m_xUIElementFactoryManager, UNO_QUERY_THROW), this );
    }

    m_aAsyncLayoutTimer.SetPriority( TaskPriority::HIGH_IDLE );
    m_aAsyncLayoutTimer.SetTimeout( 50 );
    m_aAsyncLayoutTimer.SetInvokeHandler( LINK( this, LayoutManager, AsyncLayoutHdl ) );

    registerProperty( LAYOUTMANAGER_PROPNAME_ASCII_AUTOMATICTOOLBARS, LAYOUTMANAGER_PROPHANDLE_AUTOMATICTOOLBARS, css::beans::PropertyAttribute::TRANSIENT, &m_bAutomaticToolbars, cppu::UnoType<decltype(m_bAutomaticToolbars)>::get() );
    registerProperty( LAYOUTMANAGER_PROPNAME_ASCII_HIDECURRENTUI, LAYOUTMANAGER_PROPHANDLE_HIDECURRENTUI, beans::PropertyAttribute::TRANSIENT, &m_bHideCurrentUI, cppu::UnoType<decltype(m_bHideCurrentUI)>::get() );
    registerProperty( LAYOUTMANAGER_PROPNAME_ASCII_LOCKCOUNT, LAYOUTMANAGER_PROPHANDLE_LOCKCOUNT, beans::PropertyAttribute::TRANSIENT | beans::PropertyAttribute::READONLY, &m_nLockCount, cppu::UnoType<decltype(m_nLockCount)>::get()  );
    registerProperty( LAYOUTMANAGER_PROPNAME_MENUBARCLOSER, LAYOUTMANAGER_PROPHANDLE_MENUBARCLOSER, beans::PropertyAttribute::TRANSIENT, &m_bMenuBarCloseButton, cppu::UnoType<decltype(m_bMenuBarCloseButton)>::get() );
    registerPropertyNoMember( LAYOUTMANAGER_PROPNAME_ASCII_REFRESHVISIBILITY, LAYOUTMANAGER_PROPHANDLE_REFRESHVISIBILITY, beans::PropertyAttribute::TRANSIENT, cppu::UnoType<bool>::get(), css::uno::Any(false) );
    registerProperty( LAYOUTMANAGER_PROPNAME_ASCII_PRESERVE_CONTENT_SIZE, LAYOUTMANAGER_PROPHANDLE_PRESERVE_CONTENT_SIZE, beans::PropertyAttribute::TRANSIENT, &m_bPreserveContentSize, cppu::UnoType<decltype(m_bPreserveContentSize)>::get() );
    registerPropertyNoMember( LAYOUTMANAGER_PROPNAME_ASCII_REFRESHTOOLTIP, LAYOUTMANAGER_PROPHANDLE_REFRESHTOOLTIP, beans::PropertyAttribute::TRANSIENT, cppu::UnoType<bool>::get(), css::uno::Any(false) );
}

LayoutManager::~LayoutManager()
{
    m_aAsyncLayoutTimer.Stop();
    setDockingAreaAcceptor(nullptr);
    m_pGlobalSettings.reset();
}

void LayoutManager::implts_createMenuBar(const OUString& rMenuBarName)
{
    SolarMutexGuard aWriteLock;

    // Create a customized menu if compatibility mode is on
    if (m_aModuleIdentifier == "com.sun.star.text.TextDocument" && officecfg::Office::Compatibility::View::MSCompatibleFormsMenu::get())
    {
        implts_createMSCompatibleMenuBar(rMenuBarName);
    }

    // Create the default menubar otherwise
    if (m_bInplaceMenuSet || m_xMenuBar.is())
        return;

    m_xMenuBar.set( static_cast< MenuBarWrapper* >(implts_createElement( rMenuBarName ).get()) );
    if ( !m_xMenuBar.is() )
        return;

    SystemWindow* pSysWindow = getTopSystemWindow( m_xContainerWindow );
    if ( !pSysWindow )
        return;

    Reference< awt::XMenuBar > xMenuBar;

    try
    {
        m_xMenuBar->getPropertyValue(u"XMenuBar"_ustr) >>= xMenuBar;
    }
    catch (const beans::UnknownPropertyException&)
    {
    }
    catch (const lang::WrappedTargetException&)
    {
    }

    if ( !xMenuBar.is() )
        return;

    VCLXMenu* pAwtMenuBar = dynamic_cast<VCLXMenu*>( xMenuBar.get() );
    if ( pAwtMenuBar )
    {
        MenuBar* pMenuBar = static_cast<MenuBar*>(pAwtMenuBar->GetMenu());
        if ( pMenuBar )
        {
            pSysWindow->SetMenuBar(pMenuBar);
            pMenuBar->SetDisplayable( m_bMenuVisible );
            implts_updateMenuBarClose();
        }
    }
}

// Internal helper function
void LayoutManager::impl_clearUpMenuBar()
{
    implts_lock();

    // Clear up VCL menu bar to prepare shutdown
    if ( m_xContainerWindow.is() )
    {
        SolarMutexGuard aGuard;

        SystemWindow* pSysWindow = getTopSystemWindow( m_xContainerWindow );
        if ( pSysWindow )
        {
            MenuBar* pSetMenuBar = nullptr;
            if ( m_xInplaceMenuBar.is() )
                pSetMenuBar = static_cast<MenuBar *>(m_xInplaceMenuBar->GetMenuBar());
            else
            {
                Reference< awt::XMenuBar > xMenuBar;

                if ( m_xMenuBar.is() )
                {
                    try
                    {
                        m_xMenuBar->getPropertyValue(u"XMenuBar"_ustr) >>= xMenuBar;
                    }
                    catch (const beans::UnknownPropertyException&)
                    {
                    }
                    catch (const lang::WrappedTargetException&)
                    {
                    }
                }

                VCLXMenu* pAwtMenuBar = dynamic_cast<VCLXMenu*>( xMenuBar.get() );
                if ( pAwtMenuBar )
                    pSetMenuBar = static_cast<MenuBar*>(pAwtMenuBar->GetMenu());
            }

            MenuBar* pTopMenuBar = pSysWindow->GetMenuBar();
            if ( pSetMenuBar == pTopMenuBar )
                pSysWindow->SetMenuBar( nullptr );
        }
    }

    // reset inplace menubar manager
    VclPtr<Menu> pMenuBar;
    if (m_xInplaceMenuBar.is())
    {
        pMenuBar = m_xInplaceMenuBar->GetMenuBar();
        m_xInplaceMenuBar->dispose();
        m_xInplaceMenuBar.clear();
    }
    pMenuBar.disposeAndClear();
    m_bInplaceMenuSet = false;

    if ( m_xMenuBar.is() )
    {
        m_xMenuBar->dispose();
        m_xMenuBar.clear();
    }
    implts_unlock();
}

void LayoutManager::implts_lock()
{
    SolarMutexGuard g;
    ++m_nLockCount;
}

bool LayoutManager::implts_unlock()
{
    SolarMutexGuard g;
    m_nLockCount = std::max( m_nLockCount-1, static_cast<sal_Int32>(0) );
    return ( m_nLockCount == 0 );
}

void LayoutManager::implts_reset( bool bAttached )
{
    /* SAFE AREA ----------------------------------------------------------------------------------------------- */
    SolarMutexClearableGuard aReadLock;
    Reference< XFrame > xFrame = m_xFrame;
    Reference< awt::XWindow > xContainerWindow( m_xContainerWindow );
    Reference< XUIConfiguration > xModuleCfgMgr( m_xModuleCfgMgr, UNO_QUERY );
    Reference< XUIConfiguration > xDocCfgMgr( m_xDocCfgMgr, UNO_QUERY );
    Reference< XNameAccess > xPersistentWindowState( m_xPersistentWindowState );
    Reference< XComponentContext > xContext( m_xContext );
    Reference< XNameAccess > xPersistentWindowStateSupplier( m_xPersistentWindowStateSupplier );
    rtl::Reference<ToolbarLayoutManager> xToolbarManager( m_xToolbarManager );
    OUString aModuleIdentifier( m_aModuleIdentifier );
    bool bAutomaticToolbars( m_bAutomaticToolbars );
    aReadLock.clear();
    /* SAFE AREA ----------------------------------------------------------------------------------------------- */

    implts_lock();

    Reference< XModel > xModel;
    if ( xFrame.is() )
    {
        if ( bAttached )
        {
            OUString aOldModuleIdentifier( aModuleIdentifier );
            try
            {
                aModuleIdentifier = m_xModuleManager->identify( xFrame );
            }
            catch( const Exception& ) {}

            if ( !aModuleIdentifier.isEmpty() && aOldModuleIdentifier != aModuleIdentifier )
            {
                Reference< XModuleUIConfigurationManagerSupplier > xModuleCfgSupplier;
                if ( xContext.is() )
                    xModuleCfgSupplier = theModuleUIConfigurationManagerSupplier::get( xContext );

                if ( xModuleCfgMgr.is() )
                {
                    try
                    {
                        // Remove listener to old module ui configuration manager
                        xModuleCfgMgr->removeConfigurationListener( Reference< XUIConfigurationListener >(this) );
                    }
                    catch (const Exception&)
                    {
                    }
                }

                try
                {
                    // Add listener to new module ui configuration manager
                    xModuleCfgMgr.set( xModuleCfgSupplier->getUIConfigurationManager( aModuleIdentifier ), UNO_QUERY );
                    if ( xModuleCfgMgr.is() )
                        xModuleCfgMgr->addConfigurationListener( Reference< XUIConfigurationListener >(this) );
                }
                catch (const Exception&)
                {
                }

                try
                {
                    // Retrieve persistent window state reference for our new module
                    if ( xPersistentWindowStateSupplier.is() )
                        xPersistentWindowStateSupplier->getByName( aModuleIdentifier ) >>= xPersistentWindowState;
                }
                catch (const NoSuchElementException&)
                {
                }
                catch (const WrappedTargetException&)
                {
                }
            }

            xModel = impl_getModelFromFrame( xFrame );
            if ( xModel.is() )
            {
                Reference< XUIConfigurationManagerSupplier > xUIConfigurationManagerSupplier( xModel, UNO_QUERY );
                if ( xUIConfigurationManagerSupplier.is() )
                {
                    if ( xDocCfgMgr.is() )
                    {
                        try
                        {
                            // Remove listener to old ui configuration manager
                            xDocCfgMgr->removeConfigurationListener( Reference< XUIConfigurationListener >(this) );
                        }
                        catch (const Exception&)
                        {
                        }
                    }

                    try
                    {
                        xDocCfgMgr.set( xUIConfigurationManagerSupplier->getUIConfigurationManager(), UNO_QUERY );
                        if ( xDocCfgMgr.is() )
                            xDocCfgMgr->addConfigurationListener( Reference< XUIConfigurationListener >(this) );
                    }
                    catch (const Exception&)
                    {
                    }
                }
            }
        }
        else
        {
            // Remove configuration listeners before we can release our references
            if ( xModuleCfgMgr.is() )
            {
                try
                {
                    xModuleCfgMgr->removeConfigurationListener(
                        Reference< XUIConfigurationListener >(this) );
                }
                catch (const Exception&)
                {
                }
            }

            if ( xDocCfgMgr.is() )
            {
                try
                {
                    xDocCfgMgr->removeConfigurationListener(
                        Reference< XUIConfigurationListener >(this) );
                }
                catch (const Exception&)
                {
                }
            }

            // Release references to our configuration managers as we currently don't have
            // an attached module.
            xModuleCfgMgr.clear();
            xDocCfgMgr.clear();
            xPersistentWindowState.clear();
            aModuleIdentifier.clear();
        }

        Reference< XUIConfigurationManager > xModCfgMgr( xModuleCfgMgr, UNO_QUERY );
        Reference< XUIConfigurationManager > xDokCfgMgr( xDocCfgMgr, UNO_QUERY );

        /* SAFE AREA ----------------------------------------------------------------------------------------------- */
        SolarMutexClearableGuard aWriteLock;
        m_aDockingArea = awt::Rectangle();
        m_aModuleIdentifier = aModuleIdentifier;
        m_xModuleCfgMgr = xModCfgMgr;
        m_xDocCfgMgr = xDokCfgMgr;
        m_xPersistentWindowState = xPersistentWindowState;
        m_aStatusBarElement.m_bStateRead = false; // reset state to read data again!
        aWriteLock.clear();
        /* SAFE AREA ----------------------------------------------------------------------------------------------- */

        // reset/notify toolbar layout manager
        if ( xToolbarManager.is() )
        {
            if ( bAttached )
            {
                xToolbarManager->attach( xFrame, xModCfgMgr, xDokCfgMgr, xPersistentWindowState );
                uno::Reference< awt::XVclWindowPeer > xParent( xContainerWindow, UNO_QUERY );
                xToolbarManager->setParentWindow( xParent );
                if ( bAutomaticToolbars )
                    xToolbarManager->createStaticToolbars();
            }
            else
            {
                xToolbarManager->reset();
                implts_destroyElements();
            }
        }
    }

    implts_unlock();
}

bool LayoutManager::implts_isEmbeddedLayoutManager() const
{
    SolarMutexClearableGuard aReadLock;
    Reference< XFrame > xFrame = m_xFrame;
    Reference< awt::XWindow > xContainerWindow( m_xContainerWindow );
    aReadLock.clear();

    Reference< awt::XWindow > xFrameContainerWindow = xFrame->getContainerWindow();
    return xFrameContainerWindow != xContainerWindow;
}

void LayoutManager::implts_destroyElements()
{
    SolarMutexResettableGuard aWriteLock;
    ToolbarLayoutManager* pToolbarManager = m_xToolbarManager.get();
    aWriteLock.clear();

    if ( pToolbarManager )
        pToolbarManager->destroyToolbars();

    implts_destroyStatusBar();

    aWriteLock.reset();
    impl_clearUpMenuBar();
    aWriteLock.clear();
}

void LayoutManager::implts_toggleFloatingUIElementsVisibility( bool bActive )
{
    SolarMutexClearableGuard aReadLock;
    ToolbarLayoutManager* pToolbarManager = m_xToolbarManager.get();
    aReadLock.clear();

    if ( pToolbarManager )
        pToolbarManager->setFloatingToolbarsVisibility( bActive );
}

uno::Reference< ui::XUIElement > LayoutManager::implts_findElement( std::u16string_view aName )
{
    OUString aElementType;
    OUString aElementName;

    parseResourceURL( aName, aElementType, aElementName );
    if ( aElementType.equalsIgnoreAsciiCase("menubar") &&
         aElementName.equalsIgnoreAsciiCase("menubar") )
        return m_xMenuBar;
    else if (( aElementType.equalsIgnoreAsciiCase("statusbar") &&
               aElementName.equalsIgnoreAsciiCase("statusbar") ) ||
             ( m_aStatusBarElement.m_aName == aName ))
        return m_aStatusBarElement.m_xUIElement;
    else if ( aElementType.equalsIgnoreAsciiCase("progressbar") &&
              aElementName.equalsIgnoreAsciiCase("progressbar") )
        return m_aProgressBarElement.m_xUIElement;

    return uno::Reference< ui::XUIElement >();
}

bool LayoutManager::implts_readWindowStateData( const OUString& aName, UIElement& rElementData )
{
    return readWindowStateData( aName, rElementData, m_xPersistentWindowState,
            m_pGlobalSettings, m_bGlobalSettings, m_xContext );
}

bool LayoutManager::readWindowStateData( const OUString& aName, UIElement& rElementData,
        const Reference< XNameAccess > &rPersistentWindowState,
        std::unique_ptr<GlobalSettings> &rGlobalSettings, bool &bInGlobalSettings,
        const Reference< XComponentContext > &rComponentContext )
{
    if ( !rPersistentWindowState.is() )
        return false;

    bool bGetSettingsState( false );

    SolarMutexClearableGuard aWriteLock;
    bool bGlobalSettings( bInGlobalSettings );
    if ( rGlobalSettings == nullptr )
    {
        rGlobalSettings.reset( new GlobalSettings( rComponentContext ) );
        bGetSettingsState = true;
    }
    GlobalSettings* pGlobalSettings = rGlobalSettings.get();
    aWriteLock.clear();

    try
    {
        Sequence< PropertyValue > aWindowState;
        if ( rPersistentWindowState->hasByName( aName ) && (rPersistentWindowState->getByName( aName ) >>= aWindowState) )
        {
            bool bValue( false );
            for (PropertyValue const& rProp : aWindowState)
            {
                if ( rProp.Name == WINDOWSTATE_PROPERTY_DOCKED )
                {
                    if ( rProp.Value >>= bValue )
                        rElementData.m_bFloating = !bValue;
                }
                else if ( rProp.Name == WINDOWSTATE_PROPERTY_VISIBLE )
                {
                    if ( rProp.Value >>= bValue )
                        rElementData.m_bVisible = bValue;
                }
                else if ( rProp.Name == WINDOWSTATE_PROPERTY_DOCKINGAREA )
                {
                    ui::DockingArea eDockingArea;
                    if ( rProp.Value >>= eDockingArea )
                        rElementData.m_aDockedData.m_nDockedArea = eDockingArea;
                }
                else if ( rProp.Name == WINDOWSTATE_PROPERTY_DOCKPOS )
                {
                    awt::Point aPoint;
                    if (rProp.Value >>= aPoint)
                    {
                        //tdf#90256 repair these broken Docking positions
                        if (aPoint.X < 0)
                            aPoint.X = SAL_MAX_INT32;
                        if (aPoint.Y < 0)
                            aPoint.Y = SAL_MAX_INT32;
                        rElementData.m_aDockedData.m_aPos = aPoint;
                    }
                }
                else if ( rProp.Name == WINDOWSTATE_PROPERTY_POS )
                {
                    awt::Point aPoint;
                    if ( rProp.Value >>= aPoint )
                        rElementData.m_aFloatingData.m_aPos = aPoint;
                }
                else if ( rProp.Name == WINDOWSTATE_PROPERTY_SIZE )
                {
                    awt::Size aSize;
                    if ( rProp.Value >>= aSize )
                        rElementData.m_aFloatingData.m_aSize = aSize;
                }
                else if ( rProp.Name == WINDOWSTATE_PROPERTY_UINAME )
                    rProp.Value >>= rElementData.m_aUIName;
                else if ( rProp.Name == WINDOWSTATE_PROPERTY_STYLE )
                {
                    sal_Int32 nStyle = 0;
                    if ( rProp.Value >>= nStyle )
                        rElementData.m_nStyle = static_cast<ButtonType>( nStyle );
                }
                else if ( rProp.Name == WINDOWSTATE_PROPERTY_LOCKED )
                {
                    if ( rProp.Value >>= bValue )
                        rElementData.m_aDockedData.m_bLocked = bValue;
                }
                else if ( rProp.Name == WINDOWSTATE_PROPERTY_CONTEXT )
                {
                    if ( rProp.Value >>= bValue )
                        rElementData.m_bContextSensitive = bValue;
                }
                else if ( rProp.Name == WINDOWSTATE_PROPERTY_NOCLOSE )
                {
                    if ( rProp.Value >>= bValue )
                        rElementData.m_bNoClose = bValue;
                }
            }
        }

        // oversteer values with global settings
        if (bGetSettingsState || bGlobalSettings)
        {
            if ( pGlobalSettings->HasToolbarStatesInfo())
            {
                {
                    SolarMutexGuard aWriteLock2;
                    bInGlobalSettings = true;
                }

                uno::Any aValue;
                if ( pGlobalSettings->GetToolbarStateInfo(
                                                    GlobalSettings::STATEINFO_LOCKED,
                                                    aValue ))
                    aValue >>= rElementData.m_aDockedData.m_bLocked;
                if ( pGlobalSettings->GetToolbarStateInfo(
                                                    GlobalSettings::STATEINFO_DOCKED,
                                                    aValue ))
                {
                    bool bValue;
                    if ( aValue >>= bValue )
                        rElementData.m_bFloating = !bValue;
                }
            }
        }

        const bool bDockingSupportCrippled = !StyleSettings::GetDockingFloatsSupported();
        if (bDockingSupportCrippled)
            rElementData.m_bFloating = false;

        return true;
    }
    catch (const NoSuchElementException&)
    {
    }

    return false;
}

void LayoutManager::implts_writeWindowStateData( const OUString& aName, const UIElement& rElementData )
{
    SolarMutexClearableGuard aWriteLock;
    Reference< XNameAccess > xPersistentWindowState( m_xPersistentWindowState );

    aWriteLock.clear();

    bool bPersistent( false );
    Reference< XPropertySet > xPropSet( rElementData.m_xUIElement, UNO_QUERY );
    if ( xPropSet.is() )
    {
        try
        {
            // Check persistent flag of the user interface element
            xPropSet->getPropertyValue(u"Persistent"_ustr) >>= bPersistent;
        }
        catch (const beans::UnknownPropertyException&)
        {
            // Non-configurable elements should at least store their dimension/position
            bPersistent = true;
        }
        catch (const lang::WrappedTargetException&)
        {
        }
    }

    if ( !(bPersistent && xPersistentWindowState.is()) )
        return;

    try
    {
        Sequence< 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)
        };

        if ( xPersistentWindowState->hasByName( aName ))
        {
            Reference< XNameReplace > xReplace( xPersistentWindowState, uno::UNO_QUERY );
            xReplace->replaceByName( aName, Any( aWindowState ));
        }
        else
        {
            Reference< XNameContainer > xInsert( xPersistentWindowState, uno::UNO_QUERY );
            xInsert->insertByName( aName, Any( aWindowState ));
        }
    }
    catch (const Exception&)
    {
    }
}

::Size LayoutManager::implts_getContainerWindowOutputSize()
{
    ::Size  aContainerWinSize;
    vcl::Window* pContainerWindow( nullptr );

    // Retrieve output size from container Window
    SolarMutexGuard aGuard;
    pContainerWindow  = VCLUnoHelper::GetWindow( m_xContainerWindow );
    if ( pContainerWindow )
        aContainerWinSize = pContainerWindow->GetOutputSizePixel();

    return aContainerWinSize;
}

Reference< XUIElement > LayoutManager::implts_createElement( const OUString& aName )
{
    Reference< ui::XUIElement > xUIElement;

    SolarMutexGuard g;
    Sequence< PropertyValue > aPropSeq{ comphelper::makePropertyValue(u"Frame"_ustr, m_xFrame),
                                        comphelper::makePropertyValue(u"Persistent"_ustr, true) };

    try
    {
        xUIElement = m_xUIElementFactoryManager->createUIElement( aName, aPropSeq );
    }
    catch (const NoSuchElementException&)
    {
    }
    catch (const IllegalArgumentException&)
    {
    }

    return xUIElement;
}

void LayoutManager::implts_setVisibleState( bool bShow )
{
    {
        SolarMutexGuard aWriteLock;
        m_aStatusBarElement.m_bMasterHide = !bShow;
    }

    implts_updateUIElementsVisibleState( bShow );
}

void LayoutManager::implts_updateUIElementsVisibleState( bool bSetVisible )
{
    // notify listeners
    uno::Any a;
    if ( bSetVisible )
        implts_notifyListeners( frame::LayoutManagerEvents::VISIBLE, a );
    else
        implts_notifyListeners( frame::LayoutManagerEvents::INVISIBLE, a );

    SolarMutexResettableGuard aWriteLock;
    rtl::Reference< MenuBarWrapper > xMenuBar = m_xMenuBar;
    Reference< awt::XWindow > xContainerWindow( m_xContainerWindow );
    rtl::Reference< MenuBarManager > xInplaceMenuBar( m_xInplaceMenuBar );
    aWriteLock.clear();

    if (( xMenuBar.is() || xInplaceMenuBar.is() ) && xContainerWindow.is() )
    {
        SolarMutexGuard aGuard;

        MenuBar* pMenuBar( nullptr );
        if ( xInplaceMenuBar.is() )
            pMenuBar = static_cast<MenuBar *>(xInplaceMenuBar->GetMenuBar());
        else
        {
            pMenuBar = static_cast<MenuBar *>(xMenuBar->GetMenuBarManager()->GetMenuBar());
        }

        SystemWindow* pSysWindow = getTopSystemWindow( xContainerWindow );
        if ( pSysWindow )
        {
            if ( bSetVisible )
            {
                pSysWindow->SetMenuBar(pMenuBar);
            }
#ifdef MACOSX
            // Related: tdf#161623 don't set the menubar to null on macOS
            // When a window enters LibreOffice's internal full screen mode,
            // the vcl code will hide the macOS menubar. However, if the
            // window is also in native full screen mode, macOS will force
            // the menubar to be visible.
            // While the vcl code already partially handles this case by
            // disabling all menu items when in LibreOffice's internal full
            // screen mode, the problem is that any submenus that were not
            // displayed before setting the menubar to null will show all
            // menu items with no title.
            // A simple way to reproduce this bug is to open a new Writer
            // or Calc document and do the following:
            // - Switch the window to LibreOffice's internal full screen
            //   mode by manually selecting the View > Full Screen menu
            //   item (the bug does not occur if its key shortcut is
            //   pressed)
            // - Switch the window to native full screen mode
            // - Click on the menubar and note that many of the submenus
            //   are displayed with menu items, but none of the menu items
            //   have a title
            // So, we need to keep the menubar visible and rely on the vcl
            // code to disable all menu items.
            else if ( m_bInSetCurrentUIVisibility )
                pSysWindow->SetMenuBar(pMenuBar);
#endif
            else
                pSysWindow->SetMenuBar( nullptr );
        }
    }

    bool bMustDoLayout;
    // Hide/show the statusbar according to bSetVisible
    if ( bSetVisible )
        bMustDoLayout = !implts_showStatusBar();
    else
        bMustDoLayout = !implts_hideStatusBar();

    aWriteLock.reset();
    ToolbarLayoutManager* pToolbarManager( m_xToolbarManager.get() );
    aWriteLock.clear();

    if ( pToolbarManager )
    {
        pToolbarManager->setVisible( bSetVisible );
        bMustDoLayout = pToolbarManager->isLayoutDirty();
    }

    if ( bMustDoLayout )
        implts_doLayout_notify( false );
}

void LayoutManager::implts_setCurrentUIVisibility( bool bShow )
{
    {
        SolarMutexGuard aWriteLock;
        if (!bShow && m_aStatusBarElement.m_bVisible && m_aStatusBarElement.m_xUIElement.is())
            m_aStatusBarElement.m_bMasterHide = true;
        else if (bShow && m_aStatusBarElement.m_bVisible)
            m_aStatusBarElement.m_bMasterHide = false;
    }

    bool bOldInSetCurrentUIVisibility = m_bInSetCurrentUIVisibility;
    m_bInSetCurrentUIVisibility = true;
    implts_updateUIElementsVisibleState( bShow );
    m_bInSetCurrentUIVisibility = bOldInSetCurrentUIVisibility;
}

void LayoutManager::implts_destroyStatusBar()
{
    Reference< XComponent > xCompStatusBar;

    SolarMutexClearableGuard aWriteLock;
    m_aStatusBarElement.m_aName.clear();
    xCompStatusBar.set( m_aStatusBarElement.m_xUIElement, UNO_QUERY );
    m_aStatusBarElement.m_xUIElement.clear();
    aWriteLock.clear();

    if ( xCompStatusBar.is() )
        xCompStatusBar->dispose();

    implts_destroyProgressBar();
}

void LayoutManager::implts_createStatusBar( const OUString& aStatusBarName )
{
    {
        SolarMutexGuard aWriteLock;
        if (!m_aStatusBarElement.m_xUIElement.is())
        {
            implts_readStatusBarState(aStatusBarName);
            m_aStatusBarElement.m_aName = aStatusBarName;
            m_aStatusBarElement.m_xUIElement = implts_createElement(aStatusBarName);
        }
    }

    implts_createProgressBar();
}

void LayoutManager::implts_readStatusBarState( const OUString& rStatusBarName )
{
    SolarMutexGuard g;
    if ( !m_aStatusBarElement.m_bStateRead )
    {
        // Read persistent data for status bar if not yet read!
        if ( implts_readWindowStateData( rStatusBarName, m_aStatusBarElement ))
            m_aStatusBarElement.m_bStateRead = true;
    }
}

void LayoutManager::implts_createProgressBar()
{
    Reference< XUIElement > xStatusBar;
    Reference< XUIElement > xProgressBar;
    rtl::Reference< ProgressBarWrapper > xProgressBarBackup;
    Reference< awt::XWindow > xContainerWindow;

    SolarMutexResettableGuard aWriteLock;
    xStatusBar = m_aStatusBarElement.m_xUIElement;
    xProgressBar = m_aProgressBarElement.m_xUIElement;
    xProgressBarBackup = m_xProgressBarBackup;
    m_xProgressBarBackup.clear();
    xContainerWindow = m_xContainerWindow;
    aWriteLock.clear();

    bool bRecycled = xProgressBarBackup.is();
    rtl::Reference<ProgressBarWrapper> pWrapper;
    if ( bRecycled )
        pWrapper = xProgressBarBackup.get();
    else if ( xProgressBar.is() )
        pWrapper = static_cast<ProgressBarWrapper*>(xProgressBar.get());
    else
        pWrapper = new ProgressBarWrapper();

    if ( xStatusBar.is() )
    {
        Reference< awt::XWindow > xWindow( xStatusBar->getRealInterface(), UNO_QUERY );
        pWrapper->setStatusBar( xWindow );
    }
    else
    {
        Reference< awt::XWindow > xStatusBarWindow = pWrapper->getStatusBar();

        SolarMutexGuard aGuard;
        VclPtr<vcl::Window> pStatusBarWnd = VCLUnoHelper::GetWindow( xStatusBarWindow );
        if ( !pStatusBarWnd )
        {
            VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xContainerWindow );
            if ( pWindow )
            {
                VclPtrInstance<StatusBar> pStatusBar( pWindow, WinBits( WB_LEFT | WB_3DLOOK ) );
                Reference< awt::XWindow > xStatusBarWindow2( VCLUnoHelper::GetInterface( pStatusBar ));
                pWrapper->setStatusBar( xStatusBarWindow2, true );
            }
        }
    }

    /* SAFE AREA ----------------------------------------------------------------------------------------------- */
    aWriteLock.reset();
    m_aProgressBarElement.m_xUIElement = pWrapper;
    aWriteLock.clear();
    /* SAFE AREA ----------------------------------------------------------------------------------------------- */

    if ( bRecycled )
        implts_showProgressBar();
}

void LayoutManager::implts_backupProgressBarWrapper()
{
    SolarMutexGuard g;

    if (m_xProgressBarBackup.is())
        return;

    // safe a backup copy of the current progress!
    // This copy will be used automatically inside createProgressBar() which is called
    // implicitly from implts_doLayout() .-)
    m_xProgressBarBackup = static_cast<ProgressBarWrapper*>(m_aProgressBarElement.m_xUIElement.get());

    // remove the relation between this old progress bar and our old status bar.
    // Otherwise we work on disposed items ...
    // The internal used ProgressBarWrapper can handle a NULL reference.
    if ( m_xProgressBarBackup.is() )
        m_xProgressBarBackup->setStatusBar( Reference< awt::XWindow >() );

    // prevent us from dispose() the m_aProgressBarElement.m_xUIElement inside implts_reset()
    m_aProgressBarElement.m_xUIElement.clear();
}

void LayoutManager::implts_destroyProgressBar()
{
    // don't remove the progressbar in general
    // We must reuse it if a new status bar is created later.
    // Of course there exists one backup only.
    // And further this backup will be released inside our dtor.
    implts_backupProgressBarWrapper();
}

void LayoutManager::implts_setStatusBarPosSize( const ::Point& rPos, const ::Size& rSize )
{
    Reference< XUIElement > xStatusBar;
    Reference< XUIElement > xProgressBar;
    Reference< awt::XWindow > xContainerWindow;

    /* SAFE AREA ----------------------------------------------------------------------------------------------- */
    SolarMutexClearableGuard aReadLock;
    xStatusBar = m_aStatusBarElement.m_xUIElement;
    xProgressBar = m_aProgressBarElement.m_xUIElement;
    xContainerWindow = m_xContainerWindow;

    Reference< awt::XWindow > xWindow;
    if ( xStatusBar.is() )
        xWindow.set( xStatusBar->getRealInterface(), UNO_QUERY );
    else if ( xProgressBar.is() )
    {
        ProgressBarWrapper* pWrapper = static_cast<ProgressBarWrapper*>(xProgressBar.get());
        if ( pWrapper )
            xWindow = pWrapper->getStatusBar();
    }
    aReadLock.clear();
    /* SAFE AREA ----------------------------------------------------------------------------------------------- */

    if ( !xWindow.is() )
        return;

    SolarMutexGuard aGuard;
    VclPtr<vcl::Window> pParentWindow = VCLUnoHelper::GetWindow( xContainerWindow );
    VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow );
    if ( pParentWindow && ( pWindow && pWindow->GetType() == WindowType::STATUSBAR ))
    {
        vcl::Window* pOldParentWindow = pWindow->GetParent();
        if ( pParentWindow != pOldParentWindow )
            pWindow->SetParent( pParentWindow );
        static_cast<StatusBar *>(pWindow.get())->SetPosSizePixel( rPos, rSize );
    }
}

bool LayoutManager::implts_showProgressBar()
{
    Reference< XUIElement > xStatusBar;
    Reference< XUIElement > xProgressBar;
    Reference< awt::XWindow > xWindow;

    /* SAFE AREA ----------------------------------------------------------------------------------------------- */
    SolarMutexGuard aWriteLock;
    xStatusBar = m_aStatusBarElement.m_xUIElement;
    xProgressBar = m_aProgressBarElement.m_xUIElement;
    bool bVisible( m_bVisible );

    m_aProgressBarElement.m_bVisible = true;
    if ( bVisible )
    {
        if ( xStatusBar.is() && !m_aStatusBarElement.m_bMasterHide )
        {
            xWindow.set( xStatusBar->getRealInterface(), UNO_QUERY );
        }
        else if ( xProgressBar.is() )
        {
            ProgressBarWrapper* pWrapper = static_cast<ProgressBarWrapper*>(xProgressBar.get());
            if ( pWrapper )
                xWindow = pWrapper->getStatusBar();
        }
    }

    VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow );
    if ( pWindow )
    {
        if ( !pWindow->IsVisible() )
        {
            implts_setOffset( pWindow->GetSizePixel().Height() );
            pWindow->Show();
            implts_doLayout_notify( false );
        }
        return true;
    }

    return false;
}

bool LayoutManager::implts_hideProgressBar()
{
    Reference< XUIElement > xProgressBar;
    Reference< awt::XWindow > xWindow;
    bool bHideStatusBar( false );

    SolarMutexGuard g;
    xProgressBar = m_aProgressBarElement.m_xUIElement;

    bool bInternalStatusBar( false );
    if ( xProgressBar.is() )
    {
        Reference< awt::XWindow > xStatusBar;
        ProgressBarWrapper* pWrapper = static_cast<ProgressBarWrapper*>(xProgressBar.get());
        if ( pWrapper )
            xWindow = pWrapper->getStatusBar();
        Reference< ui::XUIElement > xStatusBarElement = m_aStatusBarElement.m_xUIElement;
        if ( xStatusBarElement.is() )
            xStatusBar.set( xStatusBarElement->getRealInterface(), UNO_QUERY );
        bInternalStatusBar = xStatusBar != xWindow;
    }
    m_aProgressBarElement.m_bVisible = false;
    implts_readStatusBarState( STATUS_BAR_ALIAS );
    bHideStatusBar = !m_aStatusBarElement.m_bVisible;

    VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow );
    if ( pWindow && pWindow->IsVisible() && ( bHideStatusBar || bInternalStatusBar ))
    {
        implts_setOffset( 0 );
        pWindow->Hide();
        implts_doLayout_notify( false );
        return true;
    }

    return false;
}

bool LayoutManager::implts_showStatusBar( bool bStoreState )
{
    SolarMutexClearableGuard aWriteLock;
    Reference< ui::XUIElement > xStatusBar = m_aStatusBarElement.m_xUIElement;
    if ( bStoreState )
        m_aStatusBarElement.m_bVisible = true;
    aWriteLock.clear();

    if ( xStatusBar.is() )
    {
        Reference< awt::XWindow > xWindow( xStatusBar->getRealInterface(), UNO_QUERY );

        SolarMutexGuard aGuard;
        VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow );
        if ( pWindow && !pWindow->IsVisible() )
        {
            implts_setOffset( pWindow->GetSizePixel().Height() );
            pWindow->Show();
            implts_doLayout_notify( false );
            return true;
        }
    }

    return false;
}

bool LayoutManager::implts_hideStatusBar( bool bStoreState )
{
    SolarMutexClearableGuard aWriteLock;
    Reference< ui::XUIElement > xStatusBar = m_aStatusBarElement.m_xUIElement;
    if ( bStoreState )
        m_aStatusBarElement.m_bVisible = false;
    aWriteLock.clear();

    if ( xStatusBar.is() )
    {
        Reference< awt::XWindow > xWindow( xStatusBar->getRealInterface(), UNO_QUERY );

        SolarMutexGuard aGuard;
        VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow );
        if ( pWindow && pWindow->IsVisible() )
        {
            implts_setOffset( 0 );
            pWindow->Hide();
            implts_doLayout_notify( false );
            return true;
        }
    }

    return false;
}

void LayoutManager::implts_setOffset( const sal_Int32 nBottomOffset )
{
    if ( m_xToolbarManager.is() )
        m_xToolbarManager->setDockingAreaOffsets({ 0, 0, 0, nBottomOffset });
}

void LayoutManager::implts_setInplaceMenuBar( const Reference< XIndexAccess >& xMergedMenuBar )
{
    /* SAFE AREA ----------------------------------------------------------------------------------------------- */
    SolarMutexClearableGuard aWriteLock;

    if ( m_bInplaceMenuSet )
        return;

    SolarMutexGuard aGuard;

    // Reset old inplace menubar!
    VclPtr<Menu> pOldMenuBar;
    if (m_xInplaceMenuBar.is())
    {
        pOldMenuBar = m_xInplaceMenuBar->GetMenuBar();
        m_xInplaceMenuBar->dispose();
        m_xInplaceMenuBar.clear();
    }
    pOldMenuBar.disposeAndClear();

    m_bInplaceMenuSet = false;

    if ( m_xFrame.is() && m_xContainerWindow.is() )
    {
        Reference< XDispatchProvider > xDispatchProvider;

        VclPtr<MenuBar> pMenuBar = VclPtr<MenuBar>::Create();
        m_xInplaceMenuBar = new MenuBarManager( m_xContext, m_xFrame, m_xURLTransformer, xDispatchProvider, OUString(), pMenuBar, true );
        m_xInplaceMenuBar->SetItemContainer( xMergedMenuBar );

        SystemWindow* pSysWindow = getTopSystemWindow( m_xContainerWindow );
        if ( pSysWindow )
            pSysWindow->SetMenuBar(pMenuBar);

        m_bInplaceMenuSet = true;
    }

    aWriteLock.clear();
    /* SAFE AREA ----------------------------------------------------------------------------------------------- */

    implts_updateMenuBarClose();
}

void LayoutManager::implts_resetInplaceMenuBar()
{
    SolarMutexGuard g;
    m_bInplaceMenuSet = false;

    if ( m_xContainerWindow.is() )
    {
        SolarMutexGuard aGuard;
        SystemWindow* pSysWindow = getTopSystemWindow( m_xContainerWindow );
        if ( pSysWindow )
        {
            if ( m_xMenuBar )
                pSysWindow->SetMenuBar(static_cast<MenuBar *>(m_xMenuBar->GetMenuBarManager()->GetMenuBar()));
            else
                pSysWindow->SetMenuBar(nullptr);
        }
    }

    // Remove inplace menu bar
    VclPtr<Menu> pMenuBar;
    if (m_xInplaceMenuBar.is())
    {
        pMenuBar = m_xInplaceMenuBar->GetMenuBar();
        m_xInplaceMenuBar->dispose();
        m_xInplaceMenuBar.clear();
    }
    pMenuBar.disposeAndClear();
}

void SAL_CALL LayoutManager::attachFrame( const Reference< XFrame >& xFrame )
{
    SolarMutexGuard g;
    m_xFrame = xFrame;
}

void SAL_CALL LayoutManager::reset()
{
    implts_reset( true );
}

// XMenuBarMergingAcceptor

sal_Bool SAL_CALL LayoutManager::setMergedMenuBar(
    const Reference< XIndexAccess >& xMergedMenuBar )
{
    implts_setInplaceMenuBar( xMergedMenuBar );

    uno::Any a;
    implts_notifyListeners( frame::LayoutManagerEvents::MERGEDMENUBAR, a );
    return true;
}

void SAL_CALL LayoutManager::removeMergedMenuBar()
{
    implts_resetInplaceMenuBar();
}

awt::Rectangle SAL_CALL LayoutManager::getCurrentDockingArea()
{
    SolarMutexGuard g;
    return m_aDockingArea;
}

Reference< XDockingAreaAcceptor > SAL_CALL LayoutManager::getDockingAreaAcceptor()
{
    SolarMutexGuard g;
    return m_xDockingAreaAcceptor;
}

void SAL_CALL LayoutManager::setDockingAreaAcceptor( const Reference< ui::XDockingAreaAcceptor >& xDockingAreaAcceptor )
{
    /* SAFE AREA ----------------------------------------------------------------------------------------------- */
    SolarMutexClearableGuard aWriteLock;

    if (( m_xDockingAreaAcceptor == xDockingAreaAcceptor ) || !m_xFrame.is() )
        return;

    // IMPORTANT: Be sure to stop layout timer if don't have a docking area acceptor!
    if ( !xDockingAreaAcceptor.is() )
        m_aAsyncLayoutTimer.Stop();

    bool bAutomaticToolbars( m_bAutomaticToolbars );

    ToolbarLayoutManager* pToolbarManager = m_xToolbarManager.get();

    if ( !xDockingAreaAcceptor.is() )
        m_aAsyncLayoutTimer.Stop();

    // Remove listener from old docking area acceptor
    if ( m_xDockingAreaAcceptor.is() )
    {
        Reference< awt::XWindow > xWindow( m_xDockingAreaAcceptor->getContainerWindow() );
        if ( xWindow.is() && ( m_xFrame->getContainerWindow() != m_xContainerWindow || !xDockingAreaAcceptor.is() ) )
            xWindow->removeWindowListener( Reference< awt::XWindowListener >(this) );

        m_aDockingArea = awt::Rectangle();
        if ( pToolbarManager )
            pToolbarManager->resetDockingArea();

        VclPtr<vcl::Window> pContainerWindow = VCLUnoHelper::GetWindow( xWindow );
        if ( pContainerWindow )
            pContainerWindow->RemoveChildEventListener( LINK( this, LayoutManager, WindowEventListener ) );
    }

    m_xDockingAreaAcceptor = xDockingAreaAcceptor;
    if ( m_xDockingAreaAcceptor.is() )
    {
        m_aDockingArea     = awt::Rectangle();
        m_xContainerWindow = m_xDockingAreaAcceptor->getContainerWindow();
        m_xContainerTopWindow.set( m_xContainerWindow, UNO_QUERY );
        m_xContainerWindow->addWindowListener( Reference< awt::XWindowListener >(this) );

        // we always must keep a connection to the window of our frame for resize events
        if ( m_xContainerWindow != m_xFrame->getContainerWindow() )
            m_xFrame->getContainerWindow()->addWindowListener( Reference< awt::XWindowListener >(this) );

        // #i37884# set initial visibility state - in the plugin case the container window is already shown
        // and we get no notification anymore
        {
            VclPtr<vcl::Window> pContainerWindow = VCLUnoHelper::GetWindow( m_xContainerWindow );
            if( pContainerWindow )
                m_bParentWindowVisible = pContainerWindow->IsVisible();
        }
    }

    aWriteLock.clear();
    /* SAFE AREA ----------------------------------------------------------------------------------------------- */

    if ( xDockingAreaAcceptor.is() )
    {
        SolarMutexGuard aGuard;

        // Add layout manager as listener to get notifications about toolbar button activities
        VclPtr<vcl::Window> pContainerWindow = VCLUnoHelper::GetWindow( m_xContainerWindow );
        if ( pContainerWindow )
            pContainerWindow->AddChildEventListener( LINK( this, LayoutManager, WindowEventListener ) );

        // We have now a new container window, reparent all child windows!
        implts_reparentChildWindows();
    }
    else
        implts_destroyElements(); // remove all elements

    if ( pToolbarManager && xDockingAreaAcceptor.is() )
    {
        if ( bAutomaticToolbars )
        {
            lock();
            pToolbarManager->createStaticToolbars();
            unlock();
        }
        implts_doLayout( true, false );
    }
}

void LayoutManager::implts_reparentChildWindows()
{
    SolarMutexResettableGuard aWriteLock;
    UIElement aStatusBarElement = m_aStatusBarElement;
    uno::Reference< awt::XWindow > xContainerWindow  = m_xContainerWindow;
    aWriteLock.clear();

    uno::Reference< awt::XWindow > xStatusBarWindow;
    if ( aStatusBarElement.m_xUIElement.is() )
    {
        try
        {
            xStatusBarWindow.set( aStatusBarElement.m_xUIElement->getRealInterface(), UNO_QUERY );
        }
        catch (const RuntimeException&)
        {
            throw;
        }
        catch (const Exception&)
        {
        }
    }

    if ( xStatusBarWindow.is() )
    {
        SolarMutexGuard aGuard;
        VclPtr<vcl::Window> pContainerWindow = VCLUnoHelper::GetWindow( xContainerWindow );
        VclPtr<vcl::Window> pWindow          = VCLUnoHelper::GetWindow( xStatusBarWindow );
        if ( pWindow && pContainerWindow )
            pWindow->SetParent( pContainerWindow );
    }

    implts_resetMenuBar();

    aWriteLock.reset();
    ToolbarLayoutManager* pToolbarManager = m_xToolbarManager.get();
    if ( pToolbarManager )
        pToolbarManager->setParentWindow( uno::Reference< awt::XVclWindowPeer >( xContainerWindow, uno::UNO_QUERY ));
    aWriteLock.clear();
}

uno::Reference< ui::XUIElement > LayoutManager::implts_createDockingWindow( const OUString& aElementName )
{
    Reference< XUIElement > xUIElement = implts_createElement( aElementName );
    return xUIElement;
}

IMPL_LINK( LayoutManager, WindowEventListener, VclWindowEvent&, rEvent, void )
{
    vcl::Window* pWindow = rEvent.GetWindow();
    if ( pWindow && pWindow->GetType() == WindowType::TOOLBOX )
    {
        SolarMutexClearableGuard aReadLock;
        ToolbarLayoutManager* pToolbarManager( m_xToolbarManager.get() );
        aReadLock.clear();

        if ( pToolbarManager )
            pToolbarManager->childWindowEvent( &rEvent );
    }
}

void SAL_CALL LayoutManager::createElement( const OUString& aName )
{
    SAL_INFO( "fwk", "LayoutManager::createElement " << aName );

    SolarMutexClearableGuard aReadLock;
    Reference< XFrame > xFrame = m_xFrame;
    aReadLock.clear();

    if ( !xFrame.is() )
        return;

    /* SAFE AREA ----------------------------------------------------------------------------------------------- */
    SolarMutexClearableGuard aWriteLock;

    bool bMustBeLayouted( false );
    bool bNotify( false );

    bool bPreviewFrame;
    if (m_xToolbarManager.is())
        // Assumes that we created the ToolbarLayoutManager with our frame, if
        // not then we're somewhat fouled up ...
        bPreviewFrame = m_xToolbarManager->isPreviewFrame();
    else
    {
        Reference< XModel >  xModel( impl_getModelFromFrame( xFrame ) );
        bPreviewFrame = implts_isPreviewModel( xModel );
    }

    if ( m_xContainerWindow.is() && !bPreviewFrame ) // no UI elements on preview frames
    {
        OUString aElementType;
        OUString aElementName;

        parseResourceURL( aName, aElementType, aElementName );

        if ( aElementType.equalsIgnoreAsciiCase( UIRESOURCETYPE_TOOLBAR ) && m_xToolbarManager.is() )
        {
            bNotify         = m_xToolbarManager->createToolbar( aName );
            bMustBeLayouted = m_xToolbarManager->isLayoutDirty();
        }
        else if ( aElementType.equalsIgnoreAsciiCase("menubar") &&
                  aElementName.equalsIgnoreAsciiCase("menubar") &&
                  implts_isFrameOrWindowTop(xFrame) )
        {
            implts_createMenuBar( aName );
            if (m_bMenuVisible)
                bNotify = true;

            aWriteLock.clear();
        }
        else if ( aElementType.equalsIgnoreAsciiCase("statusbar") &&
                  ( implts_isFrameOrWindowTop(xFrame) || implts_isEmbeddedLayoutManager() ))
        {
            implts_createStatusBar( aName );
            bNotify = true;
        }
        else if ( aElementType.equalsIgnoreAsciiCase("progressbar") &&
                  aElementName.equalsIgnoreAsciiCase("progressbar") &&
                  implts_isFrameOrWindowTop(xFrame) )
        {
            implts_createProgressBar();
            bNotify = true;
        }
        else if ( aElementType.equalsIgnoreAsciiCase("dockingwindow"))
        {
            // Add layout manager as listener for docking and other window events
            uno::Reference< uno::XInterface > xThis( static_cast< OWeakObject* >(this), uno::UNO_QUERY );
            uno::Reference< ui::XUIElement > xUIElement( implts_createDockingWindow( aName ));

            if ( xUIElement.is() )
            {
                impl_addWindowListeners( xThis, xUIElement );
            }

            // The docking window is created by a factory method located in the sfx2 library.
//            CreateDockingWindow( xFrame, aElementName );
        }
    }

    if ( bMustBeLayouted )
        implts_doLayout_notify( true );

    if ( bNotify )
    {
        // UI element is invisible - provide information to listeners
        implts_notifyListeners( frame::LayoutManagerEvents::UIELEMENT_VISIBLE, uno::Any( aName ) );
    }
}

void SAL_CALL LayoutManager::destroyElement( const OUString& aName )
{
    SAL_INFO( "fwk", "LayoutManager::destroyElement " << aName );

    bool bMustBeLayouted(false);
    bool bNotify(false);
    /* SAFE AREA ----------------------------------------------------------------------------------------------- */
    {
        SolarMutexClearableGuard aWriteLock;

        OUString aElementType;
        OUString aElementName;

        parseResourceURL(aName, aElementType, aElementName);

        if (aElementType.equalsIgnoreAsciiCase("menubar")
            && aElementName.equalsIgnoreAsciiCase("menubar"))
        {
            if (!m_bInplaceMenuSet)
            {
                impl_clearUpMenuBar();
                m_xMenuBar.clear();
                bNotify = true;
            }
        }
        else if ((aElementType.equalsIgnoreAsciiCase("statusbar")
                  && aElementName.equalsIgnoreAsciiCase("statusbar"))
                 || (m_aStatusBarElement.m_aName == aName))
        {
            aWriteLock.clear();
            implts_destroyStatusBar();
            bMustBeLayouted = true;
            bNotify = true;
        }
        else if (aElementType.equalsIgnoreAsciiCase("progressbar")
                 && aElementName.equalsIgnoreAsciiCase("progressbar"))
        {
            aWriteLock.clear();
            implts_createProgressBar();
            bMustBeLayouted = true;
            bNotify = true;
        }
        else if (aElementType.equalsIgnoreAsciiCase(UIRESOURCETYPE_TOOLBAR)
                 && m_xToolbarManager.is())
        {
            aWriteLock.clear();
            bNotify = m_xToolbarManager->destroyToolbar(aName);
            bMustBeLayouted = m_xToolbarManager->isLayoutDirty();
        }
        else if (aElementType.equalsIgnoreAsciiCase("dockingwindow"))
        {
            uno::Reference<frame::XFrame> xFrame(m_xFrame);
            uno::Reference<XComponentContext> xContext(m_xContext);
            aWriteLock.clear();

            impl_setDockingWindowVisibility(xContext, xFrame, aElementName, false);
            bMustBeLayouted = false;
            bNotify = false;
        }
    }
    /* SAFE AREA ----------------------------------------------------------------------------------------------- */

    if ( bMustBeLayouted )
        doLayout();

    if ( bNotify )
        implts_notifyListeners( frame::LayoutManagerEvents::UIELEMENT_INVISIBLE, uno::Any( aName ) );
}

sal_Bool SAL_CALL LayoutManager::requestElement( const OUString& rResourceURL )
{
    bool            bResult( false );
    bool            bNotify( false );
    OUString aElementType;
    OUString aElementName;

    parseResourceURL( rResourceURL, aElementType, aElementName );

    SolarMutexClearableGuard aWriteLock;

    OString aResName = OUStringToOString( aElementName, RTL_TEXTENCODING_ASCII_US );
    SAL_INFO( "fwk", "LayoutManager::requestElement " << aResName );

    if (( aElementType.equalsIgnoreAsciiCase("statusbar") &&
          aElementName.equalsIgnoreAsciiCase("statusbar") ) ||
        ( m_aStatusBarElement.m_aName == rResourceURL ))
    {
        implts_readStatusBarState( rResourceURL );
        if ( m_aStatusBarElement.m_bVisible && !m_aStatusBarElement.m_bMasterHide )
        {
            aWriteLock.clear();
            createElement( rResourceURL );

            // There are some situation where we are not able to create an element.
            // Therefore we have to check the reference before further action.
            // See #i70019#
            uno::Reference< ui::XUIElement > xUIElement( m_aStatusBarElement.m_xUIElement );
            if ( xUIElement.is() )
            {
                // we need VCL here to pass special flags to Show()
                SolarMutexGuard aGuard;
                Reference< awt::XWindow > xWindow( xUIElement->getRealInterface(), UNO_QUERY );
                VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow );
                if ( pWindow )
                {
                    pWindow->Show( true, ShowFlags::NoFocusChange | ShowFlags::NoActivate );
                    bResult   = true;
                    bNotify   = true;
                }
            }
        }
    }
    else if ( aElementType.equalsIgnoreAsciiCase("progressbar") &&
              aElementName.equalsIgnoreAsciiCase("progressbar") )
    {
        aWriteLock.clear();
        implts_showProgressBar();
        bResult   = true;
        bNotify   = true;
    }
    else if ( aElementType.equalsIgnoreAsciiCase( UIRESOURCETYPE_TOOLBAR ) && m_bVisible )
    {
        bool bComponentAttached( !m_aModuleIdentifier.isEmpty() );
        ToolbarLayoutManager* pToolbarManager = m_xToolbarManager.get();
        aWriteLock.clear();

        if ( pToolbarManager && bComponentAttached )
        {
            bNotify   = pToolbarManager->requestToolbar( rResourceURL );
        }
    }
    else if ( aElementType.equalsIgnoreAsciiCase("dockingwindow"))
    {
        uno::Reference< frame::XFrame > xFrame( m_xFrame );
        aWriteLock.clear();

        CreateDockingWindow( xFrame, aElementName );
    }

    if ( bNotify )
        implts_notifyListeners( frame::LayoutManagerEvents::UIELEMENT_VISIBLE, uno::Any( rResourceURL ) );

    return bResult;
}

Reference< XUIElement > SAL_CALL LayoutManager::getElement( const OUString& aName )
{
    Reference< XUIElement > xUIElement = implts_findElement( aName );
    if ( !xUIElement.is() )
    {
        SolarMutexClearableGuard aReadLock;
        ToolbarLayoutManager*             pToolbarManager( m_xToolbarManager.get() );
        aReadLock.clear();

        if ( pToolbarManager )
            xUIElement = pToolbarManager->getToolbar( aName );
    }

    return xUIElement;
}

Sequence< Reference< ui::XUIElement > > SAL_CALL LayoutManager::getElements()
{
    SolarMutexClearableGuard aReadLock;
    rtl::Reference< MenuBarWrapper >  xMenuBar( m_xMenuBar );
    uno::Reference< ui::XUIElement >  xStatusBar( m_aStatusBarElement.m_xUIElement );
    ToolbarLayoutManager*             pToolbarManager( m_xToolbarManager.get() );
    aReadLock.clear();

    Sequence< Reference< ui::XUIElement > > aSeq;
    if ( pToolbarManager )
        aSeq = pToolbarManager->getToolbars();

    sal_Int32 nSize = aSeq.getLength();
    sal_Int32 nMenuBarIndex(-1);
    sal_Int32 nStatusBarIndex(-1);
    if ( xMenuBar.is() )
    {
        nMenuBarIndex = nSize;
        ++nSize;
    }
    if ( xStatusBar.is() )
    {
        nStatusBarIndex = nSize;
        ++nSize;
    }

    aSeq.realloc(nSize);
    auto pSeq = aSeq.getArray();
    if ( nMenuBarIndex >= 0 )
        pSeq[nMenuBarIndex] = xMenuBar;
    if ( nStatusBarIndex >= 0 )
        pSeq[nStatusBarIndex] = std::move(xStatusBar);

    return aSeq;
}

sal_Bool SAL_CALL LayoutManager::showElement( const OUString& aName )
{
    bool            bResult( false );
    bool            bNotify( false );
    bool            bMustLayout( false );
    OUString aElementType;
    OUString aElementName;

    parseResourceURL( aName, aElementType, aElementName );

    OString aResName = OUStringToOString( aElementName, RTL_TEXTENCODING_ASCII_US );
    SAL_INFO( "fwk", "LayoutManager::showElement " << aResName );

    if ( aElementType.equalsIgnoreAsciiCase("menubar") &&
         aElementName.equalsIgnoreAsciiCase("menubar") )
    {
        {
            SolarMutexGuard aWriteLock;
            m_bMenuVisible = true;
        }

        bResult = implts_resetMenuBar();
        bNotify = bResult;
    }
    else if (( aElementType.equalsIgnoreAsciiCase("statusbar") &&
               aElementName.equalsIgnoreAsciiCase("statusbar") ) ||
             ( m_aStatusBarElement.m_aName == aName ))
    {
        SolarMutexClearableGuard aWriteLock;
        if ( m_aStatusBarElement.m_xUIElement.is() && !m_aStatusBarElement.m_bMasterHide &&
             implts_showStatusBar( true ))
        {
            aWriteLock.clear();

            implts_writeWindowStateData( STATUS_BAR_ALIAS, m_aStatusBarElement );
            bMustLayout = true;
            bResult     = true;
            bNotify     = true;
        }
    }
    else if ( aElementType.equalsIgnoreAsciiCase("progressbar") &&
              aElementName.equalsIgnoreAsciiCase("progressbar") )
    {
        bNotify = bResult = implts_showProgressBar();
    }
    else if ( aElementType.equalsIgnoreAsciiCase( UIRESOURCETYPE_TOOLBAR ))
    {
        SolarMutexClearableGuard aReadLock;
        ToolbarLayoutManager* pToolbarManager = m_xToolbarManager.get();
        aReadLock.clear();

        if ( pToolbarManager )
        {
            bNotify     = pToolbarManager->showToolbar( aName );
            bMustLayout = pToolbarManager->isLayoutDirty();
        }
    }
    else if ( aElementType.equalsIgnoreAsciiCase("dockingwindow"))
    {
        SolarMutexClearableGuard aReadGuard;
        uno::Reference< frame::XFrame > xFrame( m_xFrame );
        uno::Reference< XComponentContext > xContext( m_xContext );
        aReadGuard.clear();

        impl_setDockingWindowVisibility( xContext, xFrame, aElementName, true );
    }

    if ( bMustLayout )
        doLayout();

    if ( bNotify )
        implts_notifyListeners( frame::LayoutManagerEvents::UIELEMENT_VISIBLE, uno::Any( aName ) );

    return bResult;
}

sal_Bool SAL_CALL LayoutManager::hideElement( const OUString& aName )
{
    bool            bNotify( false );
    bool            bMustLayout( false );
    OUString aElementType;
    OUString aElementName;

    parseResourceURL( aName, aElementType, aElementName );
    OString aResName = OUStringToOString( aElementName, RTL_TEXTENCODING_ASCII_US );
    SAL_INFO( "fwk", "LayoutManager::hideElement " << aResName );

    if ( aElementType.equalsIgnoreAsciiCase("menubar") &&
         aElementName.equalsIgnoreAsciiCase("menubar") )
    {
        SolarMutexGuard g;

        if ( m_xContainerWindow.is() )
        {
            m_bMenuVisible = false;

            SolarMutexGuard aGuard;
            SystemWindow* pSysWindow = getTopSystemWindow( m_xContainerWindow );
            if ( pSysWindow )
            {
                MenuBar* pMenuBar = pSysWindow->GetMenuBar();
                if ( pMenuBar )
                {
                    pMenuBar->SetDisplayable( false );
                    bNotify = true;
                }
            }
        }
    }
    else if (( aElementType.equalsIgnoreAsciiCase("statusbar") &&
               aElementName.equalsIgnoreAsciiCase("statusbar") ) ||
             ( m_aStatusBarElement.m_aName == aName ))
    {
        SolarMutexGuard g;
        if ( m_aStatusBarElement.m_xUIElement.is() && !m_aStatusBarElement.m_bMasterHide &&
             implts_hideStatusBar( true ))
        {
            implts_writeWindowStateData( STATUS_BAR_ALIAS, m_aStatusBarElement );
            bMustLayout = true;
            bNotify     = true;
        }
    }
    else if ( aElementType.equalsIgnoreAsciiCase("progressbar") &&
              aElementName.equalsIgnoreAsciiCase("progressbar") )
    {
        bNotify = implts_hideProgressBar();
    }
    else if ( aElementType.equalsIgnoreAsciiCase( UIRESOURCETYPE_TOOLBAR ))
    {
        SolarMutexClearableGuard aReadLock;
        ToolbarLayoutManager* pToolbarManager = m_xToolbarManager.get();
        aReadLock.clear();

        if ( pToolbarManager )
        {
            bNotify     = pToolbarManager->hideToolbar( aName );
            bMustLayout = pToolbarManager->isLayoutDirty();
        }
    }
    else if ( aElementType.equalsIgnoreAsciiCase("dockingwindow"))
    {
        SolarMutexClearableGuard aReadGuard;
        uno::Reference< frame::XFrame > xFrame( m_xFrame );
        uno::Reference< XComponentContext > xContext( m_xContext );
        aReadGuard.clear();

        impl_setDockingWindowVisibility( xContext, xFrame, aElementName, false );
    }

    if ( bMustLayout )
        doLayout();

    if ( bNotify )
        implts_notifyListeners( frame::LayoutManagerEvents::UIELEMENT_INVISIBLE, uno::Any( aName ) );

    return false;
}

sal_Bool SAL_CALL LayoutManager::dockWindow( const OUString& aName, DockingArea DockingArea, const awt::Point& Pos )
{
    OUString aElementType;
    OUString aElementName;

    parseResourceURL( aName, aElementType, aElementName );
    if ( aElementType.equalsIgnoreAsciiCase( UIRESOURCETYPE_TOOLBAR ))
    {
        SolarMutexClearableGuard aReadLock;
        ToolbarLayoutManager*             pToolbarManager = m_xToolbarManager.get();
        aReadLock.clear();

        if ( pToolbarManager )
        {
            pToolbarManager->dockToolbar( aName, DockingArea, Pos );
            if ( pToolbarManager->isLayoutDirty() )
                doLayout();
        }
    }
    return false;
}

sal_Bool SAL_CALL LayoutManager::dockAllWindows( ::sal_Int16 /*nElementType*/ )
{
    SolarMutexClearableGuard aReadLock;
    bool bResult( false );
    ToolbarLayoutManager*             pToolbarManager = m_xToolbarManager.get();
    aReadLock.clear();

    if ( pToolbarManager )
    {
        bResult = pToolbarManager->dockAllToolbars();
        if ( pToolbarManager->isLayoutDirty() )
            doLayout();
    }
    return bResult;
}

sal_Bool SAL_CALL LayoutManager::floatWindow( const OUString& aName )
{
    bool bResult( false );
    if ( o3tl::equalsIgnoreAsciiCase(getElementTypeFromResourceURL( aName ), UIRESOURCETYPE_TOOLBAR ))
    {
        SolarMutexClearableGuard aReadLock;
        ToolbarLayoutManager*             pToolbarManager = m_xToolbarManager.get();
        aReadLock.clear();

        if ( pToolbarManager )
        {
            bResult = pToolbarManager->floatToolbar( aName );
            if ( pToolbarManager->isLayoutDirty() )
                doLayout();
        }
    }
    return bResult;
}

sal_Bool SAL_CALL LayoutManager::lockWindow( const OUString& aName )
{
    bool bResult( false );
    if ( o3tl::equalsIgnoreAsciiCase(getElementTypeFromResourceURL( aName ), UIRESOURCETYPE_TOOLBAR ))
    {
        SolarMutexClearableGuard aReadLock;
        ToolbarLayoutManager*             pToolbarManager = m_xToolbarManager.get();
        aReadLock.clear();

        if ( pToolbarManager )
        {
            bResult = pToolbarManager->lockToolbar( aName );
            if ( pToolbarManager->isLayoutDirty() )
                doLayout();
        }
    }
    return bResult;
}

sal_Bool SAL_CALL LayoutManager::unlockWindow( const OUString& aName )
{
    bool bResult( false );
    if ( o3tl::equalsIgnoreAsciiCase(getElementTypeFromResourceURL( aName ), UIRESOURCETYPE_TOOLBAR ))
    {
        SolarMutexClearableGuard aReadLock;
        ToolbarLayoutManager*             pToolbarManager = m_xToolbarManager.get();
        aReadLock.clear();

        if ( pToolbarManager )
        {
            bResult = pToolbarManager->unlockToolbar( aName );
            if ( pToolbarManager->isLayoutDirty() )
                doLayout();
        }
    }
    return bResult;
}

void SAL_CALL LayoutManager::setElementSize( const OUString& aName, const awt::Size& aSize )
{
    if ( !o3tl::equalsIgnoreAsciiCase(getElementTypeFromResourceURL( aName ), UIRESOURCETYPE_TOOLBAR ))
        return;

    SolarMutexClearableGuard aReadLock;
    ToolbarLayoutManager*             pToolbarManager = m_xToolbarManager.get();
    aReadLock.clear();

    if ( pToolbarManager )
    {
        pToolbarManager->setToolbarSize( aName, aSize );
        if ( pToolbarManager->isLayoutDirty() )
            doLayout();
    }
}

void SAL_CALL LayoutManager::setElementPos( const OUString& aName, const awt::Point& aPos )
{
    if ( !o3tl::equalsIgnoreAsciiCase(getElementTypeFromResourceURL( aName ), UIRESOURCETYPE_TOOLBAR ))
        return;

    SolarMutexClearableGuard aReadLock;
    ToolbarLayoutManager* pToolbarManager( m_xToolbarManager.get() );
    aReadLock.clear();

    if ( pToolbarManager )
    {
        pToolbarManager->setToolbarPos( aName, aPos );
        if ( pToolbarManager->isLayoutDirty() )
            doLayout();
    }
}

void SAL_CALL LayoutManager::setElementPosSize( const OUString& aName, const awt::Point& aPos, const awt::Size& aSize )
{
    if ( !o3tl::equalsIgnoreAsciiCase(getElementTypeFromResourceURL( aName ), UIRESOURCETYPE_TOOLBAR ))
        return;

    SolarMutexClearableGuard aReadLock;
    ToolbarLayoutManager* pToolbarManager( m_xToolbarManager.get() );
    aReadLock.clear();

    if ( pToolbarManager )
    {
        pToolbarManager->setToolbarPosSize( aName, aPos, aSize );
        if ( pToolbarManager->isLayoutDirty() )
            doLayout();
    }
}

sal_Bool SAL_CALL LayoutManager::isElementVisible( const OUString& aName )
{
    OUString aElementType;
    OUString aElementName;

    parseResourceURL( aName, aElementType, aElementName );
    if ( aElementType.equalsIgnoreAsciiCase("menubar") &&
         aElementName.equalsIgnoreAsciiCase("menubar") )
    {
        SolarMutexResettableGuard aReadLock;
        if ( m_xContainerWindow.is() )
        {
            aReadLock.clear();

            SolarMutexGuard aGuard;
            SystemWindow* pSysWindow = getTopSystemWindow( m_xContainerWindow );
            if ( pSysWindow )
            {
                MenuBar* pMenuBar = pSysWindow->GetMenuBar();
                if ( pMenuBar && pMenuBar->IsDisplayable() )
                    return true;
            }
            else
            {
                aReadLock.reset();
                return m_bMenuVisible;
            }
        }
    }
    else if (( aElementType.equalsIgnoreAsciiCase("statusbar") &&
               aElementName.equalsIgnoreAsciiCase("statusbar") ) ||
             ( m_aStatusBarElement.m_aName == aName ))
    {
        if ( m_aStatusBarElement.m_xUIElement.is() )
        {
            Reference< awt::XWindow > xWindow( m_aStatusBarElement.m_xUIElement->getRealInterface(), UNO_QUERY );
            if ( xWindow.is() )
            {
                SolarMutexGuard g;
                VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow );
                if ( pWindow && pWindow->IsVisible() )
                    return true;
                else
                    return false;
            }
        }
    }
    else if ( aElementType.equalsIgnoreAsciiCase("progressbar") &&
              aElementName.equalsIgnoreAsciiCase("progressbar") )
    {
        if ( m_aProgressBarElement.m_xUIElement.is() )
            return m_aProgressBarElement.m_bVisible;
    }
    else if ( aElementType.equalsIgnoreAsciiCase( UIRESOURCETYPE_TOOLBAR ))
    {
        SolarMutexClearableGuard aReadLock;
        ToolbarLayoutManager* pToolbarManager = m_xToolbarManager.get();
        aReadLock.clear();

        if ( pToolbarManager )
            return pToolbarManager->isToolbarVisible( aName );
    }
    else if ( aElementType.equalsIgnoreAsciiCase("dockingwindow"))
    {
        SolarMutexClearableGuard aReadGuard;
        uno::Reference< frame::XFrame > xFrame( m_xFrame );
        aReadGuard.clear();

        return IsDockingWindowVisible( xFrame, aElementName );
    }

    return false;
}

sal_Bool SAL_CALL LayoutManager::isElementFloating( const OUString& aName )
{
    if ( o3tl::equalsIgnoreAsciiCase(getElementTypeFromResourceURL( aName ), UIRESOURCETYPE_TOOLBAR ))
    {
        SolarMutexClearableGuard aReadLock;
        ToolbarLayoutManager* pToolbarManager = m_xToolbarManager.get();
        aReadLock.clear();

        if ( pToolbarManager )
            return pToolbarManager->isToolbarFloating( aName );
    }

    return false;
}

sal_Bool SAL_CALL LayoutManager::isElementDocked( const OUString& aName )
{
    if ( o3tl::equalsIgnoreAsciiCase(getElementTypeFromResourceURL( aName ), UIRESOURCETYPE_TOOLBAR ))
    {
        SolarMutexClearableGuard aReadLock;
        ToolbarLayoutManager* pToolbarManager = m_xToolbarManager.get();
        aReadLock.clear();

        if ( pToolbarManager )
            return pToolbarManager->isToolbarDocked( aName );
    }

    return false;
}

sal_Bool SAL_CALL LayoutManager::isElementLocked( const OUString& aName )
{
    if ( o3tl::equalsIgnoreAsciiCase(getElementTypeFromResourceURL( aName ), UIRESOURCETYPE_TOOLBAR ))
    {
        SolarMutexClearableGuard aReadLock;
        ToolbarLayoutManager* pToolbarManager = m_xToolbarManager.get();
        aReadLock.clear();

        if ( pToolbarManager )
            return pToolbarManager->isToolbarLocked( aName );
    }

    return false;
}

awt::Size SAL_CALL LayoutManager::getElementSize( const OUString& aName )
{
    if ( o3tl::equalsIgnoreAsciiCase(getElementTypeFromResourceURL( aName ), UIRESOURCETYPE_TOOLBAR ))
    {
        SolarMutexClearableGuard aReadLock;
        ToolbarLayoutManager* pToolbarManager = m_xToolbarManager.get();
        aReadLock.clear();

        if ( pToolbarManager )
            return pToolbarManager->getToolbarSize( aName );
    }

    return awt::Size();
}

awt::Point SAL_CALL LayoutManager::getElementPos( const OUString& aName )
{
    if ( o3tl::equalsIgnoreAsciiCase(getElementTypeFromResourceURL( aName ), UIRESOURCETYPE_TOOLBAR ))
    {
        SolarMutexClearableGuard aReadLock;
        ToolbarLayoutManager* pToolbarManager = m_xToolbarManager.get();
        aReadLock.clear();

        if ( pToolbarManager )
            return pToolbarManager->getToolbarPos( aName );
    }

    return awt::Point();
}

void SAL_CALL LayoutManager::lock()
{
    implts_lock();

    SolarMutexClearableGuard aReadLock;
    sal_Int32 nLockCount( m_nLockCount );
    aReadLock.clear();

    SAL_INFO( "fwk", "LayoutManager::lock " << reinterpret_cast<sal_Int64>(this) << " - " << nLockCount );

    Any a( nLockCount );
    implts_notifyListeners( frame::LayoutManagerEvents::LOCK, a );
}

void SAL_CALL LayoutManager::unlock()
{
    bool bDoLayout( implts_unlock() );

    SolarMutexClearableGuard aReadLock;
    sal_Int32 nLockCount( m_nLockCount );
    aReadLock.clear();

    SAL_INFO( "fwk", "LayoutManager::unlock " << reinterpret_cast<sal_Int64>(this) << " - " << nLockCount);

    // conform to documentation: unlock with lock count == 0 means force a layout

    {
        SolarMutexGuard aWriteLock;
        if (bDoLayout)
            m_aAsyncLayoutTimer.Stop();
    }

    Any a( nLockCount );
    implts_notifyListeners( frame::LayoutManagerEvents::UNLOCK, a );

    if ( bDoLayout )
        implts_doLayout_notify( true );
}

void SAL_CALL LayoutManager::doLayout()
{
    implts_doLayout_notify( true );
}

//  ILayoutNotifications

void LayoutManager::requestLayout()
{
    doLayout();
}

void LayoutManager::implts_doLayout_notify( bool bOuterResize )
{
    bool bLayouted = implts_doLayout( false, bOuterResize );
    if ( bLayouted )
        implts_notifyListeners( frame::LayoutManagerEvents::LAYOUT, Any() );
}

bool LayoutManager::implts_doLayout( bool bForceRequestBorderSpace, bool bOuterResize )
{
    SAL_INFO( "fwk", "LayoutManager::implts_doLayout" );

    /* SAFE AREA ----------------------------------------------------------------------------------------------- */
    SolarMutexClearableGuard aReadLock;

    if ( !m_xFrame.is() || !m_bParentWindowVisible )
        return false;

    bool bPreserveContentSize( m_bPreserveContentSize );
    bool bMustDoLayout( m_bMustDoLayout );
    bool bNoLock = ( m_nLockCount == 0 );
    awt::Rectangle aCurrBorderSpace( m_aDockingArea );
    Reference< awt::XWindow > xContainerWindow( m_xContainerWindow );
    Reference< awt::XTopWindow2 > xContainerTopWindow( m_xContainerTopWindow );
    Reference< awt::XWindow > xComponentWindow;
    try {
        xComponentWindow = m_xFrame->getComponentWindow();
    } catch (css::lang::DisposedException &) {
        // There can be a race between one thread calling Frame::dispose
        // (framework/source/services/frame.cxx) -> Frame::disableLayoutManager
        // -> LayoutManager::attachFrame(null) setting m_xFrame to null, and
        // the main thread firing the timer-triggered
        // LayoutManager::AsyncLayoutHdl -> LayoutManager::implts_doLayout and
        // calling into the in-dispose m_xFrame here, so silently ignore a
        // DisposedException here:
        return false;
    }
    Reference< XDockingAreaAcceptor > xDockingAreaAcceptor( m_xDockingAreaAcceptor );
    aReadLock.clear();
    /* SAFE AREA ----------------------------------------------------------------------------------------------- */

    bool bLayouted( false );

    if ( bNoLock && xDockingAreaAcceptor.is() && xContainerWindow.is() && xComponentWindow.is() )
    {
        bLayouted = true;

        awt::Rectangle aDockSpace( implts_calcDockingAreaSizes() );
        awt::Rectangle aBorderSpace( aDockSpace );
        bool       bGotRequestedBorderSpace( true );

        // We have to add the height of a possible status bar
        aBorderSpace.Height += implts_getStatusBarSize().Height();

        if ( !equalRectangles( aBorderSpace, aCurrBorderSpace ) || bForceRequestBorderSpace || bMustDoLayout )
        {
            // we always resize the content window (instead of the complete container window) if we're not set up
            // to (attempt to) preserve the content window's size
            if ( bOuterResize && !bPreserveContentSize )
                bOuterResize = false;

            // maximized windows can resized their content window only, not their container window
            if ( bOuterResize && xContainerTopWindow.is() && xContainerTopWindow->getIsMaximized() )
                bOuterResize = false;

            // if the component window does not have a size (yet), then we can't use it to calc the container
            // window size
            awt::Rectangle aComponentRect = xComponentWindow->getPosSize();
            if ( bOuterResize && ( aComponentRect.Width == 0 ) && ( aComponentRect.Height == 0 ) )
                bOuterResize = false;

            bGotRequestedBorderSpace = false;
            if ( bOuterResize )
            {
                Reference< awt::XDevice > xDevice( xContainerWindow, uno::UNO_QUERY );
                awt::DeviceInfo aContainerInfo  = xDevice->getInfo();

                awt::Size aRequestedSize( aComponentRect.Width + aContainerInfo.LeftInset + aContainerInfo.RightInset + aBorderSpace.X + aBorderSpace.Width,
                                          aComponentRect.Height + aContainerInfo.TopInset  + aContainerInfo.BottomInset + aBorderSpace.Y + aBorderSpace.Height );
                awt::Point aComponentPos( aBorderSpace.X, aBorderSpace.Y );

                bGotRequestedBorderSpace = implts_resizeContainerWindow( aRequestedSize, aComponentPos );
            }

            // if we did not do a container window resize, or it failed, then use the DockingAcceptor as usual
            if ( !bGotRequestedBorderSpace )
                bGotRequestedBorderSpace = xDockingAreaAcceptor->requestDockingAreaSpace( aBorderSpace );

            if ( bGotRequestedBorderSpace )
            {
                SolarMutexGuard aWriteGuard;
                m_aDockingArea = aBorderSpace;
                m_bMustDoLayout = false;
            }
        }

        if ( bGotRequestedBorderSpace )
        {
            ::Size      aContainerSize;
            ::Size      aStatusBarSize;

            // Interim solution to let the layout method within the
            // toolbar layout manager.
            implts_setOffset( implts_getStatusBarSize().Height() );
            if ( m_xToolbarManager.is() )
                m_xToolbarManager->setDockingArea( aDockSpace );

            // Subtract status bar size from our container output size. Docking area windows
            // don't contain the status bar!
            aStatusBarSize = implts_getStatusBarSize();
            aContainerSize = implts_getContainerWindowOutputSize();
            aContainerSize.AdjustHeight( -(aStatusBarSize.Height()) );

            if ( m_xToolbarManager.is() )
                m_xToolbarManager->doLayout(aContainerSize);

            // Position the status bar
            if ( aStatusBarSize.Height() > 0 )
            {
                implts_setStatusBarPosSize( ::Point( 0, std::max(( aContainerSize.Height() ), tools::Long( 0 ))),
                                            ::Size( aContainerSize.Width(),aStatusBarSize.Height() ));
            }

            xDockingAreaAcceptor->setDockingAreaSpace( aBorderSpace );
        }
    }

    return bLayouted;
}

bool LayoutManager::implts_resizeContainerWindow( const awt::Size& rContainerSize,
                                                      const awt::Point& rComponentPos )
{
    SolarMutexClearableGuard aReadLock;
    Reference< awt::XWindow >               xContainerWindow    = m_xContainerWindow;
    Reference< awt::XTopWindow2 >           xContainerTopWindow = m_xContainerTopWindow;
    Reference< awt::XWindow >               xComponentWindow    = m_xFrame->getComponentWindow();
    aReadLock.clear();

    // calculate the maximum size we have for the container window
    sal_Int32 nDisplay = xContainerTopWindow->getDisplay();
    AbsoluteScreenPixelRectangle aWorkArea = Application::GetScreenPosSizePixel( nDisplay );

    if (!aWorkArea.IsEmpty())
    {
        if (( rContainerSize.Width > aWorkArea.GetWidth() ) || ( rContainerSize.Height > aWorkArea.GetHeight() ))
            return false;
        // Strictly, this is not correct. If we have a multi-screen display (css.awt.DisplayAccess.MultiDisplay == true),
        // the "effective work area" would be much larger than the work area of a single display, since we could in theory
        // position the container window across multiple screens.
        // However, this should suffice as a heuristics here ... (nobody really wants to check whether the different screens are
        // stacked horizontally or vertically, whether their work areas can really be combined, or are separated by non-work-areas,
        // and the like ... right?)
    }

    // resize our container window
    xContainerWindow->setPosSize( 0, 0, rContainerSize.Width, rContainerSize.Height, awt::PosSize::SIZE );
    // position the component window
    xComponentWindow->setPosSize( rComponentPos.X, rComponentPos.Y, 0, 0, awt::PosSize::POS );
    return true;
}

void SAL_CALL LayoutManager::setVisible( sal_Bool bVisible )
{
    SolarMutexClearableGuard aWriteLock;
    bool bWasVisible( m_bVisible );
    m_bVisible = bVisible;
    aWriteLock.clear();

    if ( bWasVisible != bool(bVisible) )
        implts_setVisibleState( bVisible );
}

sal_Bool SAL_CALL LayoutManager::isVisible()
{
    SolarMutexGuard g;
    return m_bVisible;
}

::Size LayoutManager::implts_getStatusBarSize()
{
    SolarMutexClearableGuard aReadLock;
    bool bStatusBarVisible( isElementVisible( STATUS_BAR_ALIAS ));
    bool bProgressBarVisible( isElementVisible( u"private:resource/progressbar/progressbar"_ustr ));
    bool bVisible( m_bVisible );
    Reference< XUIElement > xStatusBar( m_aStatusBarElement.m_xUIElement );
    Reference< XUIElement > xProgressBar( m_aProgressBarElement.m_xUIElement );

    Reference< awt::XWindow > xWindow;
    if ( bStatusBarVisible && bVisible && xStatusBar.is() )
        xWindow.set( xStatusBar->getRealInterface(), UNO_QUERY );
    else if ( xProgressBar.is() && !xStatusBar.is() && bProgressBarVisible )
    {
        ProgressBarWrapper* pWrapper = static_cast<ProgressBarWrapper*>(xProgressBar.get());
        if ( pWrapper )
            xWindow = pWrapper->getStatusBar();
    }
    aReadLock.clear();

    if ( xWindow.is() )
    {
        awt::Rectangle aPosSize = xWindow->getPosSize();
        return ::Size( aPosSize.Width, aPosSize.Height );
    }
    else
        return ::Size();
}

awt::Rectangle LayoutManager::implts_calcDockingAreaSizes()
{
    SolarMutexClearableGuard aReadLock;
    Reference< awt::XWindow > xContainerWindow( m_xContainerWindow );
    Reference< XDockingAreaAcceptor > xDockingAreaAcceptor( m_xDockingAreaAcceptor );
    aReadLock.clear();

    awt::Rectangle aBorderSpace;
    if ( m_xToolbarManager.is() && xDockingAreaAcceptor.is() && xContainerWindow.is() )
        aBorderSpace = m_xToolbarManager->getDockingArea();

    return aBorderSpace;
}

void LayoutManager::implts_setDockingAreaWindowSizes()
{
    SolarMutexClearableGuard aReadLock;
    Reference< awt::XWindow > xContainerWindow( m_xContainerWindow );
    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 );
    ::Size          aStatusBarSize       = implts_getStatusBarSize();

    // Position the status bar
    if ( aStatusBarSize.Height() > 0 )
    {
        implts_setStatusBarPosSize( ::Point( 0, std::max(( aContainerClientSize.Height - aStatusBarSize.Height() ), tools::Long( 0 ))),
                                    ::Size( aContainerClientSize.Width, aStatusBarSize.Height() ));
    }
}

void LayoutManager::implts_updateMenuBarClose()
{
    SolarMutexClearableGuard aWriteLock;
    bool                      bShowCloseButton( m_bMenuBarCloseButton );
    Reference< awt::XWindow > xContainerWindow( m_xContainerWindow );
    aWriteLock.clear();

    if ( !xContainerWindow.is() )
        return;

    SolarMutexGuard aGuard;

    SystemWindow* pSysWindow = getTopSystemWindow( xContainerWindow );
    if ( pSysWindow )
    {
        MenuBar* pMenuBar = pSysWindow->GetMenuBar();
        if ( pMenuBar )
        {
            // TODO remove link on sal_False ?!
            pMenuBar->ShowCloseButton(bShowCloseButton);
            pMenuBar->SetCloseButtonClickHdl(LINK(this, LayoutManager, MenuBarClose));
        }
    }
}

bool LayoutManager::implts_resetMenuBar()
{
    /* SAFE AREA ----------------------------------------------------------------------------------------------- */
    SolarMutexGuard aWriteLock;
    bool bMenuVisible( m_bMenuVisible );
    Reference< awt::XWindow > xContainerWindow( m_xContainerWindow );

    MenuBar* pSetMenuBar = nullptr;
    if ( m_xInplaceMenuBar.is() )
        pSetMenuBar = static_cast<MenuBar *>(m_xInplaceMenuBar->GetMenuBar());
    else if ( m_xMenuBar )
        pSetMenuBar = static_cast<MenuBar*>(m_xMenuBar->GetMenuBarManager()->GetMenuBar());

    SystemWindow* pSysWindow = getTopSystemWindow( xContainerWindow );
    if ( pSysWindow && bMenuVisible && pSetMenuBar )
    {
        pSysWindow->SetMenuBar(pSetMenuBar);
        pSetMenuBar->SetDisplayable( true );
        return true;
    }

    return false;
}

void LayoutManager::implts_createMSCompatibleMenuBar( const OUString& aName )
{
    SolarMutexGuard aWriteLock;

    // Find Form menu in the original menubar
    m_xMenuBar.set( static_cast< MenuBarWrapper* >(implts_createElement( aName ).get()) );
    uno::Reference< container::XIndexReplace > xMenuIndex(m_xMenuBar->getSettings(true), UNO_QUERY);

    sal_Int32 nFormsMenu = -1;
    for (sal_Int32 nIndex = 0; nIndex < xMenuIndex->getCount(); ++nIndex)
    {
        uno::Sequence< beans::PropertyValue > aProps;
        xMenuIndex->getByIndex( nIndex ) >>= aProps;
        OUString aCommand;
        for (beans::PropertyValue const& rProp : aProps)
        {
            if (rProp.Name == "CommandURL")
            {
                rProp.Value >>= aCommand;
                break;
            }
        }

        if (aCommand == ".uno:FormatFormMenu")
            nFormsMenu = nIndex;
    }
    assert(nFormsMenu != -1);

    // Create the MS compatible Form menu
    css::uno::Reference< css::ui::XUIElement > xFormsMenu = implts_createElement( u"private:resource/menubar/mscompatibleformsmenu"_ustr );
    if(!xFormsMenu.is())
        return;

    // Merge the MS compatible Form menu into the menubar
    uno::Reference< XUIElementSettings > xFormsMenuSettings(xFormsMenu, UNO_QUERY);
    uno::Reference< container::XIndexAccess > xFormsMenuIndex(xFormsMenuSettings->getSettings(true));

    assert(xFormsMenuIndex->getCount() >= 1);
    uno::Sequence< beans::PropertyValue > aNewFormsMenu;
    xFormsMenuIndex->getByIndex( 0 ) >>= aNewFormsMenu;
    xMenuIndex->replaceByIndex(nFormsMenu, uno::Any(aNewFormsMenu));

    setMergedMenuBar( xMenuIndex );

    // Clear up the temporal forms menubar
    Reference< XComponent > xFormsMenuComp( xFormsMenu, UNO_QUERY );
    if ( xFormsMenuComp.is() )
        xFormsMenuComp->dispose();
    xFormsMenu.clear();
}

IMPL_LINK_NOARG(LayoutManager, MenuBarClose, void*, void)
{
    SolarMutexClearableGuard aReadLock;
    uno::Reference< frame::XDispatchProvider >   xProvider(m_xFrame, uno::UNO_QUERY);
    uno::Reference< XComponentContext > xContext( m_xContext );
    aReadLock.clear();

    if ( !xProvider.is())
        return;

    uno::Reference< frame::XDispatchHelper > xDispatcher = frame::DispatchHelper::create( xContext );

    xDispatcher->executeDispatch(
        xProvider,
        u".uno:CloseWin"_ustr,
        u"_self"_ustr,
        0,
        uno::Sequence< beans::PropertyValue >());
}

//  XLayoutManagerEventBroadcaster

void SAL_CALL LayoutManager::addLayoutManagerEventListener( const uno::Reference< frame::XLayoutManagerListener >& xListener )
{
    m_aListenerContainer.addInterface( cppu::UnoType<frame::XLayoutManagerListener>::get(), xListener );
}

void SAL_CALL LayoutManager::removeLayoutManagerEventListener( const uno::Reference< frame::XLayoutManagerListener >& xListener )
{
    m_aListenerContainer.removeInterface( cppu::UnoType<frame::XLayoutManagerListener>::get(), xListener );
}

void LayoutManager::implts_notifyListeners(short nEvent, const uno::Any& rInfoParam)
{
    comphelper::OInterfaceContainerHelper2* pContainer = m_aListenerContainer.getContainer( cppu::UnoType<frame::XLayoutManagerListener>::get());
    if (pContainer==nullptr)
        return;

    lang::EventObject                  aSource( static_cast< ::cppu::OWeakObject*>(this) );
    comphelper::OInterfaceIteratorHelper2 pIterator(*pContainer);
    while (pIterator.hasMoreElements())
    {
        try
        {
            static_cast<frame::XLayoutManagerListener*>(pIterator.next())->layoutEvent(aSource, nEvent, rInfoParam);
        }
        catch( const uno::RuntimeException& )
        {
            pIterator.remove();
        }
    }
}

//      XWindowListener

void SAL_CALL LayoutManager::windowResized( const awt::WindowEvent& aEvent )
{
    SolarMutexGuard g;
    Reference< awt::XWindow >         xContainerWindow( m_xContainerWindow );

    Reference< XInterface > xIfac( xContainerWindow, UNO_QUERY );
    if ( xIfac == aEvent.Source && m_bVisible )
    {
        // We have to call our resize handler at least once synchronously, as some
        // application modules need this. So we have to check if this is the first
        // call after the async layout time expired.
        m_bMustDoLayout = true;
        if ( !m_aAsyncLayoutTimer.IsActive() )
        {
            m_aAsyncLayoutTimer.Invoke();
            if ( m_nLockCount == 0 )
                m_aAsyncLayoutTimer.Start();
        }
    }
    else if ( m_xFrame.is() && aEvent.Source == m_xFrame->getContainerWindow() )
    {
        // the container window of my DockingAreaAcceptor is not the same as of my frame
        // I still have to resize my frames' window as nobody else will do it
        Reference< awt::XWindow > xComponentWindow( m_xFrame->getComponentWindow() );
        if( xComponentWindow.is() )
        {
            uno::Reference< awt::XDevice > xDevice( m_xFrame->getContainerWindow(), uno::UNO_QUERY );

            // Convert relative size to output size.
            awt::Rectangle  aRectangle = m_xFrame->getContainerWindow()->getPosSize();
            awt::DeviceInfo aInfo      = xDevice->getInfo();
            awt::Size       aSize(  aRectangle.Width  - aInfo.LeftInset - aInfo.RightInset  ,
                                    aRectangle.Height - aInfo.TopInset  - aInfo.BottomInset );

            // Resize our component window.
            xComponentWindow->setPosSize( 0, 0, aSize.Width, aSize.Height, awt::PosSize::POSSIZE );
        }
    }
}

void SAL_CALL LayoutManager::windowMoved( const awt::WindowEvent& )
{
}

void SAL_CALL LayoutManager::windowShown( const lang::EventObject& aEvent )
{
    SolarMutexClearableGuard aReadLock;
    Reference< awt::XWindow >  xContainerWindow( m_xContainerWindow );
    bool                       bParentWindowVisible( m_bParentWindowVisible );
    aReadLock.clear();

    Reference< XInterface > xIfac( xContainerWindow, UNO_QUERY );
    if ( xIfac == aEvent.Source )
    {
        SolarMutexClearableGuard aWriteLock;
        m_bParentWindowVisible = true;
        bool bSetVisible = ( m_bParentWindowVisible != bParentWindowVisible );
        aWriteLock.clear();

        if ( bSetVisible )
            implts_updateUIElementsVisibleState( true );
    }
}

void SAL_CALL LayoutManager::windowHidden( const lang::EventObject& aEvent )
{
    SolarMutexClearableGuard aReadLock;
    Reference< awt::XWindow > xContainerWindow( m_xContainerWindow );
    bool                      bParentWindowVisible( m_bParentWindowVisible );
    aReadLock.clear();

    Reference< XInterface > xIfac( xContainerWindow, UNO_QUERY );
    if ( xIfac == aEvent.Source )
    {
        SolarMutexClearableGuard aWriteLock;
        m_bParentWindowVisible = false;
        bool bSetInvisible = ( m_bParentWindowVisible != bParentWindowVisible );
        aWriteLock.clear();

        if ( bSetInvisible )
            implts_updateUIElementsVisibleState( false );
    }
}

IMPL_LINK_NOARG(LayoutManager, AsyncLayoutHdl, Timer *, void)
{
    {
        SolarMutexGuard aReadLock;

        if (!m_xContainerWindow.is())
            return;
    }

    implts_setDockingAreaWindowSizes();
    implts_doLayout( true, false );
}

//      XFrameActionListener

void SAL_CALL LayoutManager::frameAction( const FrameActionEvent& aEvent )
{
    if (( aEvent.Action == FrameAction_COMPONENT_ATTACHED ) || ( aEvent.Action == FrameAction_COMPONENT_REATTACHED ))
    {
        SAL_INFO( "fwk", "LayoutManager::frameAction (COMPONENT_ATTACHED|REATTACHED)" );

        {
            SolarMutexGuard aWriteLock;
            m_bMustDoLayout = true;
        }

        implts_reset( true );
        implts_doLayout( true, false );
        implts_doLayout( true, true );
    }
    else if (( aEvent.Action == FrameAction_FRAME_UI_ACTIVATED ) || ( aEvent.Action == FrameAction_FRAME_UI_DEACTIVATING ))
    {
        SAL_INFO( "fwk", "LayoutManager::frameAction (FRAME_UI_ACTIVATED|DEACTIVATING)" );

        implts_toggleFloatingUIElementsVisibility( aEvent.Action == FrameAction_FRAME_UI_ACTIVATED );
    }
    else if ( aEvent.Action == FrameAction_COMPONENT_DETACHING )
    {
        SAL_INFO( "fwk", "LayoutManager::frameAction (COMPONENT_DETACHING)" );

        implts_reset( false );
    }
}

void SAL_CALL LayoutManager::disposing( const lang::EventObject& rEvent )
{
    bool bDisposeAndClear( false );

    /* SAFE AREA ----------------------------------------------------------------------------------------------- */
    {
        SolarMutexGuard aWriteLock;

        if (rEvent.Source == Reference<XInterface>(m_xFrame, UNO_QUERY))
        {
            // Our frame gets disposed, release all our references that depends on a working frame reference.

            setDockingAreaAcceptor(Reference<ui::XDockingAreaAcceptor>());

            // destroy all elements, it's possible that detaching is NOT called!
            implts_destroyElements();
            impl_clearUpMenuBar();
            m_xMenuBar.clear();
            VclPtr<Menu> pMenuBar;
            if (m_xInplaceMenuBar.is())
            {
                pMenuBar = m_xInplaceMenuBar->GetMenuBar();
                m_xInplaceMenuBar->dispose();
                m_xInplaceMenuBar.clear();
            }
            pMenuBar.disposeAndClear();
            m_xContainerWindow.clear();
            m_xContainerTopWindow.clear();

            // forward disposing call to toolbar manager
            if (m_xToolbarManager.is())
                m_xToolbarManager->disposing(rEvent);

            if (m_xModuleCfgMgr.is())
            {
                try
                {
                    Reference<XUIConfiguration> xModuleCfgMgr(m_xModuleCfgMgr, UNO_QUERY);
                    xModuleCfgMgr->removeConfigurationListener(Reference<XUIConfigurationListener>(this));
                }
                catch (const Exception&)
                {
                }
            }

            if (m_xDocCfgMgr.is())
            {
                try
                {
                    Reference<XUIConfiguration> xDocCfgMgr(m_xDocCfgMgr, UNO_QUERY);
                    xDocCfgMgr->removeConfigurationListener(Reference<XUIConfigurationListener>(this));
                }
                catch (const Exception&)
                {
                }
            }

            m_xDocCfgMgr.clear();
            m_xModuleCfgMgr.clear();
            m_xFrame.clear();
            m_pGlobalSettings.reset();

            bDisposeAndClear = true;
        }
        else if (rEvent.Source == Reference<XInterface>(m_xContainerWindow, UNO_QUERY))
        {
            // Our container window gets disposed. Remove all user interface elements.
            ToolbarLayoutManager* pToolbarManager = m_xToolbarManager.get();
            if (pToolbarManager)
            {
                uno::Reference<awt::XVclWindowPeer> aEmptyWindowPeer;
                pToolbarManager->setParentWindow(aEmptyWindowPeer);
            }
            impl_clearUpMenuBar();
            m_xMenuBar.clear();
            VclPtr<Menu> pMenuBar;
            if (m_xInplaceMenuBar.is())
            {
                pMenuBar = m_xInplaceMenuBar->GetMenuBar();
                m_xInplaceMenuBar->dispose();
                m_xInplaceMenuBar.clear();
            }
            pMenuBar.disposeAndClear();
            m_xContainerWindow.clear();
            m_xContainerTopWindow.clear();
        }
        else if (rEvent.Source == Reference<XInterface>(m_xDocCfgMgr, UNO_QUERY))
            m_xDocCfgMgr.clear();
        else if (rEvent.Source == Reference<XInterface>(m_xModuleCfgMgr, UNO_QUERY))
            m_xModuleCfgMgr.clear();
    }
    /* SAFE AREA ----------------------------------------------------------------------------------------------- */

    // Send disposing to our listener when we have lost our frame.
    if ( bDisposeAndClear )
    {
        // Send message to all listener and forget her references.
        uno::Reference< frame::XLayoutManager > xThis(this);
        lang::EventObject aEvent( xThis );
        m_aListenerContainer.disposeAndClear( aEvent );
    }
}

void SAL_CALL LayoutManager::elementInserted( const ui::ConfigurationEvent& Event )
{
    SolarMutexClearableGuard aReadLock;
    Reference< XFrame > xFrame( m_xFrame );
    rtl::Reference< ToolbarLayoutManager > xToolbarManager( m_xToolbarManager );
    aReadLock.clear();

    if ( !xFrame.is() )
        return;

    OUString aElementType;
    OUString aElementName;
    bool            bRefreshLayout(false);

    parseResourceURL( Event.ResourceURL, aElementType, aElementName );
    if ( aElementType.equalsIgnoreAsciiCase( UIRESOURCETYPE_TOOLBAR ))
    {
        if ( xToolbarManager.is() )
        {
            xToolbarManager->elementInserted( Event );
            bRefreshLayout = xToolbarManager->isLayoutDirty();
        }
    }
    else if ( aElementType.equalsIgnoreAsciiCase( UIRESOURCETYPE_MENUBAR ))
    {
        Reference< XUIElement >         xUIElement = implts_findElement( Event.ResourceURL );
        Reference< XUIElementSettings > xElementSettings( xUIElement, UNO_QUERY );
        if ( xElementSettings.is() )
        {
            uno::Reference< XPropertySet > xPropSet( xElementSettings, uno::UNO_QUERY );
            if ( xPropSet.is() )
            {
                if ( Event.Source == uno::Reference< uno::XInterface >( m_xDocCfgMgr, uno::UNO_QUERY ))
                    xPropSet->setPropertyValue( u"ConfigurationSource"_ustr, Any( m_xDocCfgMgr ));
            }
            xElementSettings->updateSettings();
        }
    }

    if ( bRefreshLayout )
        doLayout();
}

void SAL_CALL LayoutManager::elementRemoved( const ui::ConfigurationEvent& Event )
{
    SolarMutexClearableGuard aReadLock;
    Reference< frame::XFrame >                xFrame( m_xFrame );
    rtl::Reference< ToolbarLayoutManager >    xToolbarManager( m_xToolbarManager );
    Reference< awt::XWindow >                 xContainerWindow( m_xContainerWindow );
    rtl::Reference< MenuBarWrapper >          xMenuBar( m_xMenuBar );
    Reference< ui::XUIConfigurationManager >  xModuleCfgMgr( m_xModuleCfgMgr );
    Reference< ui::XUIConfigurationManager >  xDocCfgMgr( m_xDocCfgMgr );
    aReadLock.clear();

    if ( !xFrame.is() )
        return;

    OUString aElementType;
    OUString aElementName;
    bool            bRefreshLayout(false);

    parseResourceURL( Event.ResourceURL, aElementType, aElementName );
    if ( aElementType.equalsIgnoreAsciiCase( UIRESOURCETYPE_TOOLBAR ))
    {
        if ( xToolbarManager.is() )
        {
            xToolbarManager->elementRemoved( Event );
            bRefreshLayout = xToolbarManager->isLayoutDirty();
        }
    }
    else
    {
        Reference< XUIElement > xUIElement = implts_findElement( Event.ResourceURL );
        Reference< XUIElementSettings > xElementSettings( xUIElement, UNO_QUERY );
        if ( xElementSettings.is() )
        {
            bool                      bNoSettings( false );
            OUString           aConfigSourcePropName( u"ConfigurationSource"_ustr );
            Reference< XInterface >   xElementCfgMgr;
            Reference< XPropertySet > xPropSet( xElementSettings, 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 ( Event.Source == xElementCfgMgr )
            {
                // Same UI configuration manager where our element has its settings
                if ( Event.Source == Reference< XInterface >( xDocCfgMgr, UNO_QUERY ))
                {
                    // document settings removed
                    if ( xModuleCfgMgr->hasSettings( Event.ResourceURL ))
                    {
                        xPropSet->setPropertyValue( aConfigSourcePropName, Any( m_xModuleCfgMgr ));
                        xElementSettings->updateSettings();
                        return;
                    }
                }

                bNoSettings = true;
            }

            // No settings anymore, element must be destroyed
            if ( xContainerWindow.is() && bNoSettings )
            {
                if ( aElementType.equalsIgnoreAsciiCase("menubar") &&
                     aElementName.equalsIgnoreAsciiCase("menubar") )
                {
                    SystemWindow* pSysWindow = getTopSystemWindow( xContainerWindow );
                    if ( pSysWindow && !m_bInplaceMenuSet )
                        pSysWindow->SetMenuBar( nullptr );

                    if ( xMenuBar.is() )
                        xMenuBar->dispose();

                    SolarMutexGuard g;
                    m_xMenuBar.clear();
                }
            }
        }
    }

    if ( bRefreshLayout )
        doLayout();
}

void SAL_CALL LayoutManager::elementReplaced( const ui::ConfigurationEvent& Event )
{
    SolarMutexClearableGuard aReadLock;
    Reference< XFrame >                       xFrame( m_xFrame );
    rtl::Reference< ToolbarLayoutManager >    xToolbarManager( m_xToolbarManager );
    aReadLock.clear();

    if ( !xFrame.is() )
        return;

    OUString aElementType;
    OUString aElementName;
    bool            bRefreshLayout(false);

    parseResourceURL( Event.ResourceURL, aElementType, aElementName );
    if ( aElementType.equalsIgnoreAsciiCase( UIRESOURCETYPE_TOOLBAR ))
    {
        if ( xToolbarManager.is() )
        {
            xToolbarManager->elementReplaced( Event );
            bRefreshLayout = xToolbarManager->isLayoutDirty();
        }
    }
    else
    {
        Reference< XUIElement >         xUIElement = implts_findElement( Event.ResourceURL );
        Reference< XUIElementSettings > xElementSettings( xUIElement, UNO_QUERY );
        if ( xElementSettings.is() )
        {
            Reference< XInterface >   xElementCfgMgr;
            Reference< XPropertySet > xPropSet( xElementSettings, UNO_QUERY );

            if ( xPropSet.is() )
                xPropSet->getPropertyValue( u"ConfigurationSource"_ustr ) >>= xElementCfgMgr;

            if ( !xElementCfgMgr.is() )
                return;

            // Check if the same UI configuration manager has changed => update settings
            if ( Event.Source == xElementCfgMgr )
                xElementSettings->updateSettings();
        }
    }

    if ( bRefreshLayout )
        doLayout();
}

void SAL_CALL LayoutManager::setFastPropertyValue_NoBroadcast( sal_Int32       nHandle,
                                                               const uno::Any& aValue  )
{
    if ( (nHandle != LAYOUTMANAGER_PROPHANDLE_REFRESHVISIBILITY) && (nHandle != LAYOUTMANAGER_PROPHANDLE_REFRESHTOOLTIP) )
        LayoutManager_PBase::setFastPropertyValue_NoBroadcast( nHandle, aValue );

    switch( nHandle )
    {
        case LAYOUTMANAGER_PROPHANDLE_MENUBARCLOSER:
            implts_updateMenuBarClose();
            break;

        case LAYOUTMANAGER_PROPHANDLE_REFRESHVISIBILITY:
        {
            bool bValue(false);
            if (( aValue >>= bValue ) && bValue )
            {
                SolarMutexClearableGuard aReadLock;
                ToolbarLayoutManager* pToolbarManager = m_xToolbarManager.get();
                bool bAutomaticToolbars( m_bAutomaticToolbars );
                aReadLock.clear();

                if ( pToolbarManager )
                    pToolbarManager->refreshToolbarsVisibility( bAutomaticToolbars );
            }
            break;
        }

        case LAYOUTMANAGER_PROPHANDLE_HIDECURRENTUI:
            implts_setCurrentUIVisibility( !m_bHideCurrentUI );
            break;

        case LAYOUTMANAGER_PROPHANDLE_REFRESHTOOLTIP:
            if (m_xToolbarManager.is())
                m_xToolbarManager->updateToolbarsTips();
            break;

        default: break;
    }
}

namespace detail
{
    class InfoHelperBuilder
    {
    private:
        std::unique_ptr<::cppu::OPropertyArrayHelper> m_pInfoHelper;
    public:
        explicit InfoHelperBuilder(const LayoutManager &rManager)
        {
            uno::Sequence< beans::Property > aProperties;
            rManager.describeProperties(aProperties);
            m_pInfoHelper.reset( new ::cppu::OPropertyArrayHelper(aProperties, true) );
        }
        InfoHelperBuilder(const InfoHelperBuilder&) = delete;
        InfoHelperBuilder& operator=(const InfoHelperBuilder&) = delete;

        ::cppu::OPropertyArrayHelper& getHelper() { return *m_pInfoHelper; }
    };
}

::cppu::IPropertyArrayHelper& SAL_CALL LayoutManager::getInfoHelper()
{
    static detail::InfoHelperBuilder INFO(*this);
    return INFO.getHelper();
}

uno::Reference< beans::XPropertySetInfo > SAL_CALL LayoutManager::getPropertySetInfo()
{
    static uno::Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );

    return xInfo;
}

} // namespace framework

extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
com_sun_star_comp_framework_LayoutManager_get_implementation(
    css::uno::XComponentContext *context,
    css::uno::Sequence<css::uno::Any> const &)
{
    return cppu::acquire(new framework::LayoutManager(context));
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
