Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/embeddedobj/source/general/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 44 kB image not shown  

Quelle  docholder.cxx   Sprache: C

 
/* -*- 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 <com/sun/star/embed/Aspects.hpp>
#include <com/sun/star/frame/TaskCreator.hpp>
#include <com/sun/star/frame/XTitle.hpp>
#include <com/sun/star/frame/TerminationVetoException.hpp>
#include <com/sun/star/frame/XComponentLoader.hpp>
#include <com/sun/star/frame/XSynchronousFrameLoader.hpp>
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
#include <com/sun/star/lang/XSingleComponentFactory.hpp>
#include <com/sun/star/util/CloseVetoException.hpp>
#include <com/sun/star/util/XCloseBroadcaster.hpp>
#include <com/sun/star/util/XCloseable.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/NamedValue.hpp>
#include <com/sun/star/frame/XModel.hpp>
#include <com/sun/star/frame/Desktop.hpp>
#include <com/sun/star/frame/XFramesSupplier.hpp>
#include <com/sun/star/frame/XControllerBorder.hpp>
#include <com/sun/star/util/XModifyBroadcaster.hpp>
#include <com/sun/star/frame/XDispatchProviderInterception.hpp>
#include <com/sun/star/awt/Toolkit.hpp>
#include <com/sun/star/awt/XTopWindow.hpp>
#include <com/sun/star/awt/PosSize.hpp>
#include <com/sun/star/awt/WindowAttribute.hpp>
#include <com/sun/star/awt/VclWindowPeerAttribute.hpp>
#include <com/sun/star/embed/XHatchWindow.hpp>
#include <com/sun/star/embed/HatchWindowFactory.hpp>
#include <com/sun/star/frame/XLayoutManager.hpp>
#include <com/sun/star/frame/XMenuBarMergingAcceptor.hpp>
#include <com/sun/star/frame/ModuleManager.hpp>
#include <com/sun/star/ui/XDockingAreaAcceptor.hpp>
#include <com/sun/star/ui/XUIElementSettings.hpp>
#include <com/sun/star/ui/XUIConfigurationManager.hpp>
#include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
#include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp>
#include <com/sun/star/embed/StateChangeInProgressException.hpp>

#include <com/sun/star/embed/EmbedMisc.hpp>
#include <com/sun/star/embed/EmbedStates.hpp>
#include <osl/diagnose.h>
#include <utility>
#include <vcl/svapp.hxx>
#include <unotools/resmgr.hxx>
#include <sfx2/strings.hrc>

#include <comphelper/processfactory.hxx>
#include <comphelper/namedvaluecollection.hxx>

#include <docholder.hxx>
#include <commonembobj.hxx>
#include <intercept.hxx>

#define HATCH_BORDER_WIDTH (((m_pEmbedObj->getStatus(embed::Aspects::MSOLE_CONTENT)&embed::EmbedMisc::MS_EMBED_ACTIVATEWHENVISIBLE)&nbsp;&& \
                            m_pEmbedObj->getCurrentState()!=embed::EmbedStates::UI_ACTIVE) ? 0 : 4 )

using namespace ::com::sun::star;

namespace {

class IntCounterGuard
{
    sal_Int32& m_rFlag;
public:
    explicit IntCounterGuard(sal_Int32& rFlag)
        : m_rFlag(rFlag)
    {
        ++m_rFlag;
    }

    ~IntCounterGuard()
    {
        if (m_rFlag)
            --m_rFlag;
    }
};

}

static void InsertMenu_Impl( const uno::Reference< container::XIndexContainer >& xTargetMenu,
                            sal_Int32 nTargetIndex,
                            const uno::Reference< container::XIndexAccess >& xSourceMenu,
                            sal_Int32 nSourceIndex,
                            const OUString& aContModuleName,
                            const uno::Reference< frame::XDispatchProvider >& xSourceDisp )
{
    sal_Int32 nInd = 0;
    OUString aModuleIdentPropName( u"ModuleIdentifier"_ustr );
    OUString aDispProvPropName( u"DispatchProvider"_ustr );
    bool bModuleNameSet = false;
    bool bDispProvSet = false;

    uno::Sequence< beans::PropertyValue > aSourceProps;
    xSourceMenu->getByIndex( nSourceIndex ) >>= aSourceProps;
    uno::Sequence< beans::PropertyValue > aTargetProps( aSourceProps.getLength() );
    auto aTargetPropsRange = asNonConstRange(aTargetProps);
    for ( nInd = 0; nInd < aSourceProps.getLength(); nInd++ )
    {
        aTargetPropsRange[nInd].Name = aSourceProps[nInd].Name;
        if ( !aContModuleName.isEmpty() && aTargetProps[nInd].Name == aModuleIdentPropName )
        {
            aTargetPropsRange[nInd].Value <<= aContModuleName;
            bModuleNameSet = true;
        }
        else if ( aTargetProps[nInd].Name == aDispProvPropName )
        {
            aTargetPropsRange[nInd].Value <<= xSourceDisp;
            bDispProvSet = true;
        }
        else
            aTargetPropsRange[nInd].Value = aSourceProps[nInd].Value;
    }

    if ( !bModuleNameSet && !aContModuleName.isEmpty() )
    {
        aTargetProps.realloc( ++nInd );
        auto pTargetProps = aTargetProps.getArray();
        pTargetProps[nInd-1].Name = aModuleIdentPropName;
        pTargetProps[nInd-1].Value <<= aContModuleName;
    }

    if ( !bDispProvSet && xSourceDisp.is() )
    {
        aTargetProps.realloc( ++nInd );
        auto pTargetProps = aTargetProps.getArray();
        pTargetProps[nInd-1].Name = aDispProvPropName;
        pTargetProps[nInd-1].Value <<= xSourceDisp;
    }

    xTargetMenu->insertByIndex( nTargetIndex, uno::Any( aTargetProps ) );
}

namespace embeddedobj
{

DocumentHolder::DocumentHolder( uno::Reference< uno::XComponentContext > xContext,
                                OCommonEmbeddedObject* pEmbObj )
: m_pEmbedObj( pEmbObj ),
  m_xContext(std::move( xContext )),
  m_bReadOnly( false ),
  m_bWaitForClose( false ),
  m_bAllowClosing( false ),
  m_bDesktopTerminated( false ),
  m_nNoBorderResizeReact( 0 ),
  m_nNoResizeReact( 0 )
{
    uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create( m_xContext );
    osl_atomic_increment(&m_refCount);
    try
    {
        xDesktop->addTerminateListener( this );
    }
    catch ( const uno::Exception& )
    {
    }
    osl_atomic_decrement(&m_refCount);

    m_aOutplaceFrameProps = { uno::Any(beans::NamedValue{ u"TopWindow"_ustr, uno::Any(true) }),
                              uno::Any(beans::NamedValue{ u"MakeVisible"_ustr, uno::Any(false) }),
                              //TODO/LATER: should use parent document frame
                              uno::Any(beans::NamedValue{ u"ParentFrame"_ustr, uno::Any(xDesktop) }) };
}


DocumentHolder::~DocumentHolder()
{
    osl_atomic_increment(&m_refCount); // to allow deregistration as a listener

    if( m_xFrame.is() )
        CloseFrame();

    if ( m_xComponent.is() )
    {
        try {
            CloseDocument( truefalse );
        } catchconst uno::Exception& ) {}
    }

    if ( m_xInterceptor.is() )
    {
        m_xInterceptor->DisconnectDocHolder();
        m_xInterceptor.clear();
    }

    if ( !m_bDesktopTerminated )
        FreeOffice();
}


void DocumentHolder::CloseFrame()
{
    uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xFrame, uno::UNO_QUERY );
    if ( xCloseBroadcaster.is() )
        xCloseBroadcaster->removeCloseListener( static_cast<util::XCloseListener*>(this) );

    uno::Reference<util::XCloseable> xCloseable(
        m_xFrame,uno::UNO_QUERY );
    if( xCloseable.is() )
        try {
            xCloseable->close( true );
        }
        catchconst uno::Exception& ) {
        }
    else {
        if( m_xFrame.is() )
            m_xFrame->dispose();
    }

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

    m_xHatchWindow.clear();
    m_xOwnWindow.clear();
    m_xFrame.clear();
}


void DocumentHolder::FreeOffice()
{
    try {
        uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create( m_xContext );
        xDesktop->removeTerminateListener( this );
    } catch (const css::uno::DeploymentException&) {
        // if this happens, the desktop is already gone
    }

    // the following code is commented out since for now there is still no completely correct way to detect
    // whether the office can be terminated, so it is better to have unnecessary process running than
    // to lose any data

//      uno::Reference< frame::XFramesSupplier > xFramesSupplier( xDesktop, uno::UNO_QUERY );
//      if ( xFramesSupplier.is() )
//      {
//          uno::Reference< frame::XFrames > xFrames = xFramesSupplier->getFrames();
//          if ( xFrames.is() && !xFrames->hasElements() )
//          {
//              try
//              {
//                  xDesktop->terminate();
//              }
//              catch( uno::Exception & )
//              {}
//          }
//      }
}


void DocumentHolder::CloseDocument( bool bDeliverOwnership, bool bWaitForClose )
{
    if ( m_xComponent.is() )
    {
        uno::Reference< document::XEventBroadcaster > xEventBroadcaster( m_xComponent, uno::UNO_QUERY );
        if ( xEventBroadcaster.is() )
            xEventBroadcaster->removeEventListener( static_cast<document::XEventListener*>(this);
        else
        {
            // the object does not support document::XEventBroadcaster interface
            // use the workaround, register for modified events
            uno::Reference< util::XModifyBroadcaster > xModifyBroadcaster( m_xComponent, uno::UNO_QUERY );
            if ( xModifyBroadcaster.is() )
                xModifyBroadcaster->removeModifyListener( static_cast<util::XModifyListener*>(this) );
        }

        m_bAllowClosing = true;
        m_bWaitForClose = bWaitForClose;
        m_xComponent->close( bDeliverOwnership );
    }

    m_xComponent = nullptr;
}


void DocumentHolder::PlaceFrame( const awt::Rectangle& aNewRect )
{
    OSL_ENSURE( m_xFrame.is() && m_xOwnWindow.is(),
                "The object does not have windows required for inplace mode!" );

    //TODO: may need mutex locking???
    if ( !(m_xFrame.is() && m_xOwnWindow.is()) )
        return;

    // the frame can be replaced only in inplace mode
    frame::BorderWidths aOldWidths;
    IntCounterGuard aGuard( m_nNoBorderResizeReact );

    do
    {
        aOldWidths = m_aBorderWidths;

        awt::Rectangle aHatchRect = AddBorderToArea( aNewRect );

        ResizeWindows_Impl( aHatchRect );

    } while ( aOldWidths.Left != m_aBorderWidths.Left
           || aOldWidths.Top != m_aBorderWidths.Top
           || aOldWidths.Right != m_aBorderWidths.Right
           || aOldWidths.Bottom != m_aBorderWidths.Bottom );

    m_aObjRect = aNewRect;
}


void DocumentHolder::ResizeWindows_Impl( const awt::Rectangle& aHatchRect )
{
    OSL_ENSURE( m_xFrame.is() && m_xOwnWindow.is() /*&& m_xHatchWindow.is()*/,
                "The object does not have windows required for inplace mode!" );
    if ( m_xHatchWindow.is() )
    {
        m_xOwnWindow->setPosSize( HATCH_BORDER_WIDTH,
                                  HATCH_BORDER_WIDTH,
                                  aHatchRect.Width - 2*HATCH_BORDER_WIDTH,
                                  aHatchRect.Height - 2*HATCH_BORDER_WIDTH,
                                  awt::PosSize::POSSIZE );


        m_xHatchWindow->setPosSize( aHatchRect.X,
                                    aHatchRect.Y,
                                    aHatchRect.Width,
                                    aHatchRect.Height,
                                    awt::PosSize::POSSIZE );
    }
    else
        m_xOwnWindow->setPosSize( aHatchRect.X + HATCH_BORDER_WIDTH,
                                  aHatchRect.Y + HATCH_BORDER_WIDTH,
                                  aHatchRect.Width - 2*HATCH_BORDER_WIDTH,
                                  aHatchRect.Height - 2*HATCH_BORDER_WIDTH,
                                  awt::PosSize::POSSIZE );
}


bool DocumentHolder::SetFrameLMVisibility( const uno::Reference< frame::XFrame >& xFrame, bool bVisible )
{
    bool bResult = false;

    try
    {
        uno::Reference< css::frame::XLayoutManager > xLayoutManager;
        uno::Reference< beans::XPropertySet > xPropSet( xFrame, uno::UNO_QUERY_THROW );
        xPropSet->getPropertyValue(u"LayoutManager"_ustr) >>= xLayoutManager;
        if ( xLayoutManager.is() )
        {
            xLayoutManager->setVisible( bVisible );

            // MBA: locking is done only on the container LM, because it is not about hiding windows, it's about
            // giving up control over the component window (and stopping to listen for resize events of the container window)
            if ( bVisible )
                xLayoutManager->unlock();
            else
                xLayoutManager->lock();

            bResult = true;
        }
    }
    catchconst uno::Exception& )
    {}

    return bResult;
}


bool DocumentHolder::ShowInplace( const uno::Reference< awt::XWindowPeer >& xParent,
                                      const awt::Rectangle& aRectangleToShow,
                                      const uno::Reference< frame::XDispatchProvider >& xContDisp )
{
    OSL_ENSURE( !m_xFrame.is(), "A frame exists already!" );

    if ( !m_xFrame.is() )
    {
        uno::Reference < frame::XModel > xModel( GetComponent(), uno::UNO_QUERY );
        awt::Rectangle aHatchRectangle = AddBorderToArea( aRectangleToShow );

        awt::Rectangle aOwnRectangle(  HATCH_BORDER_WIDTH,
                                    HATCH_BORDER_WIDTH,
                                    aHatchRectangle.Width - 2*HATCH_BORDER_WIDTH,
                                    aHatchRectangle.Height - 2*HATCH_BORDER_WIDTH );
        uno::Reference< awt::XWindow > xHWindow;
        uno::Reference< awt::XWindowPeer > xMyParent( xParent );

        if ( xModel.is() )
        {

            uno::Reference< embed::XHatchWindowFactory > xHatchFactory =
                    embed::HatchWindowFactory::create(m_xContext);

            uno::Reference< embed::XHatchWindow > xHatchWindow =
                            xHatchFactory->createHatchWindowInstance( xParent,
                                                                      aHatchRectangle,
                                                                      awt::Size( HATCH_BORDER_WIDTH, HATCH_BORDER_WIDTH ) );

            uno::Reference< awt::XWindowPeer > xHatchWinPeer( xHatchWindow, uno::UNO_QUERY );
            xHWindow.set( xHatchWinPeer, uno::UNO_QUERY_THROW );

            xHatchWindow->setController( uno::Reference< embed::XHatchWindowController >(
                                                static_cast< embed::XHatchWindowController* >( this ) ) );

            xMyParent = std::move(xHatchWinPeer);
        }
        else
        {
            aOwnRectangle.X += aHatchRectangle.X;
            aOwnRectangle.Y += aHatchRectangle.Y;
        }

        awt::WindowDescriptor aOwnWinDescriptor( awt::WindowClass_TOP,
                                                u"dockingwindow"_ustr,
                                                xMyParent,
                                                0,
                                                awt::Rectangle(),//aOwnRectangle,
                                                awt::WindowAttribute::SHOW | awt::VclWindowPeerAttribute::CLIPCHILDREN );

        uno::Reference< awt::XToolkit2 > xToolkit = awt::Toolkit::create(m_xContext);

        uno::Reference< awt::XWindowPeer > xNewWinPeer = xToolkit->createWindow( aOwnWinDescriptor );
        uno::Reference< awt::XWindow > xOwnWindow( xNewWinPeer, uno::UNO_QUERY_THROW );
        uno::Reference< frame::XFrame > xContFrame( xContDisp, uno::UNO_QUERY );

        // create a frame based on the specified window
        uno::Reference< lang::XSingleServiceFactory > xFrameFact = frame::TaskCreator::create(m_xContext);

        uno::Sequence< uno::Any > aArgs( xContFrame.is() ? 2 : 1 );
        auto pArgs = aArgs.getArray();
        beans::NamedValue aArg;

        aArg.Name    = "ContainerWindow";
        aArg.Value <<= xOwnWindow;
        pArgs[0] <<= aArg;

        if ( xContFrame.is() )
        {
            aArg.Name    = "ParentFrame";
            aArg.Value <<= xContFrame;
            pArgs[1] <<= aArg;
        }

        // the call will create, initialize the frame, and register it in the parent
        m_xFrame.set( xFrameFact->createInstanceWithArguments( aArgs ), uno::UNO_QUERY_THROW );

        m_xHatchWindow = std::move(xHWindow);
        m_xOwnWindow = std::move(xOwnWindow);

        if ( !SetFrameLMVisibility( m_xFrame, false ) )
        {
            OSL_FAIL( "Can't deactivate LayoutManager!" );
            // TODO/LATER: error handling?
        }

        // m_bIsInplace = sal_True; TODO: ?

        uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xFrame, uno::UNO_QUERY );
        if ( xCloseBroadcaster.is() )
            xCloseBroadcaster->addCloseListener( static_cast<util::XCloseListener*>(this) );

        // TODO: some listeners to the frame and the window ( resize for example )
    }

    if ( !m_xComponent )
        return false;

    if ( !LoadDocToFrame( true ) )
    {
        CloseFrame();
        return false;
    }

    uno::Reference< frame::XControllerBorder > xControllerBorder( m_xFrame->getController(), uno::UNO_QUERY );
    if ( xControllerBorder.is() )
    {
        m_aBorderWidths = xControllerBorder->getBorder();
        xControllerBorder->addBorderResizeListener( static_cast<frame::XBorderResizeListener*>(this) );
    }

    PlaceFrame( aRectangleToShow );

    if ( m_xHatchWindow.is() )
        m_xHatchWindow->setVisible( true );

    return true;
}


uno::Reference< container::XIndexAccess > DocumentHolder::RetrieveOwnMenu_Impl()
{
    uno::Reference< container::XIndexAccess > xResult;

    uno::Reference< css::ui::XUIConfigurationManagerSupplier > xUIConfSupplier(
                m_xComponent,
                uno::UNO_QUERY );
    uno::Reference< css::ui::XUIConfigurationManager > xUIConfigManager;
    if( xUIConfSupplier.is())
    {
        xUIConfigManager.set(
            xUIConfSupplier->getUIConfigurationManager(),
            uno::UNO_SET_THROW );
    }

    try
    {
        if( xUIConfigManager.is())
        {
            xResult = xUIConfigManager->getSettings(
                u"private:resource/menubar/menubar"_ustr,
                false );
        }
    }
    catchconst uno::Exception& )
    {}

    if ( !xResult.is() )
    {
        // no internal document configuration, use the one from the module
        uno::Reference< frame::XModuleManager2 > xModuleMan = frame::ModuleManager::create(m_xContext);
        OUString aModuleIdent =
            xModuleMan->identify( uno::Reference< uno::XInterface >( m_xComponent, uno::UNO_QUERY ) );

        if ( !aModuleIdent.isEmpty() )
        {
            uno::Reference< ui::XModuleUIConfigurationManagerSupplier > xModConfSupplier =
                    ui::theModuleUIConfigurationManagerSupplier::get(m_xContext);
            uno::Reference< css::ui::XUIConfigurationManager > xModUIConfMan(
                    xModConfSupplier->getUIConfigurationManager( aModuleIdent ),
                    uno::UNO_SET_THROW );
            xResult = xModUIConfMan->getSettings(
                    u"private:resource/menubar/menubar"_ustr,
                    false );
        }
    }

    if ( !xResult.is() )
        throw uno::RuntimeException(u"Unable to retrieve the UI configuration menu."_ustr, getXWeak());

    return xResult;
}


void DocumentHolder::FindConnectPoints(
        const uno::Reference< container::XIndexAccess >& xMenu,
        sal_Int32 nConnectPoints[2] )
{
    nConnectPoints[0] = -1;
    nConnectPoints[1] = -1;
    for ( sal_Int32 nInd = 0; nInd < xMenu->getCount(); nInd++ )
    {
        uno::Sequence< beans::PropertyValue > aProps;
        xMenu->getByIndex( nInd ) >>= aProps;
        OUString aCommand;
        for (beans::PropertyValue const& prop : aProps)
            if ( prop.Name == "CommandURL" )
            {
                prop.Value >>= aCommand;
                break;
            }

        if ( aCommand.isEmpty() )
            throw uno::RuntimeException("CommandURL is empty at index: " + OUString::number(nInd),  xMenu);

        if ( aCommand == ".uno:PickList" )
            nConnectPoints[0] = nInd;
        else if ( aCommand == ".uno:WindowList" )
            nConnectPoints[1] = nInd;
    }
}


uno::Reference< container::XIndexAccess > DocumentHolder::MergeMenusForInplace(
        const uno::Reference< container::XIndexAccess >& xContMenu,
        const uno::Reference< frame::XDispatchProvider >& xContDisp,
        const OUString& aContModuleName,
        const uno::Reference< container::XIndexAccess >& xOwnMenu,
        const uno::Reference< frame::XDispatchProvider >& xOwnDisp )
{
    // TODO/LATER: use dispatch providers on merge

    sal_Int32 nContPoints[2];
    sal_Int32 nOwnPoints[2];

    uno::Reference< lang::XSingleComponentFactory > xIndAccessFact( xContMenu, uno::UNO_QUERY_THROW );

    uno::Reference< container::XIndexContainer > xMergedMenu(
            xIndAccessFact->createInstanceWithContext(
                comphelper::getProcessComponentContext() ),
            uno::UNO_QUERY_THROW );

    FindConnectPoints( xContMenu, nContPoints );
    FindConnectPoints( xOwnMenu, nOwnPoints );

    for ( sal_Int32 nInd = 0; nInd < xOwnMenu->getCount(); nInd++ )
    {
        if ( nOwnPoints[0] == nInd )
        {
            if ( nContPoints[0] >= 0 && nContPoints[0] < xContMenu->getCount() )
            {
                InsertMenu_Impl( xMergedMenu, nInd, xContMenu, nContPoints[0], aContModuleName, xContDisp );
            }
        }
        else if ( nOwnPoints[1] == nInd )
        {
            if ( nContPoints[1] >= 0 && nContPoints[1] < xContMenu->getCount() )
            {
                InsertMenu_Impl( xMergedMenu, nInd, xContMenu, nContPoints[1], aContModuleName, xContDisp );
            }
        }
        else
            InsertMenu_Impl( xMergedMenu, nInd, xOwnMenu, nInd, OUString(), xOwnDisp );
    }

    return uno::Reference< container::XIndexAccess >( xMergedMenu, uno::UNO_QUERY_THROW );
}


bool DocumentHolder::MergeMenus_Impl( const uno::Reference< css::frame::XLayoutManager >& xOwnLM,
                                            const uno::Reference< css::frame::XLayoutManager >& xContLM,
                                            const uno::Reference< frame::XDispatchProvider >& xContDisp,
                                            const OUString& aContModuleName )
{
    bool bMenuMerged = false;
    try
    {
        uno::Reference< css::ui::XUIElementSettings > xUISettings(
            xContLM->getElement( u"private:resource/menubar/menubar"_ustr ),
            uno::UNO_QUERY_THROW );
        uno::Reference< container::XIndexAccess > xContMenu = xUISettings->getSettings( true );
        if ( !xContMenu.is() )
            throw uno::RuntimeException(u"Unable to merge the menu"_ustr, getXWeak());

        uno::Reference< container::XIndexAccess > xOwnMenu = RetrieveOwnMenu_Impl();
        uno::Reference< frame::XDispatchProvider > xOwnDisp( m_xFrame, uno::UNO_QUERY_THROW );

        uno::Reference< container::XIndexAccess > xMergedMenu = MergeMenusForInplace( xContMenu, xContDisp, aContModuleName, xOwnMenu, xOwnDisp );
        uno::Reference< css::frame::XMenuBarMergingAcceptor > xMerge( xOwnLM,
                                                                                         uno::UNO_QUERY_THROW );
        bMenuMerged = xMerge->setMergedMenuBar( xMergedMenu );
    }
    catchconst uno::Exception& )
    {}

    return bMenuMerged;
}

bool DocumentHolder::ShowUI( const uno::Reference< css::frame::XLayoutManager >& xContainerLM,
                                 const uno::Reference< frame::XDispatchProvider >& xContainerDP,
                                 const OUString& aContModuleName )
{
    bool bResult = false;
    if ( xContainerLM.is() )
    {
        // the LM of the embedded frame and its current DockingAreaAcceptor
        uno::Reference< css::frame::XLayoutManager > xOwnLM;
        uno::Reference< css::ui::XDockingAreaAcceptor > xDocAreaAcc;

        try
        {
            uno::Reference< beans::XPropertySet > xPropSet( m_xFrame, uno::UNO_QUERY_THROW );
            xPropSet->getPropertyValue(u"LayoutManager"_ustr) >>= xOwnLM;
            xDocAreaAcc = xContainerLM->getDockingAreaAcceptor();
        }
        catchconst uno::Exception& ){}

        if ( xOwnLM.is() && xDocAreaAcc.is() )
        {
            // make sure that lock state of LM is correct even if an exception is thrown in between
            bool bUnlockContainerLM = false;
            bool bLockOwnLM = false;
            try
            {
                // take over the control over the containers window
                // as long as the LM is invisible and locked an empty tool space will be used on resizing
                xOwnLM->setDockingAreaAcceptor( xDocAreaAcc );

                // try to merge menus; don't do anything else if it fails
                if ( MergeMenus_Impl( xOwnLM, xContainerLM, xContainerDP, aContModuleName ) )
                {
                    // make sure that the container LM does not control the size of the containers window anymore
                    // this must be done after merging menus as we won't get the container menu otherwise
                    xContainerLM->setDockingAreaAcceptor( uno::Reference < ui::XDockingAreaAcceptor >() );

                    uno::Reference< lang::XServiceInfo> xServiceInfo(m_xComponent, uno::UNO_QUERY);
                    if (!xServiceInfo.is() || !xServiceInfo->supportsService(u"com.sun.star.chart2.ChartDocument"_ustr))
                    {
                        // prevent further changes at this LM
                        xContainerLM->setVisible(false);
                        xContainerLM->lock();
                        bUnlockContainerLM = true;
                    }

                    // by unlocking the LM each layout change will now resize the containers window; pending layouts will be processed now
                    xOwnLM->setVisible( true );

                    uno::Reference< frame::XFramesSupplier > xSupp = m_xFrame->getCreator();
                    if ( xSupp.is() )
                        xSupp->setActiveFrame( m_xFrame );

                    xOwnLM->unlock();
                    bLockOwnLM = true;
                    bResult = true;

                    // TODO/LATER: The following action should be done only if the window is not hidden
                    // otherwise the activation must fail, unfortunately currently it is not possible
                    // to detect whether the window is hidden using UNO API
                    m_xOwnWindow->setFocus();
                }
            }
            catchconst uno::Exception& )
            {
                // activation failed; reestablish old state
                try
                {
                    uno::Reference< frame::XFramesSupplier > xSupp = m_xFrame->getCreator();
                    if ( xSupp.is() )
                        xSupp->setActiveFrame( nullptr );

                    // remove control about containers window from own LM
                    if (bLockOwnLM)
                        xOwnLM->lock();
                    xOwnLM->setVisible( false );
                    xOwnLM->setDockingAreaAcceptor( uno::Reference< css::ui::XDockingAreaAcceptor >() );

                    // unmerge menu
                    uno::Reference< css::frame::XMenuBarMergingAcceptor > xMerge( xOwnLM, uno::UNO_QUERY_THROW );
                    xMerge->removeMergedMenuBar();
                }
                catchconst uno::Exception& ) {}

                try
                {
                    // reestablish control of containers window
                    xContainerLM->setDockingAreaAcceptor( xDocAreaAcc );
                    xContainerLM->setVisible( true );
                    if (bUnlockContainerLM)
                        xContainerLM->unlock();
                }
                catchconst uno::Exception& ) {}
            }
        }
    }

    return bResult;
}


bool DocumentHolder::HideUI( const uno::Reference< css::frame::XLayoutManager >& xContainerLM )
{
    bool bResult = false;

    if ( xContainerLM.is() )
    {
        uno::Reference< css::frame::XLayoutManager > xOwnLM;

        try {
            uno::Reference< beans::XPropertySet > xPropSet( m_xFrame, uno::UNO_QUERY_THROW );
            xPropSet->getPropertyValue(u"LayoutManager"_ustr) >>= xOwnLM;
        } catchconst uno::Exception& )
        {}

        if ( xOwnLM.is() )
        {
            try {
                uno::Reference< frame::XFramesSupplier > xSupp = m_xFrame->getCreator();
                if ( xSupp.is() )
                    xSupp->setActiveFrame( nullptr );

                uno::Reference< css::ui::XDockingAreaAcceptor > xDocAreaAcc = xOwnLM->getDockingAreaAcceptor();

                xOwnLM->setDockingAreaAcceptor( uno::Reference < ui::XDockingAreaAcceptor >() );
                xOwnLM->lock();
                xOwnLM->setVisible( false );

                uno::Reference< css::frame::XMenuBarMergingAcceptor > xMerge( xOwnLM, uno::UNO_QUERY_THROW );
                xMerge->removeMergedMenuBar();

                xContainerLM->setDockingAreaAcceptor( xDocAreaAcc );
                uno::Reference< lang::XServiceInfo> xServiceInfo(m_xComponent, uno::UNO_QUERY);
                if (!xServiceInfo.is() || !xServiceInfo->supportsService(u"com.sun.star.chart2.ChartDocument"_ustr))
                {
                    xContainerLM->setVisible(true);
                    xContainerLM->unlock();
                }

                xContainerLM->doLayout();
                bResult = true;
            }
            catchconst uno::Exception& )
            {
                SetFrameLMVisibility( m_xFrame, true );
            }
        }
    }

    return bResult;
}


uno::Reference< frame::XFrame > const & DocumentHolder::GetDocFrame()
{
    // the frame for outplace activation
    if ( !m_xFrame.is() )
    {
        uno::Reference< lang::XSingleServiceFactory > xFrameFact = frame::TaskCreator::create(m_xContext);

        m_xFrame.set(xFrameFact->createInstanceWithArguments( m_aOutplaceFrameProps ), uno::UNO_QUERY_THROW);

        uno::Reference< frame::XDispatchProviderInterception > xInterception( m_xFrame, uno::UNO_QUERY );
        if ( xInterception.is() )
        {
            if ( m_xInterceptor.is() )
            {
                m_xInterceptor->DisconnectDocHolder();
                m_xInterceptor.clear();
            }

            m_xInterceptor = new Interceptor( this );

            xInterception->registerDispatchProviderInterceptor( m_xInterceptor );

            // register interceptor from outside
            if ( m_xOutplaceInterceptor.is() )
                xInterception->registerDispatchProviderInterceptor( m_xOutplaceInterceptor );
        }

        uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xFrame, uno::UNO_QUERY );
        if ( xCloseBroadcaster.is() )
            xCloseBroadcaster->addCloseListener( static_cast<util::XCloseListener*>(this) );
    }

    if ( m_xComponent.is() )
    {
        uno::Reference< css::frame::XLayoutManager > xOwnLM;
        try {
            uno::Reference< beans::XPropertySet > xPropSet( m_xFrame, uno::UNO_QUERY_THROW );
            xPropSet->getPropertyValue(u"LayoutManager"_ustr) >>= xOwnLM;
        } catchconst uno::Exception& )
        {}

        if ( xOwnLM.is() )
            xOwnLM->lock();

        // TODO/LATER: get it for the real aspect
        awt::Size aSize;
        LoadDocToFrame(false);

        if ( xOwnLM.is() )
        {
            xOwnLM->unlock();
            xOwnLM->lock();
        }

        GetExtent(embed::Aspects::MSOLE_CONTENT, &aSize);
        SetExtent(embed::Aspects::MSOLE_CONTENT, aSize);

        if ( xOwnLM.is() )
            xOwnLM->unlock();
    }

    try
    {
        uno::Reference< awt::XWindow > xHWindow = m_xFrame->getContainerWindow();

        if( xHWindow.is() )
        {
            sal_Int32 nDisplay = Application::GetDisplayBuiltInScreen();

            AbsoluteScreenPixelRectangle aWorkRect = Application::GetScreenPosSizePixel( nDisplay );
            awt::Rectangle aWindowRect = xHWindow->getPosSize();

            if (( aWindowRect.Width < aWorkRect.GetWidth()) && ( aWindowRect.Height < aWorkRect.GetHeight() ))
            {
                int OffsetX = ( aWorkRect.GetWidth() - aWindowRect.Width ) / 2 + aWorkRect.Left();
                int OffsetY = ( aWorkRect.GetHeight() - aWindowRect.Height ) /2 + aWorkRect.Top();
                xHWindow->setPosSize( OffsetX, OffsetY, aWindowRect.Width, aWindowRect.Height, awt::PosSize::POS );
            }
            else
            {
                xHWindow->setPosSize( aWorkRect.Left(), aWorkRect.Top(), aWorkRect.GetWidth(), aWorkRect.GetHeight(), awt::PosSize::POSSIZE );
            }

            xHWindow->setVisible( true );
        }
    }
    catch ( const uno::Exception& )
    {
    }

    return m_xFrame;
}


void DocumentHolder::SetComponent( const uno::Reference< util::XCloseable >& xDoc, bool bReadOnly )
{
    if ( m_xComponent.is() )
    {
        // May be should be improved
        try {
            CloseDocument( truefalse );
        } catchconst uno::Exception& )
        {}
    }

    m_xComponent = xDoc;

    m_bReadOnly = bReadOnly;
    m_bAllowClosing = false;

    if ( m_xComponent.is() )
        m_xComponent->addCloseListener( static_cast<util::XCloseListener*>(this) );

    uno::Reference< document::XEventBroadcaster > xEventBroadcaster( m_xComponent, uno::UNO_QUERY );
    if ( xEventBroadcaster.is() )
        xEventBroadcaster->addEventListener( static_cast<document::XEventListener*>(this) );
    else
    {
        // the object does not support document::XEventBroadcaster interface
        // use the workaround, register for modified events
        uno::Reference< util::XModifyBroadcaster > xModifyBroadcaster( m_xComponent, uno::UNO_QUERY );
        if ( xModifyBroadcaster.is() )
            xModifyBroadcaster->addModifyListener( static_cast<util::XModifyListener*>(this) );
    }

    if ( m_xFrame.is() )
        LoadDocToFrame(false);
}


bool DocumentHolder::LoadDocToFrame( bool bInPlace )
{
    if ( !m_xFrame || !m_xComponent )
        return true;

    uno::Reference < frame::XModel > xDoc( m_xComponent, uno::UNO_QUERY );
    if ( xDoc.is() )
    {
        // load new document into the frame
        uno::Reference< frame::XComponentLoader > xComponentLoader( m_xFrame, uno::UNO_QUERY_THROW );

        ::comphelper::NamedValueCollection aArgs;
        aArgs.put( u"Model"_ustr, m_xComponent );
        aArgs.put( u"ReadOnly"_ustr, m_bReadOnly );

        // set document title to show in the title bar
        css::uno::Reference< css::frame::XTitle > xModelTitle( xDoc, css::uno::UNO_QUERY );
        if( xModelTitle.is() && m_pEmbedObj && !m_pEmbedObj->getContainerName().isEmpty() )
        {
            std::locale aResLoc = Translate::Create("sfx");
            OUString sEmbedded = Translate::get(STR_EMBEDDED_TITLE, aResLoc);
            xModelTitle->setTitle( m_pEmbedObj->getContainerName() + sEmbedded );
            m_aContainerName = m_pEmbedObj->getContainerName();
            // TODO: get real m_aDocumentNamePart
            m_aDocumentNamePart = sEmbedded;
        }

        if ( bInPlace )
            aArgs.put( u"PluginMode"_ustr, sal_Int16(1) );
        OUString sUrl;
        uno::Reference< lang::XServiceInfo> xServiceInfo(xDoc,uno::UNO_QUERY);
        if (    xServiceInfo.is()
            &&  xServiceInfo->supportsService(u"com.sun.star.report.ReportDefinition"_ustr) )
        {
            sUrl = ".component:DB/ReportDesign";
        }
        else if( xServiceInfo.is()
            &&   xServiceInfo->supportsService(u"com.sun.star.chart2.ChartDocument"_ustr))
            sUrl = "private:factory/schart";
        else
            sUrl = "private:object";

        xComponentLoader->loadComponentFromURL( sUrl,
                                                    u"_self"_ustr,
                                                    0,
                                                    aArgs.getPropertyValues() );

        return true;
    }
    else
    {
        uno::Reference < frame::XSynchronousFrameLoader > xLoader( m_xComponent, uno::UNO_QUERY );
        if ( xLoader.is() )
            return xLoader->load( uno::Sequence < beans::PropertyValue >(), m_xFrame );
        else
            return false;
    }

    return true;
}


void DocumentHolder::Show()
{
    if( m_xFrame.is() )
    {
        m_xFrame->activate();
        uno::Reference<awt::XTopWindow> xTopWindow( m_xFrame->getContainerWindow(), uno::UNO_QUERY );
        if( xTopWindow.is() )
            xTopWindow->toFront();
    }
    else
        GetDocFrame();
}


bool DocumentHolder::SetExtent( sal_Int64 nAspect, const awt::Size& aSize )
{
    uno::Reference< embed::XVisualObject > xDocVis( m_xComponent, uno::UNO_QUERY );
    if ( xDocVis.is() )
    {
        try
        {
            xDocVis->setVisualAreaSize( nAspect, aSize );
            return true;
        }
        catchconst uno::Exception& )
        {
            // TODO: Error handling
        }
    }

    return false;
}


bool DocumentHolder::GetExtent( sal_Int64 nAspect, awt::Size *pSize )
{
    uno::Reference< embed::XVisualObject > xDocVis( m_xComponent, uno::UNO_QUERY );
    if ( pSize && xDocVis.is() )
    {
        try
        {
            *pSize = xDocVis->getVisualAreaSize( nAspect );
            return true;
        }
        catchconst uno::Exception& )
        {
            // TODO: Error handling
        }
    }

    return false;
}


sal_Int32 DocumentHolder::GetMapUnit( sal_Int64 nAspect )
{
    uno::Reference< embed::XVisualObject > xDocVis( m_xComponent, uno::UNO_QUERY );
    if ( xDocVis.is() )
    {
        try
        {
            return xDocVis->getMapUnit( nAspect );
        }
        catchconst uno::Exception& )
        {
            // TODO: Error handling
        }
    }

    return 0;
}


awt::Rectangle DocumentHolder::CalculateBorderedArea( const awt::Rectangle& aRect )
{
    return awt::Rectangle( aRect.X + m_aBorderWidths.Left + HATCH_BORDER_WIDTH,
                             aRect.Y + m_aBorderWidths.Top + HATCH_BORDER_WIDTH,
                             aRect.Width - m_aBorderWidths.Left - m_aBorderWidths.Right - 2*HATCH_BORDER_WIDTH,
                             aRect.Height - m_aBorderWidths.Top - m_aBorderWidths.Bottom - 2*HATCH_BORDER_WIDTH );
}


awt::Rectangle DocumentHolder::AddBorderToArea( const awt::Rectangle& aRect )
{
    return awt::Rectangle( aRect.X - m_aBorderWidths.Left - HATCH_BORDER_WIDTH,
                             aRect.Y - m_aBorderWidths.Top - HATCH_BORDER_WIDTH,
                             aRect.Width + m_aBorderWidths.Left + m_aBorderWidths.Right + 2*HATCH_BORDER_WIDTH,
                             aRect.Height + m_aBorderWidths.Top + m_aBorderWidths.Bottom + 2*HATCH_BORDER_WIDTH );
}


void SAL_CALL DocumentHolder::disposing( const css::lang::EventObject& aSource )
{
    if ( m_xComponent.is() && m_xComponent == aSource.Source )
    {
        m_xComponent = nullptr;
        if ( m_bWaitForClose )
        {
            m_bWaitForClose = false;
            FreeOffice();
        }
    }

    if( m_xFrame.is() && m_xFrame == aSource.Source )
    {
        m_xHatchWindow.clear();
        m_xOwnWindow.clear();
        m_xFrame.clear();
    }
}


void SAL_CALL DocumentHolder::queryClosing( const lang::EventObject& aSource, sal_Bool /*bGetsOwnership*/ )
{
    if ( m_xComponent.is() && m_xComponent == aSource.Source && !m_bAllowClosing )
        throw util::CloseVetoException(u"To close an embedded document, close the document holder (document definition), not the document itself."_ustr, static_cast< ::cppu::OWeakObject*>(this));
}


void SAL_CALL DocumentHolder::notifyClosing( const lang::EventObject& aSource )
{
    if ( m_xComponent.is() && m_xComponent == aSource.Source )
    {
        m_xComponent = nullptr;
        if ( m_bWaitForClose )
        {
            m_bWaitForClose = false;
            FreeOffice();
        }
    }

    if( m_xFrame.is() && m_xFrame == aSource.Source )
    {
        m_xHatchWindow.clear();
        m_xOwnWindow.clear();
        m_xFrame.clear();
    }
}


void SAL_CALL DocumentHolder::queryTermination( const lang::EventObject& )
{
    if ( m_bWaitForClose )
        throw frame::TerminationVetoException();
}


void SAL_CALL DocumentHolder::notifyTermination( const lang::EventObject& aSource )
{
    OSL_ENSURE( !m_xComponent.is(), "Just a disaster..." );

    uno::Reference< frame::XDesktop > xDesktop( aSource.Source, uno::UNO_QUERY );
    m_bDesktopTerminated = true;
    if ( xDesktop.is() )
        xDesktop->removeTerminateListener( static_cast<frame::XTerminateListener*>(this) );
}


void SAL_CALL DocumentHolder::modified( const lang::EventObject& aEvent )
{
    // if the component does not support document::XEventBroadcaster
    // the modify notifications are used as workaround, but only for running state
    if( aEvent.Source == m_xComponent && m_pEmbedObj && m_pEmbedObj->getCurrentState() == embed::EmbedStates::RUNNING )
        m_pEmbedObj->PostEvent_Impl( u"OnVisAreaChanged"_ustr );
}


void SAL_CALL DocumentHolder::notifyEvent( const document::EventObject& Event )
{
    if( m_pEmbedObj && Event.Source == m_xComponent )
    {
        // for now the ignored events are not forwarded, but sent by the object itself
        if ( !Event.EventName.startsWith( "OnSave" )
          && !Event.EventName.startsWith( "OnSaveDone" )
          && !Event.EventName.startsWith( "OnSaveAs" )
          && !Event.EventName.startsWith( "OnSaveAsDone" )
          && !( Event.EventName.startsWith( "OnVisAreaChanged" ) && m_nNoResizeReact ) )
            m_pEmbedObj->PostEvent_Impl( Event.EventName );
    }
}


void SAL_CALL DocumentHolder::borderWidthsChanged( const uno::Reference< uno::XInterface >& aObject,
                                                    const frame::BorderWidths& aNewSize )
{
    // TODO: may require mutex introduction ???
    if ( m_pEmbedObj && m_xFrame.is() && aObject == m_xFrame->getController() )
    {
        if ( m_aBorderWidths.Left != aNewSize.Left
          || m_aBorderWidths.Right != aNewSize.Right
          || m_aBorderWidths.Top != aNewSize.Top
          || m_aBorderWidths.Bottom != aNewSize.Bottom )
        {
            m_aBorderWidths = aNewSize;
            if ( !m_nNoBorderResizeReact )
                PlaceFrame( m_aObjRect );
        }
    }
}


void SAL_CALL DocumentHolder::requestPositioning( const awt::Rectangle& aRect )
{
    // TODO: may require mutex introduction ???
    if ( m_pEmbedObj )
    {
        // borders should not be counted
        awt::Rectangle aObjRect = CalculateBorderedArea( aRect );
        IntCounterGuard aGuard( m_nNoResizeReact );
        m_pEmbedObj->requestPositioning( aObjRect );
    }
}


awt::Rectangle SAL_CALL DocumentHolder::calcAdjustedRectangle( const awt::Rectangle&&nbsp;aRect )
{
    // Solar mutex should be locked already since this is a call from HatchWindow with focus
    awt::Rectangle aResult( aRect );

    if ( m_xFrame.is() )
    {
        // borders should not be counted
        uno::Reference< frame::XControllerBorder > xControllerBorder( m_xFrame->getController(), uno::UNO_QUERY );
        if ( xControllerBorder.is() )
        {
            awt::Rectangle aObjRect = CalculateBorderedArea( aRect );
            aObjRect = xControllerBorder->queryBorderedArea( aObjRect );
            aResult = AddBorderToArea( aObjRect );
        }
    }

    awt::Rectangle aMinRectangle = AddBorderToArea( awt::Rectangle() );
    if ( aResult.Width < aMinRectangle.Width + 2 )
        aResult.Width = aMinRectangle.Width + 2;
    if ( aResult.Height < aMinRectangle.Height + 2 )
        aResult.Height = aMinRectangle.Height + 2;

    return aResult;
}

void SAL_CALL DocumentHolder::activated(  )
{
    if ( !(m_pEmbedObj->getStatus(embed::Aspects::MSOLE_CONTENT)&embed::EmbedMisc::MS_EMBED_ACTIVATEWHENVISIBLE) )
        return;

    if ( m_pEmbedObj->getCurrentState() != embed::EmbedStates::UI_ACTIVE &&
    !(m_pEmbedObj->getStatus(embed::Aspects::MSOLE_CONTENT)&embed::EmbedMisc::MS_EMBED_NOUIACTIVATE) )
    {
        try
        {
            m_pEmbedObj->changeState( embed::EmbedStates::UI_ACTIVE );
        }
        catch ( const css::embed::StateChangeInProgressException& )
        {
            // must catch this exception because focus is grabbed while UI activation in doVerb()
        }
        catch ( const css::uno::Exception& )
        {
            // no outgoing exceptions specified here
        }
    }
    else
    {
        uno::Reference< frame::XFramesSupplier > xSupp = m_xFrame->getCreator();
        if ( xSupp.is() )
            xSupp->setActiveFrame( m_xFrame );
    }
}

void DocumentHolder::ResizeHatchWindow()
{
    awt::Rectangle aHatchRect = AddBorderToArea( m_aObjRect );
    ResizeWindows_Impl( aHatchRect );
    uno::Reference< embed::XHatchWindow > xHatchWindow( m_xHatchWindow, uno::UNO_QUERY );
    xHatchWindow->setHatchBorderSize( awt::Size( HATCH_BORDER_WIDTH, HATCH_BORDER_WIDTH ) );
}

void SAL_CALL DocumentHolder::deactivated(  )
{
    // deactivation is too unspecific to be useful; usually we only trigger code from activation
    // so UIDeactivation is actively triggered by the container
}

// namespace embeddedobj

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

Messung V0.5
C=93 H=96 G=94

¤ Dauer der Verarbeitung: 0.14 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.