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

Quelle  sfxbasemodel.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 <sal/config.h>

#include <algorithm>
#include <chrono>
#include <memory>
#include <optional>
#include <config_features.h>

#include <sfx2/sfxbasemodel.hxx>

#include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
#include <com/sun/star/task/XInteractionHandler.hpp>
#include <com/sun/star/task/ErrorCodeIOException.hpp>
#include <com/sun/star/task/ErrorCodeRequest2.hpp>
#include <com/sun/star/view/XSelectionSupplier.hpp>
#include <com/sun/star/view/XPrintJobListener.hpp>
#include <com/sun/star/lang/DisposedException.hpp>
#include <com/sun/star/lang/IllegalArgumentException.hpp>
#include <com/sun/star/lang/NoSupportException.hpp>
#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
#include <com/sun/star/lang/NotInitializedException.hpp>
#include <com/sun/star/frame/Desktop.hpp>
#include <com/sun/star/frame/IllegalArgumentIOException.hpp>
#include <com/sun/star/frame/XUntitledNumbers.hpp>
#include <com/sun/star/frame/DoubleInitializationException.hpp>
#include <com/sun/star/embed/XStorage.hpp>
#include <com/sun/star/document/XStorageChangeListener.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/XPropertySetInfo.hpp>
#include <com/sun/star/container/XIndexContainer.hpp>
#include <com/sun/star/script/provider/theMasterScriptProviderFactory.hpp>
#include <com/sun/star/script/provider/XScriptProvider.hpp>
#include <com/sun/star/ui/UIConfigurationManager.hpp>
#include <com/sun/star/embed/ElementModes.hpp>
#include <com/sun/star/embed/Aspects.hpp>
#include <com/sun/star/document/DocumentProperties.hpp>
#include <com/sun/star/frame/XTransientDocumentsDocumentContentFactory.hpp>
#include <com/sun/star/ucb/XCommandEnvironment.hpp>
#include <com/sun/star/ucb/ContentCreationException.hpp>
#include <com/sun/star/ucb/CommandAbortedException.hpp>
#include <com/sun/star/util/XCloneable.hpp>
#include <com/sun/star/util/InvalidStateException.hpp>
#include <com/sun/star/util/CloseVetoException.hpp>
#include <comphelper/enumhelper.hxx>
#include <comphelper/indexedpropertyvalues.hxx>
#include <comphelper/interfacecontainer3.hxx>
#include <comphelper/string.hxx>

#include <cppuhelper/implbase.hxx>
#include <comphelper/lok.hxx>
#include <comphelper/multicontainer2.hxx>
#include <cppuhelper/exc_hlp.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/propertyvalue.hxx>
#include <comphelper/sequenceashashmap.hxx>
#include <comphelper/namedvaluecollection.hxx>
#include <o3tl/safeint.hxx>
#include <o3tl/string_view.hxx>
#include <svl/itemset.hxx>
#include <svl/stritem.hxx>
#include <svl/eitem.hxx>
#include <svl/grabbagitem.hxx>
#include <tools/urlobj.hxx>
#include <tools/debug.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <tools/svborder.hxx>
#include <unotools/tempfile.hxx>
#include <osl/mutex.hxx>
#include <comphelper/errcode.hxx>
#include <vcl/filter/SvmWriter.hxx>
#include <vcl/salctype.hxx>
#include <vcl/gdimtf.hxx>
#include <comphelper/fileformat.h>
#include <comphelper/servicehelper.hxx>
#include <comphelper/storagehelper.hxx>
#include <toolkit/helper/vclunohelper.hxx>
#include <vcl/transfer.hxx>
#include <svtools/ehdl.hxx>
#include <svtools/sfxecode.hxx>
#include <sal/log.hxx>
#include <framework/configimporter.hxx>
#include <framework/titlehelper.hxx>
#include <comphelper/numberedcollection.hxx>
#include <unotools/ucbhelper.hxx>
#include <ucbhelper/content.hxx>

#include <sfx2/sfxbasecontroller.hxx>
#include <sfx2/viewfac.hxx>
#include <workwin.hxx>
#include <sfx2/signaturestate.hxx>
#include <sfx2/sfxuno.hxx>
#include <objshimp.hxx>
#include <sfx2/viewfrm.hxx>
#include <sfx2/viewsh.hxx>
#include <sfx2/docfile.hxx>
#include <sfx2/docfilt.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/module.hxx>
#include <basic/basmgr.hxx>
#include <sfx2/event.hxx>
#include <eventsupplier.hxx>
#include <sfx2/sfxsids.hrc>
#include <sfx2/strings.hrc>
#include <sfx2/app.hxx>
#include <sfx2/docfac.hxx>
#include <sfx2/fcontnr.hxx>
#include <sfx2/docstoragemodifylistener.hxx>
#include <sfx2/brokenpackageint.hxx>
#include "graphhelp.hxx"
#include <docundomanager.hxx>
#include <openurlhint.hxx>
#include <sfx2/msgpool.hxx>
#include <sfx2/DocumentMetadataAccess.hxx>
#include "printhelper.hxx"
#include <sfx2/sfxresid.hxx>
#include <sfx2/filedlghelper.hxx>
#include <comphelper/profilezone.hxx>
#include <vcl/threadex.hxx>
#include <unotools/mediadescriptor.hxx>

#include <LibreOfficeKit/LibreOfficeKitEnums.h>

//  namespaces


using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using ::com::sun::star::beans::PropertyValue;
using ::com::sun::star::document::CmisProperty;
using ::com::sun::star::frame::XFrame;
using ::com::sun::star::frame::XController;
using ::com::sun::star::frame::XController2;
using ::com::sun::star::lang::IllegalArgumentException;
using ::com::sun::star::io::IOException;
using ::com::sun::star::uno::Sequence;
using ::com::sun::star::document::XDocumentRecovery;
using ::com::sun::star::document::XUndoManager;
using ::com::sun::star::document::XUndoAction;
using ::com::sun::star::frame::XModel;

namespace {

/** This Listener is used to get notified when the XDocumentProperties of the
    XModel change.
 */

class SfxDocInfoListener_Impl : public ::cppu::WeakImplHelper<
    util::XModifyListener >
{

public:
    SfxObjectShell& m_rShell;

    explicit SfxDocInfoListener_Impl( SfxObjectShell& i_rDoc )
        : m_rShell(i_rDoc)
    { };

    virtual void SAL_CALL disposing( const lang::EventObject& ) override;
    virtual void SAL_CALL modified( const lang::EventObject& ) override;
};

}

void SAL_CALL SfxDocInfoListener_Impl::modified( const lang::EventObject& )
{
    SolarMutexGuard aSolarGuard;

    // notify changes to the SfxObjectShell
    m_rShell.FlushDocInfo();
}

void SAL_CALL SfxDocInfoListener_Impl::disposing( const lang::EventObject& )
{
}


//  impl. declarations


struct IMPL_SfxBaseModel_DataContainer : public ::sfx2::IModifiableDocument
{
    // counter for SfxBaseModel instances created.
    inline static std::atomic<sal_Int64>                       g_nInstanceCounter = 0   ;
    SfxObjectShellRef                                          m_pObjectShell           ;
    OUString                                                   m_sURL                   ;
    OUString                                                   m_sRuntimeUID            ;
    OUString                                                   m_aPreusedFilterName     ;
    comphelper::OInterfaceContainerHelper3<view::XPrintJobListener>  m_aPrintJobListeners;
    comphelper::OInterfaceContainerHelper3<lang::XEventListener>  m_aEventListeners;
    comphelper::OInterfaceContainerHelper3<util::XModifyListener>  m_aModifyListeners;
    comphelper::OInterfaceContainerHelper3<document::XEventListener>  m_aDocumentEventListeners1;
    comphelper::OInterfaceContainerHelper3<document::XDocumentEventListener>  m_aDocumentEventListeners2;
    comphelper::OInterfaceContainerHelper3<document::XStorageChangeListener>  m_aStorageChangeListeners;
    comphelper::OInterfaceContainerHelper3<util::XCloseListener>  m_aCloseListeners;
    std::unordered_map<css::uno::Reference< css::drawing::XShape >,
                       std::vector<css::uno::Reference< css::document::XShapeEventListener >>> maShapeListeners;
    Reference< XInterface >                                    m_xParent                ;
    Reference< frame::XController >                            m_xCurrent               ;
    Reference< document::XDocumentProperties >                 m_xDocumentProperties    ;
    Reference< script::XStarBasicAccess >                      m_xStarBasicAccess       ;
    rtl::Reference< SfxEvents_Impl >                           m_xEvents                ;
    Sequence< beans::PropertyValue>                            m_seqArguments           ;
    std::vector< Reference< frame::XController > >             m_seqControllers         ;
    Reference< container::XIndexAccess >                       m_contViewData           ;
    sal_uInt16                                                 m_nControllerLockCount   ;
    bool                                                       m_bClosed                ;
    bool                                                       m_bClosing               ;
    bool                                                       m_bSaving                ;
    bool                                                       m_bSuicide               ;
    bool                                                       m_bExternalTitle         ;
    bool                                                       m_bDisposing             ;
    rtl::Reference< SfxPrintHelper>                            m_xPrintable             ;
    Reference< ui::XUIConfigurationManager2 >                  m_xUIConfigurationManager;
    ::rtl::Reference< ::sfx2::DocumentStorageModifyListener >  m_pStorageModifyListen   ;
    OUString                                                   m_sModuleIdentifier      ;
    rtl::Reference< ::framework::TitleHelper >                 m_xTitleHelper           ;
    rtl::Reference< ::comphelper::NumberedCollection >         m_xNumberedControllers   ;
    rtl::Reference<::sfx2::DocumentMetadataAccess>             m_xDocumentMetadata      ;
    ::rtl::Reference< ::sfx2::DocumentUndoManager >            m_pDocumentUndoManager   ;
    Sequence< document::CmisProperty>                          m_cmisProperties         ;
    std::shared_ptr<SfxGrabBagItem>                            m_xGrabBagItem           ;
    std::optional<std::chrono::steady_clock::time_point>       m_oDirtyTimestamp        ;

    IMPL_SfxBaseModel_DataContainer( ::osl::Mutex& rMutex, SfxObjectShell* pObjectShell )
            :   m_pObjectShell          ( pObjectShell  )
            ,   m_aPrintJobListeners    ( rMutex    )
            ,   m_aEventListeners       ( rMutex    )
            ,   m_aModifyListeners      ( rMutex    )
            ,   m_aDocumentEventListeners1( rMutex  )
            ,   m_aDocumentEventListeners2( rMutex  )
            ,   m_aStorageChangeListeners ( rMutex  )
            ,   m_aCloseListeners       ( rMutex    )
            ,   m_nControllerLockCount  ( 0         )
            ,   m_bClosed               ( false     )
            ,   m_bClosing              ( false     )
            ,   m_bSaving               ( false     )
            ,   m_bSuicide              ( false     )
            ,   m_bExternalTitle        ( false     )
            ,   m_bDisposing            ( false     )
    {
        // increase global instance counter, and set own Runtime UID
        m_sRuntimeUID = OUString::number(++g_nInstanceCounter);
    }

    virtual ~IMPL_SfxBaseModel_DataContainer()
    {
    }

    // ::sfx2::IModifiableDocument
    virtual void storageIsModified() override
    {
        if ( m_pObjectShell.is() && !m_pObjectShell->IsModified() )
            m_pObjectShell->SetModified();
    }

    void impl_setDocumentProperties(
            const Reference< document::XDocumentProperties >& );

    Reference<rdf::XDocumentMetadataAccess> GetDMA()
    {
        if (!m_xDocumentMetadata.is())
        {
            OSL_ENSURE(m_pObjectShell.is(), "GetDMA: no object shell?");
            if (!m_pObjectShell.is())
            {
                return nullptr;
            }

            const Reference<XComponentContext>& xContext(
                ::comphelper::getProcessComponentContext());
            const Reference<frame::XModel> xModel(
                m_pObjectShell->GetModel());
            const Reference<lang::XMultiComponentFactory> xMsf(
                xContext->getServiceManager());
            const Reference<frame::
                XTransientDocumentsDocumentContentFactory> xTDDCF(
                    xMsf->createInstanceWithContext(
                        u"com.sun.star.frame.TransientDocumentsDocumentContentFactory"_ustr,
                    xContext),
                UNO_QUERY_THROW);
            const Reference<ucb::XContent> xContent(
                xTDDCF->createDocumentContent(xModel) );
            OSL_ENSURE(xContent.is(), "GetDMA: cannot create DocumentContent");
            if (!xContent.is())
            {
                return nullptr;
            }
            OUString uri = xContent->getIdentifier()->getContentIdentifier();
            OSL_ENSURE(!uri.isEmpty(), "GetDMA: empty uri?");
            if (!uri.isEmpty() && !uri.endsWith("/"))
            {
                uri += "/";
            }

            m_xDocumentMetadata = new ::sfx2::DocumentMetadataAccess(
                xContext, *m_pObjectShell, uri);
        }
        return m_xDocumentMetadata;
    }

    rtl::Reference<::sfx2::DocumentMetadataAccess> CreateDMAUninitialized()
    {
        return (m_pObjectShell.is())
            ? new ::sfx2::DocumentMetadataAccess(
                ::comphelper::getProcessComponentContext(), *m_pObjectShell)
            : nullptr;
    }

    void setModifiedForAutoSave(bool val)
    {
        if (val)
        {
            if (!m_oDirtyTimestamp)
                m_oDirtyTimestamp.emplace(std::chrono::steady_clock::now());
        }
        else
        {
            m_oDirtyTimestamp.reset();
        }
    }
};

namespace {

// Listener that forwards notifications from the PrintHelper to the "real" listeners
class SfxPrintHelperListener_Impl : public ::cppu::WeakImplHelper< view::XPrintJobListener >
{
public:
    IMPL_SfxBaseModel_DataContainer* m_pData;
    explicit SfxPrintHelperListener_Impl( IMPL_SfxBaseModel_DataContainer* pData )
        : m_pData( pData )
    {}

    virtual void SAL_CALL disposing( const lang::EventObject& aEvent ) override ;
    virtual void SAL_CALL printJobEvent( const view::PrintJobEvent& rEvent ) override;
};

}

void SAL_CALL SfxPrintHelperListener_Impl::disposing( const lang::EventObject& )
{
    m_pData->m_xPrintable = nullptr;
}

void SAL_CALL SfxPrintHelperListener_Impl::printJobEvent( const view::PrintJobEvent&&nbsp;rEvent )
{
    if ( m_pData->m_aPrintJobListeners.getLength() )
    {
        m_pData->m_aPrintJobListeners.notifyEach(&view::XPrintJobListener::printJobEvent, rEvent);
    }
}

namespace {

// SfxOwnFramesLocker ====================================================================================
// allows to lock all the frames related to the provided SfxObjectShell
class SfxOwnFramesLocker
{
    Sequence< Reference< frame::XFrame > > m_aLockedFrames;

    static vcl::Window* GetVCLWindow( const Reference< frame::XFrame >& xFrame );
public:
    explicit SfxOwnFramesLocker( SfxObjectShell const * ObjechShell );
    ~SfxOwnFramesLocker();
};

}

SfxOwnFramesLocker::SfxOwnFramesLocker( SfxObjectShell const * pObjectShell )
{
    if ( !pObjectShell )
        return;

    if ( comphelper::LibreOfficeKit::isForkedChild() )
        return// no need to tweak UI when in the background

    for (   SfxViewFrame *pFrame = SfxViewFrame::GetFirst( pObjectShell );
            pFrame;
            pFrame = SfxViewFrame::GetNext( *pFrame, pObjectShell )
        )
    {
        SfxFrame& rSfxFrame = pFrame->GetFrame();
        try
        {
            // get vcl window related to the frame and lock it if it is still not locked
            const Reference< frame::XFrame >& xFrame = rSfxFrame.GetFrameInterface();
            vcl::Window* pWindow = GetVCLWindow( xFrame );
            if ( !pWindow )
                throw RuntimeException();

            if ( pWindow->IsEnabled() )
            {
                pWindow->Disable();

                try
                {
                    sal_Int32 nLen = m_aLockedFrames.getLength();
                    m_aLockedFrames.realloc( nLen + 1 );
                    m_aLockedFrames.getArray()[nLen] = xFrame;
                }
                catch( Exception& )
                {
                    pWindow->Enable();
                    throw;
                }
            }
        }
        catch( Exception& )
        {
            OSL_FAIL( "Not possible to lock the frame window!" );
        }
    }
}

SfxOwnFramesLocker::~SfxOwnFramesLocker()
{
    for ( auto& rFrame : asNonConstRange(m_aLockedFrames) )
    {
        try
        {
            if ( rFrame.is() )
            {
                // get vcl window related to the frame and unlock it
                vcl::Window* pWindow = GetVCLWindow( rFrame );
                if ( !pWindow )
                    throw RuntimeException();

                pWindow->Enable();

                rFrame.clear();
            }
        }
        catch( Exception& )
        {
            OSL_FAIL( "Can't unlock the frame window!" );
        }
    }
}

vcl::Window* SfxOwnFramesLocker::GetVCLWindow( const Reference< frame::XFrame >& xFrame )
{
    VclPtr<vcl::Window> pWindow;

    if ( xFrame.is() )
    {
        Reference< awt::XWindow > xWindow = xFrame->getContainerWindow();
        if ( xWindow.is() )
               pWindow = VCLUnoHelper::GetWindow( xWindow );
    }

    return pWindow;
}

namespace {

// SfxSaveGuard ====================================================================================
class SfxSaveGuard
{
    private:
        Reference< frame::XModel > m_xModel;
        IMPL_SfxBaseModel_DataContainer* m_pData;
        std::unique_ptr<SfxOwnFramesLocker> m_pFramesLock;

        SfxSaveGuard(SfxSaveGuard const &) = delete;
        void operator =(const SfxSaveGuard&) = delete;

    public:
        SfxSaveGuard(const Reference< frame::XModel >&             xModel                      ,
                           IMPL_SfxBaseModel_DataContainer* pData);
        ~SfxSaveGuard();
};

}

SfxSaveGuard::SfxSaveGuard(const Reference< frame::XModel >&             xModel                      ,
                                 IMPL_SfxBaseModel_DataContainer* pData)
    : m_xModel     ( xModel )
    , m_pData      ( pData )
{
    if ( m_pData->m_bClosed )
        throw lang::DisposedException(u"Object already disposed."_ustr);

    m_pData->m_bSaving = true;
    m_pFramesLock.reset(new SfxOwnFramesLocker( m_pData->m_pObjectShell.get() ));
}

SfxSaveGuard::~SfxSaveGuard()
{
    m_pFramesLock.reset();

    m_pData->m_bSaving = false;

    // m_bSuicide was set e.g. in case someone tried to close a document, while it was used for
    // storing at the same time. Further m_bSuicide was set to sal_True only if close(sal_True) was called.
    // So the ownership was delegated to the place where a veto exception was thrown.
    // Now we have to call close() again and delegate the ownership to the next one, which
    // can't accept that. Close(sal_False) can't work in this case. Because then the document will may be never closed...

    if ( !m_pData->m_bSuicide )
        return;

    // Reset this state. In case the new close() request is not accepted by someone else...
    // it's not a good idea to have two "owners" for close.-)
    m_pData->m_bSuicide = false;
    try
    {
        Reference< util::XCloseable > xClose(m_xModel, UNO_QUERY);
        if (xClose.is())
            xClose->close(true);
    }
    catch(const util::CloseVetoException&)
    {}
}

SfxBaseModel::SfxBaseModel( SfxObjectShell *pObjectShell )
: BaseMutex()
, m_pData( std::make_shared<IMPL_SfxBaseModel_DataContainer>( m_aMutex, pObjectShell ) )
, m_bSupportEmbeddedScripts( pObjectShell && pObjectShell->Get_Impl() && !pObjectShell->Get_Impl()->m_bNoBasicCapabilities )
, m_bSupportDocRecovery( pObjectShell && pObjectShell->Get_Impl() && pObjectShell->Get_Impl()->m_bDocRecoverySupport )
{
    if ( pObjectShell != nullptr )
    {
        StartListening( *pObjectShell ) ;
    }
}

//  destructor
SfxBaseModel::~SfxBaseModel()
{
}

//  XInterface
Any SAL_CALL SfxBaseModel::queryInterface( const uno::Type& rType )
{
    if  (   ( !m_bSupportEmbeddedScripts && rType.equals( cppu::UnoType<document::XEmbeddedScripts>::get() ) )
        ||  ( !m_bSupportDocRecovery && (rType.equals( cppu::UnoType<XDocumentRecovery>::get() ) || rType.equals( cppu::UnoType<XDocumentRecovery2>::get() )) )
        )
        return Any();

    return SfxBaseModel_Base::queryInterface( rType );
}


//  XTypeProvider


namespace
{
    void lcl_stripType( Sequence< uno::Type >& io_rTypes, const uno::Type& i_rTypeToStrip )
    {
        Sequence< uno::Type > aStrippedTypes( io_rTypes.getLength() - 1 );
        ::std::remove_copy_if(
            std::cbegin(io_rTypes),
            std::cend(io_rTypes),
            aStrippedTypes.getArray(),
            [&i_rTypeToStrip](const uno::Type& aType) { return aType == i_rTypeToStrip; }
        );
        io_rTypes = std::move(aStrippedTypes);
    }
}

Sequence< uno::Type > SAL_CALL SfxBaseModel::getTypes()
{
    Sequence< uno::Type > aTypes( SfxBaseModel_Base::getTypes() );

    if ( !m_bSupportEmbeddedScripts )
        lcl_stripType( aTypes, cppu::UnoType<document::XEmbeddedScripts>::get() );

    if ( !m_bSupportDocRecovery )
        lcl_stripType( aTypes, cppu::UnoType<XDocumentRecovery2>::get() );

    return aTypes;
}


//  XTypeProvider


Sequence< sal_Int8 > SAL_CALL SfxBaseModel::getImplementationId()
{
    return css::uno::Sequence<sal_Int8>();
}


//  XStarBasicAccess

#if HAVE_FEATURE_SCRIPTING

static Reference< script::XStarBasicAccess > implGetStarBasicAccess( SfxObjectShell const * pObjectShell )
{
    Reference< script::XStarBasicAccess > xRet;

#if !HAVE_FEATURE_SCRIPTING
    (void) pObjectShell;
#else
    if( pObjectShell )
    {
        BasicManager* pMgr = pObjectShell->GetBasicManager();
        xRet = getStarBasicAccess( pMgr );
    }
#endif
    return xRet;
}

#endif

Reference< container::XNameContainer > SAL_CALL SfxBaseModel::getLibraryContainer()
{
#if !HAVE_FEATURE_SCRIPTING
    Reference< container::XNameContainer > dummy;

    return dummy;
#else
    SfxModelGuard aGuard( *this );

    Reference< script::XStarBasicAccess >& rxAccess = m_pData->m_xStarBasicAccess;
    if( !rxAccess.is() && m_pData->m_pObjectShell.is() )
        rxAccess = implGetStarBasicAccess( m_pData->m_pObjectShell.get() );

    Reference< container::XNameContainer > xRet;
    if( rxAccess.is() )
        xRet = rxAccess->getLibraryContainer();
    return xRet;
#endif
}

/**___________________________________________________________________________________________________
    @seealso    XStarBasicAccess
*/

void SAL_CALL SfxBaseModel::createLibrary( const OUString& LibName, const OUString&&nbsp;Password,
    const OUString& ExternalSourceURL, const OUString& LinkTargetURL )
{
#if !HAVE_FEATURE_SCRIPTING
    (void) LibName;
    (void) Password;
    (void) ExternalSourceURL;
    (void) LinkTargetURL;
#else
    SfxModelGuard aGuard( *this );

    Reference< script::XStarBasicAccess >& rxAccess = m_pData->m_xStarBasicAccess;
    if( !rxAccess.is() && m_pData->m_pObjectShell.is() )
        rxAccess = implGetStarBasicAccess( m_pData->m_pObjectShell.get() );

    if( rxAccess.is() )
        rxAccess->createLibrary( LibName, Password, ExternalSourceURL, LinkTargetURL );
#endif
}

/**___________________________________________________________________________________________________
    @seealso    XStarBasicAccess
*/

void SAL_CALL SfxBaseModel::addModule( const OUString& LibraryName, const OUString&&nbsp;ModuleName,
    const OUString& Language, const OUString& Source )
{
#if !HAVE_FEATURE_SCRIPTING
    (void) LibraryName;
    (void) ModuleName;
    (void) Language;
    (void) Source;
#else
    SfxModelGuard aGuard( *this );

    Reference< script::XStarBasicAccess >& rxAccess = m_pData->m_xStarBasicAccess;
    if( !rxAccess.is() && m_pData->m_pObjectShell.is() )
        rxAccess = implGetStarBasicAccess( m_pData->m_pObjectShell.get() );

    if( rxAccess.is() )
        rxAccess->addModule( LibraryName, ModuleName, Language, Source );
#endif
}

/**___________________________________________________________________________________________________
    @seealso    XStarBasicAccess
*/

void SAL_CALL SfxBaseModel::addDialog( const OUString& LibraryName, const OUString&&nbsp;DialogName,
    const Sequence< sal_Int8 >& Data )
{
#if !HAVE_FEATURE_SCRIPTING
    (void) LibraryName;
    (void) DialogName;
    (void) Data;
#else
    SfxModelGuard aGuard( *this );

    Reference< script::XStarBasicAccess >& rxAccess = m_pData->m_xStarBasicAccess;
    if( !rxAccess.is() && m_pData->m_pObjectShell.is() )
        rxAccess = implGetStarBasicAccess( m_pData->m_pObjectShell.get() );

    if( rxAccess.is() )
        rxAccess->addDialog( LibraryName, DialogName, Data );
#endif
}


//  XChild


Reference< XInterface > SAL_CALL SfxBaseModel::getParent()
{
    SfxModelGuard aGuard( *this );

    return m_pData->m_xParent;
}


//  XChild


void SAL_CALL SfxBaseModel::setParent(const Reference< XInterface >& Parent)
{
    SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
    m_pData->m_xParent = Parent;
}


//  XChild


void SAL_CALL SfxBaseModel::dispose()
{
    SolarMutexGuard aGuard;
    if (impl_isDisposed())
        return;

    if  ( !m_pData->m_bClosed )
    {
        // gracefully accept wrong dispose calls instead of close call
        // and try to make it work (may be really disposed later!)
        try
        {
            close( true );
        }
        catch ( util::CloseVetoException& )
        {
        }

        return;
    }

    if  ( m_pData->m_bDisposing )
        return;
    m_pData->m_bDisposing = true;

    if ( m_pData->m_pStorageModifyListen.is() )
    {
        m_pData->m_pStorageModifyListen->dispose();
        m_pData->m_pStorageModifyListen = nullptr;
    }

    if ( m_pData->m_pDocumentUndoManager.is() )
    {
        m_pData->m_pDocumentUndoManager->disposing();
        m_pData->m_pDocumentUndoManager = nullptr;
    }

    lang::EventObject aEvent( static_cast<frame::XModel *>(this) );
    m_pData->m_aPrintJobListeners.disposeAndClear( aEvent );
    m_pData->m_aEventListeners.disposeAndClear( aEvent );
    m_pData->m_aModifyListeners.disposeAndClear( aEvent );
    m_pData->m_aDocumentEventListeners1.disposeAndClear( aEvent );
    m_pData->m_aDocumentEventListeners2.disposeAndClear( aEvent );
    m_pData->m_aStorageChangeListeners.disposeAndClear( aEvent );
    m_pData->m_aCloseListeners.disposeAndClear( aEvent );

    m_pData->m_xDocumentProperties.clear();

    m_pData->m_xDocumentMetadata.clear();

    if ( m_pData->m_pObjectShell.is() )
    {
        EndListening( *m_pData->m_pObjectShell );
    }

    m_pData->m_xCurrent.clear();
    m_pData->m_seqControllers.clear();

    // m_pData member must be set to zero before delete is called to
    // force disposed exception whenever someone tries to access our
    // instance while in the dtor.
    m_pData.reset();
}


//  XChild


void SAL_CALL SfxBaseModel::addEventListener( const Reference< lang::XEventListener >&&nbsp;aListener )
{
    SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
    m_pData->m_aEventListeners.addInterface( aListener );
}


//  XChild


void SAL_CALL SfxBaseModel::removeEventListener( const Reference< lang::XEventListener >&&nbsp;aListener )
{
    SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
    m_pData->m_aEventListeners.removeInterface( aListener );
}

void
IMPL_SfxBaseModel_DataContainer::impl_setDocumentProperties(
        const Reference< document::XDocumentProperties >& rxNewDocProps)
{
    m_xDocumentProperties.set(rxNewDocProps, UNO_SET_THROW);
    if (m_pObjectShell.is())
    {
        Reference<util::XModifyBroadcaster> const xMB(
            m_xDocumentProperties, UNO_QUERY_THROW);
        xMB->addModifyListener(new SfxDocInfoListener_Impl(*m_pObjectShell));
    }
}

// document::XDocumentPropertiesSupplier:
Reference< document::XDocumentProperties > SAL_CALL
SfxBaseModel::getDocumentProperties()
{
    SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
    if ( !m_pData->m_xDocumentProperties.is() )
    {
        Reference< document::XDocumentProperties > xDocProps(
            document::DocumentProperties::create( ::comphelper::getProcessComponentContext() ) );
        m_pData->impl_setDocumentProperties(xDocProps);
    }

    return m_pData->m_xDocumentProperties;
}


//  lang::XEventListener


void SAL_CALL SfxBaseModel::disposing( const lang::EventObject& aObject )
{
    SolarMutexGuard aGuard;
    if ( impl_isDisposed() )
        return;

    Reference< util::XModifyListener >  xMod( aObject.Source, UNO_QUERY );
    Reference< lang::XEventListener >  xListener( aObject.Source, UNO_QUERY );
    Reference< document::XEventListener >  xDocListener( aObject.Source, UNO_QUERY );

    if ( xMod.is() )
        m_pData->m_aModifyListeners.removeInterface( xMod );
    else if ( xListener.is() )
        m_pData->m_aEventListeners.removeInterface( xListener );
    else if ( xDocListener.is() )
        m_pData->m_aDocumentEventListeners1.removeInterface( xDocListener );
}


//  frame::XModel


sal_Bool SAL_CALL SfxBaseModel::attachResource( const   OUString&                   rURL    ,
                                                const   Sequence< beans::PropertyValue >&  rArgs   )
{
    SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
    if ( rURL.isEmpty() && rArgs.getLength() == 1 && rArgs[0].Name == "SetEmbedded" )
    {
        // allows to set a windowless document to EMBEDDED state
        // but _only_ before load() or initNew() methods
        if ( m_pData->m_pObjectShell.is() && !m_pData->m_pObjectShell->GetMedium() )
        {
            bool bEmb(false);
            if ( ( rArgs[0].Value >>= bEmb ) && bEmb )
                m_pData->m_pObjectShell->SetCreateMode_Impl( SfxObjectCreateMode::EMBEDDED );
        }

        return true;
    }

    if ( m_pData->m_pObjectShell.is() )
    {
        m_pData->m_sURL = rURL;

        SfxObjectShell* pObjectShell = m_pData->m_pObjectShell.get();

        Sequence< sal_Int32 > aWinExtent;
        for (const beans::PropertyValue & rProp : rArgs)
        {
            if (rProp.Name == "WinExtent" && (rProp.Value >>= aWinExtent) && ( aWinExtent.getLength() == 4 ) )
            {
                tools::Rectangle aVisArea( aWinExtent[0], aWinExtent[1], aWinExtent[2], aWinExtent[3] );
                aVisArea = OutputDevice::LogicToLogic(aVisArea, MapMode(MapUnit::Map100thMM), MapMode(pObjectShell->GetMapUnit()));
                pObjectShell->SetVisArea( aVisArea );
            }
            bool bBreakMacroSign = false;
            if ( rProp.Name == "BreakMacroSignature" && (rProp.Value >>= bBreakMacroSign) )
            {
                pObjectShell->BreakMacroSign_Impl( bBreakMacroSign );
            }
            bool bMacroEventRead = false;
            if ( rProp.Name == "MacroEventRead" && (rProp.Value >>= bMacroEventRead) && bMacroEventRead)
            {
                pObjectShell->SetMacroCallsSeenWhileLoading();
            }
        }
        Sequence<beans::PropertyValue> aStrippedArgs(rArgs.getLength());
        beans::PropertyValue* pStripped = aStrippedArgs.getArray();
        for (const beans::PropertyValue & rProp : rArgs)
        {
            if (rProp.Name == "WinExtent"
                || rProp.Name == "BreakMacroSignature"
                || rProp.Name == "MacroEventRead"
                || rProp.Name == "Stream"
                || rProp.Name == "InputStream"
                || rProp.Name == "URL"
                || rProp.Name == "Frame"
                || rProp.Name == "Password"
                || rProp.Name == "EncryptionData")
                continue;
            *pStripped++ = rProp;
        }
        aStrippedArgs.realloc(pStripped - aStrippedArgs.getArray());

        // TODO/LATER: all the parameters that are accepted by ItemSet of the DocShell must be removed here

        m_pData->m_seqArguments = std::move(aStrippedArgs);

        SfxMedium* pMedium = pObjectShell->GetMedium();
        if ( pMedium )
        {
            SfxAllItemSet aSet( pObjectShell->GetPool() );
            TransformParameters( SID_OPENDOC, rArgs, aSet );

            // the arguments are not allowed to reach the medium
            aSet.ClearItem( SID_FILE_NAME );
            aSet.ClearItem( SID_FILLFRAME );

            pMedium->GetItemSet().Put( aSet );
            const SfxStringItem* pItem = aSet.GetItem<SfxStringItem>(SID_FILTER_NAME, false);
            if ( pItem )
                pMedium->SetFilter(
                    pObjectShell->GetFactory().GetFilterContainer()->GetFilter4FilterName( pItem->GetValue() ) );

            const SfxStringItem* pTitleItem = aSet.GetItem<SfxStringItem>(SID_DOCINFO_TITLE, false);
            if ( pTitleItem )
            {
                SfxViewFrame* pFrame = SfxViewFrame::GetFirst( pObjectShell );
                if ( pFrame )
                    pFrame->UpdateTitle();
            }
        }
    }

    return true ;
}


//  frame::XModel


OUString SAL_CALL SfxBaseModel::getURL()
{
    SfxModelGuard aGuard( *this );
    return m_pData->m_sURL ;
}


//  frame::XModel

Sequence< beans::PropertyValue > SAL_CALL SfxBaseModel::getArgs()
{
    return getArgs2({});
}

//  frame::XModel3

Sequence< beans::PropertyValue > SAL_CALL SfxBaseModel::getArgs2(const Sequence<OUString> &&nbsp;requestedArgsSeq )
{
    SfxModelGuard aGuard( *this );

    if (!SfxApplication::Get()) // tdf#113755
    {
        SAL_WARN("sfx.appl""Unexpected operations on model");
        return m_pData->m_seqArguments;
    }

    std::set<std::u16string_view> requestedArgs;
    for (OUString const & s : requestedArgsSeq)
        requestedArgs.insert(s);

    if ( m_pData->m_pObjectShell.is() )
    {
        Sequence< beans::PropertyValue > seqArgsNew;
        Sequence< beans::PropertyValue > seqArgsOld;
        SfxAllItemSet aSet( m_pData->m_pObjectShell->GetPool() );

        // we need to know which properties are supported by the transformer
        // hopefully it is a temporary solution, I guess nonconvertable properties
        // should not be supported so then there will be only ItemSet from medium

        TransformItems( SID_OPENDOC, m_pData->m_pObjectShell->GetMedium()->GetItemSet(), seqArgsNew );
        TransformParameters( SID_OPENDOC, m_pData->m_seqArguments, aSet );
        TransformItems( SID_OPENDOC, aSet, seqArgsOld );

        sal_Int32 nNewLength = seqArgsNew.getLength();

        if (requestedArgs.empty() || requestedArgs.count(u"WinExtent"))
        {
            // "WinExtent" property should be updated always.
            // We can store it now to overwrite an old value
            // since it is not from ItemSet
            tools::Rectangle aTmpRect = m_pData->m_pObjectShell->GetVisArea( ASPECT_CONTENT );
            aTmpRect = OutputDevice::LogicToLogic(aTmpRect, MapMode(m_pData->m_pObjectShell->GetMapUnit()), MapMode(MapUnit::Map100thMM));

            Sequence< sal_Int32 > aRectSeq
            {
                o3tl::narrowing<int>(aTmpRect.Left()),
                o3tl::narrowing<int>(aTmpRect.Top()),
                o3tl::narrowing<int>(aTmpRect.IsWidthEmpty() ? aTmpRect.Left() : aTmpRect.Right()),
                o3tl::narrowing<int>(aTmpRect.IsHeightEmpty() ? aTmpRect.Top() : aTmpRect.Bottom())
            };

            seqArgsNew.realloc( ++nNewLength );
            auto pseqArgsNew = seqArgsNew.getArray();
            pseqArgsNew[ nNewLength - 1 ].Name = "WinExtent";
            pseqArgsNew[ nNewLength - 1 ].Value <<= aRectSeq;
        }

        if (requestedArgs.empty() || requestedArgs.count(u"PreusedFilterName"))
        {
            if ( !m_pData->m_aPreusedFilterName.isEmpty() )
            {
                seqArgsNew.realloc( ++nNewLength );
                auto pseqArgsNew = seqArgsNew.getArray();
                pseqArgsNew[ nNewLength - 1 ].Name = "PreusedFilterName";
                pseqArgsNew[ nNewLength - 1 ].Value <<= m_pData->m_aPreusedFilterName;
            }
        }

        if (requestedArgs.empty() || requestedArgs.count(u"DocumentBorder"))
        {
            SfxViewFrame* pFrame = SfxViewFrame::GetFirst( m_pData->m_pObjectShell.get() );
            if ( pFrame )
            {
                SvBorder aBorder = pFrame->GetBorderPixelImpl();

                Sequence< sal_Int32 > aBorderSeq
                {
                    o3tl::narrowing<int>(aBorder.Left()),
                    o3tl::narrowing<int>(aBorder.Top()),
                    o3tl::narrowing<int>(aBorder.Right()),
                    o3tl::narrowing<int>(aBorder.Bottom())
                };

                seqArgsNew.realloc( ++nNewLength );
                auto pseqArgsNew = seqArgsNew.getArray();
                pseqArgsNew[ nNewLength - 1 ].Name = "DocumentBorder";
                pseqArgsNew[ nNewLength - 1 ].Value <<= aBorderSeq;
            }
        }

        if (requestedArgs.empty())
        {
            // only the values that are not supported by the ItemSet must be cached here
            Sequence< beans::PropertyValue > aFinalCache;
            sal_Int32 nFinalLength = 0;

            for (const auto& rOrg : m_pData->m_seqArguments)
            {
                auto bNew = std::none_of(std::cbegin(seqArgsOld), std::cend(seqArgsOld),
                    [&rOrg](const beans::PropertyValue& rOld){ return rOld.Name == rOrg.Name; });
                if ( bNew )
                {
                    // the entity with this name should be new for seqArgsNew
                    // since it is not supported by transformer

                    seqArgsNew.realloc( ++nNewLength );
                    seqArgsNew.getArray()[ nNewLength - 1 ] = rOrg;

                    aFinalCache.realloc( ++nFinalLength );
                    aFinalCache.getArray()[ nFinalLength - 1 ] = rOrg;
                }
            }

            m_pData->m_seqArguments = std::move(aFinalCache);
        }

        return seqArgsNew;
    }

    return m_pData->m_seqArguments;
}

void SAL_CALL SfxBaseModel::setArgs(const Sequence<beans::PropertyValue>& aArgs)
{
    SfxModelGuard aGuard( *this );

    SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
    if (!pMedium)
    {
        throw util::InvalidStateException(
            u"Medium could not be retrieved, unable to execute setArgs"_ustr);
    }

    for (const auto& rArg : aArgs)
    {
        OUString sValue;
        bool bValue;
        bool ok = false;
        if (rArg.Name == "SuggestedSaveAsName")
        {
            if (rArg.Value >>= sValue)
            {
                pMedium->GetItemSet().Put(SfxStringItem(SID_SUGGESTEDSAVEASNAME, sValue));
                ok = true;
            }
        }
        else if (rArg.Name == "SuggestedSaveAsDir")
        {
            if (rArg.Value >>= sValue)
            {
                pMedium->GetItemSet().Put(SfxStringItem(SID_SUGGESTEDSAVEASDIR, sValue));
                ok = true;
            }
        }
        else if (rArg.Name == "ExportDirectory")
        {
            if (rArg.Value >>= sValue)
            {
                pMedium->GetItemSet().Put(SfxStringItem(SID_EXPORTDIRECTORY, sValue));
                ok = true;
            }
        }
        else if (rArg.Name == "LockContentExtraction")
        {
            if (rArg.Value >>= bValue)
            {
                pMedium->GetItemSet().Put(SfxBoolItem(SID_LOCK_CONTENT_EXTRACTION, bValue));
                ok = true;
            }
        }
        else if (rArg.Name == "LockExport")
        {
            if (rArg.Value >>= bValue)
            {
                pMedium->GetItemSet().Put(SfxBoolItem(SID_LOCK_EXPORT, bValue));
                ok = true;
            }
        }
        else if (rArg.Name == "LockPrint")
        {
            if (rArg.Value >>= bValue)
            {
                pMedium->GetItemSet().Put(SfxBoolItem(SID_LOCK_PRINT, bValue));
                ok = true;
            }
        }
        else if (rArg.Name == "LockSave")
        {
            if (rArg.Value >>= bValue)
            {
                pMedium->GetItemSet().Put(SfxBoolItem(SID_LOCK_SAVE, bValue));
                ok = true;
            }
        }
        else if (rArg.Name == "LockEditDoc")
        {
            if (rArg.Value >>= bValue)
            {
                pMedium->GetItemSet().Put(SfxBoolItem(SID_LOCK_EDITDOC, bValue));
                ok = true;
            }
        }
        else if (rArg.Name == "Replaceable")
        {
            if (rArg.Value >>= bValue)
            {
                pMedium->GetItemSet().Put(SfxBoolItem(SID_REPLACEABLE, bValue));
                ok = true;
            }
        }
        else if (rArg.Name == "EncryptionData")
        {
            pMedium->GetItemSet().Put(SfxUnoAnyItem(SID_ENCRYPTIONDATA, rArg.Value));
            ok = true;
        }
        if (!ok)
        {
            throw lang::IllegalArgumentException("Setting property not supported: " + rArg.Name,
                                                 comphelper::getProcessComponentContext(), 0);
        }
    }
}

//  frame::XModel


void SAL_CALL SfxBaseModel::connectController( const Reference< frame::XController >& ;xController )
{
    SfxModelGuard aGuard( *this );
    OSL_PRECOND( xController.is(), "SfxBaseModel::connectController: invalid controller!" );
    if ( !xController.is() )
        return;

    m_pData->m_seqControllers.push_back(xController);

    if ( m_pData->m_seqControllers.size() == 1 )
    {
        SfxViewFrame* pViewFrame = SfxViewFrame::Get( xController, GetObjectShell() );
        ENSURE_OR_THROW( pViewFrame, "SFX document without SFX view!?" );
        pViewFrame->UpdateDocument_Impl();
        const OUString sDocumentURL = GetObjectShell()->GetMedium()->GetName();
        if ( !sDocumentURL.isEmpty() )
            SfxGetpApp()->Broadcast( SfxOpenUrlHint( sDocumentURL ) );
    }
}


//  frame::XModel


void SAL_CALL SfxBaseModel::disconnectController( const Reference< frame::XController >&&nbsp;xController )
{
    SfxModelGuard aGuard( *this );

    if ( m_pData->m_seqControllers.empty() )
        return;

    auto& vec = m_pData->m_seqControllers;
    std::erase(vec, xController);

    if ( xController == m_pData->m_xCurrent )
        m_pData->m_xCurrent.clear();
}

namespace
{
    class ControllerLockUndoAction : public ::cppu::WeakImplHelper< XUndoAction >
    {
    public:
        ControllerLockUndoAction( const Reference< XModel >& i_model, const bool i_undoIsUnlock )
            :m_xModel( i_model )
            ,m_bUndoIsUnlock( i_undoIsUnlock )
        {
        }

        // XUndoAction
        virtual OUString SAL_CALL getTitle() override;
        virtual void SAL_CALL undo(  ) override;
        virtual void SAL_CALL redo(  ) override;

    private:
        const Reference< XModel >   m_xModel;
        const bool                  m_bUndoIsUnlock;
    };

    OUString SAL_CALL ControllerLockUndoAction::getTitle()
    {
        // this action is intended to be used within an UndoContext only, so nobody will ever see this title ...
        return OUString();
    }

    void SAL_CALL ControllerLockUndoAction::undo(  )
    {
        if ( m_bUndoIsUnlock )
            m_xModel->unlockControllers();
        else
            m_xModel->lockControllers();
    }

    void SAL_CALL ControllerLockUndoAction::redo(  )
    {
        if ( m_bUndoIsUnlock )
            m_xModel->lockControllers();
        else
            m_xModel->unlockControllers();
    }
}


//  frame::XModel


void SAL_CALL SfxBaseModel::lockControllers()
{
    SfxModelGuard aGuard( *this );

    ++m_pData->m_nControllerLockCount ;

    if  (   m_pData->m_pDocumentUndoManager.is()
        &&  m_pData->m_pDocumentUndoManager->isInContext()
        &&  !m_pData->m_pDocumentUndoManager->isLocked()
        )
    {
        m_pData->m_pDocumentUndoManager->addUndoAction( new ControllerLockUndoAction( thistrue ) );
    }
}


//  frame::XModel


void SAL_CALL SfxBaseModel::unlockControllers()
{
    SfxModelGuard aGuard( *this );

    --m_pData->m_nControllerLockCount ;

    if  (   m_pData->m_pDocumentUndoManager.is()
        &&  m_pData->m_pDocumentUndoManager->isInContext()
        &&  !m_pData->m_pDocumentUndoManager->isLocked()
        )
    {
        m_pData->m_pDocumentUndoManager->addUndoAction( new ControllerLockUndoAction( thisfalse ) );
    }
}


//  frame::XModel


sal_Bool SAL_CALL SfxBaseModel::hasControllersLocked()
{
    SfxModelGuard aGuard( *this );
    return ( m_pData->m_nControllerLockCount != 0 ) ;
}


//  frame::XModel


Reference< frame::XController > SAL_CALL SfxBaseModel::getCurrentController()
{
    SfxModelGuard aGuard( *this );

    // get the last active controller of this model
    if ( m_pData->m_xCurrent.is() )
        return m_pData->m_xCurrent;

    // get the first controller of this model
    return !m_pData->m_seqControllers.empty() ? m_pData->m_seqControllers.front() : m_pData->m_xCurrent;
}


//  frame::XModel


void SAL_CALL SfxBaseModel::setCurrentController( const Reference< frame::XController >&&nbsp;xCurrentController )
{
    SfxModelGuard aGuard( *this );

    m_pData->m_xCurrent = xCurrentController;
}


//  frame::XModel


Reference< XInterface > SAL_CALL SfxBaseModel::getCurrentSelection()
{
    SfxModelGuard aGuard( *this );

    Reference< XInterface >     xReturn;
    Reference< frame::XController >    xController =   getCurrentController()      ;

    if ( xController.is() )
    {
        Reference< view::XSelectionSupplier >  xDocView( xController, UNO_QUERY );
        if ( xDocView.is() )
        {
            Any aSel = xDocView->getSelection();
            aSel >>= xReturn ;
        }
    }

    return xReturn ;
}


//  XModifiable2


sal_Bool SAL_CALL SfxBaseModel::disableSetModified()
{
    SfxModelGuard aGuard( *this );

    if ( !m_pData->m_pObjectShell.is() )
        throw RuntimeException();

    bool bResult = m_pData->m_pObjectShell->IsEnableSetModified();
    m_pData->m_pObjectShell->EnableSetModified( false );

    return bResult;
}

sal_Bool SAL_CALL SfxBaseModel::enableSetModified()
{
    SfxModelGuard aGuard( *this );

    if ( !m_pData->m_pObjectShell.is() )
        throw RuntimeException();

    bool bResult = m_pData->m_pObjectShell->IsEnableSetModified();
    m_pData->m_pObjectShell->EnableSetModified();

    return bResult;
}

sal_Bool SAL_CALL SfxBaseModel::isSetModifiedEnabled()
{
    SfxModelGuard aGuard( *this );

    if ( !m_pData->m_pObjectShell.is() )
        throw RuntimeException();

    return m_pData->m_pObjectShell->IsEnableSetModified();
}


//  XModifiable


sal_Bool SAL_CALL SfxBaseModel::isModified()
{
    SfxModelGuard aGuard( *this );

    return m_pData->m_pObjectShell.is() && m_pData->m_pObjectShell->IsModified();
}


//  XModifiable


void SAL_CALL SfxBaseModel::setModified( sal_Bool bModified )
{
    SfxModelGuard aGuard( *this );

    if ( m_pData->m_pObjectShell.is() )
        m_pData->m_pObjectShell->SetModified(bModified);
}


//  XModifiable


void SAL_CALL SfxBaseModel::addModifyListener(const Reference< util::XModifyListener >&&nbsp;xListener)
{
    SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );

    m_pData->m_aModifyListeners.addInterface( xListener );
}


//  XModifiable


void SAL_CALL SfxBaseModel::removeModifyListener(const Reference< util::XModifyListener >& xListener)
{
    SfxModelGuard aGuard( *this );

    m_pData->m_aModifyListeners.removeInterface( xListener );
}


//  XCloseable


void SAL_CALL SfxBaseModel::close( sal_Bool bDeliverOwnership )
{
    SolarMutexGuard aGuard;
    if ( impl_isDisposed() || m_pData->m_bClosed || m_pData->m_bClosing )
        return;

    Reference< XInterface > xSelfHold( getXWeak() );
    lang::EventObject       aSource  ( getXWeak() );
    if (m_pData->m_aCloseListeners.getLength())
    {
        comphelper::OInterfaceIteratorHelper3 pIterator(m_pData->m_aCloseListeners);
        while (pIterator.hasMoreElements())
        {
            try
            {
                pIterator.next()->queryClosing( aSource, bDeliverOwnership );
            }
            catch( RuntimeException& )
            {
                pIterator.remove();
            }
        }
    }

    if ( m_pData->m_bSaving )
    {
        if (bDeliverOwnership)
            m_pData->m_bSuicide = true;
        throw util::CloseVetoException(
                u"Can not close while saving."_ustr,
                static_cast< util::XCloseable* >(this));
    }

    // no own objections against closing!
    m_pData->m_bClosing = true;
    if (m_pData->m_aCloseListeners.getLength())
    {
        comphelper::OInterfaceIteratorHelper3 pCloseIterator(m_pData->m_aCloseListeners);
        while (pCloseIterator.hasMoreElements())
        {
            try
            {
                pCloseIterator.next()->notifyClosing( aSource );
            }
            catch( RuntimeException& )
            {
                pCloseIterator.remove();
            }
        }
    }

    m_pData->m_bClosed = true;
    m_pData->m_bClosing = false;

    dispose();
}


//  XCloseBroadcaster


void SAL_CALL SfxBaseModel::addCloseListener( const Reference< util::XCloseListener >&&nbsp;xListener )
{
    SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );

    m_pData->m_aCloseListeners.addInterface( xListener );
}


//  XCloseBroadcaster


void SAL_CALL SfxBaseModel::removeCloseListener( const Reference< util::XCloseListener >&&nbsp;xListener )
{
    SfxModelGuard aGuard( *this );

    m_pData->m_aCloseListeners.removeInterface( xListener );
}


//  XPrintable


Sequence< beans::PropertyValue > SAL_CALL SfxBaseModel::getPrinter()
{
    SfxModelGuard aGuard( *this );

    impl_getPrintHelper();
    return m_pData->m_xPrintable->getPrinter();
}

void SAL_CALL SfxBaseModel::setPrinter(const Sequence< beans::PropertyValue >& rPrinter)
{
    SfxModelGuard aGuard( *this );

    impl_getPrintHelper();
    m_pData->m_xPrintable->setPrinter( rPrinter );
}

void SAL_CALL SfxBaseModel::print(const Sequence< beans::PropertyValue >& rOptions)
{
    SfxModelGuard aGuard( *this );

    impl_getPrintHelper();

    // tdf#123728 Always print on main thread to avoid deadlocks
    vcl::solarthread::syncExecute([this, &rOptions]() { m_pData->m_xPrintable->print(rOptions); });
}

//  XStorable


sal_Bool SAL_CALL SfxBaseModel::hasLocation()
{
    SfxModelGuard aGuard( *this );

    return m_pData->m_pObjectShell.is() && m_pData->m_pObjectShell->HasName();
}


//  XStorable


OUString SAL_CALL SfxBaseModel::getLocation()
{
    SfxModelGuard aGuard( *this );

    if ( m_pData->m_pObjectShell.is() )
    {
        // TODO/LATER: is it correct that the shared document returns shared file location?
        if ( m_pData->m_pObjectShell->IsDocShared() )
            return m_pData->m_pObjectShell->GetSharedFileURL();
        else
            return m_pData->m_pObjectShell->GetMedium()->GetName();
    }

    return m_pData->m_sURL;
}


//  XStorable


sal_Bool SAL_CALL SfxBaseModel::isReadonly()
{
    SfxModelGuard aGuard( *this );

    return !m_pData->m_pObjectShell.is() || m_pData->m_pObjectShell->IsReadOnly();
}

//  XStorable2


void SAL_CALL SfxBaseModel::storeSelf( const    Sequence< beans::PropertyValue >&  aSeqArgs )
{
    SfxModelGuard aGuard( *this );

    if ( !m_pData->m_pObjectShell.is() )
        return;

    SfxSaveGuard aSaveGuard(this, m_pData.get());

    bool bCheckIn = false;
    bool bOnMainThread = false;
    for ( const auto& rArg : aSeqArgs )
    {
        // check that only acceptable parameters are provided here
        if ( rArg.Name != "VersionComment" && rArg.Name != "Author"
          && rArg.Name != "DontTerminateEdit"
          && rArg.Name != "InteractionHandler" && rArg.Name != "StatusIndicator"
          && rArg.Name != "VersionMajor"
          && rArg.Name != "FailOnWarning"
          && rArg.Name != "CheckIn"
          && rArg.Name != "NoFileSync"
          && rArg.Name != "OnMainThread" )
        {
            const OUString aMessage( "Unexpected MediaDescriptor parameter: " + rArg.Name );
            throw lang::IllegalArgumentException( aMessage, Reference< XInterface >(), 1 );
        }
        else if ( rArg.Name == "CheckIn" )
        {
            rArg.Value >>= bCheckIn;
        }
        else if (rArg.Name == "OnMainThread")
        {
            rArg.Value >>= bOnMainThread;
        }
    }

    // Remove CheckIn property if needed
    sal_uInt16 nSlotId = SID_SAVEDOC;
    Sequence< beans::PropertyValue >  aArgs = aSeqArgs;
    if ( bCheckIn )
    {
        nSlotId = SID_CHECKIN;
        sal_Int32 nLength = aSeqArgs.getLength( );
        aArgs = Sequence< beans::PropertyValue >( nLength - 1 );
        std::copy_if(aSeqArgs.begin(), aSeqArgs.end(), aArgs.getArray(),
            [](const beans::PropertyValue& rProp) { return rProp.Name != "CheckIn"; });
    }

    std::optional<SfxAllItemSet> pParams(SfxGetpApp()->GetPool() );
    TransformParameters( nSlotId, aArgs, *pParams );

    SfxGetpApp()->NotifyEvent( SfxEventHint( SfxEventHintId::SaveDoc, GlobalEventConfig::GetEventName(GlobalEventId::SAVEDOC), m_pData->m_pObjectShell.get() ) );

    bool bRet = false;

    // TODO/LATER: let the embedded case of saving be handled more careful
    if ( m_pData->m_pObjectShell->GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
    {
        // If this is an embedded object that has no URL based location it should be stored to own storage.
        // An embedded object can have a location based on URL in case it is a link, then it should be
        // stored in normal way.
        if ( !hasLocation() || getLocation().startsWith("private:") )
        {
            // actually in this very rare case only UI parameters have sense
            // TODO/LATER: should be done later, after integration of sb19
            bRet = m_pData->m_pObjectShell->DoSave()
                && m_pData->m_pObjectShell->DoSaveCompleted();
        }
        else
        {
            bRet = m_pData->m_pObjectShell->Save_Impl( &*pParams );
        }
    }
    else
    {
        // Tell the SfxMedium if we are in checkin instead of normal save
        m_pData->m_pObjectShell->GetMedium( )->SetInCheckIn( nSlotId == SID_CHECKIN );
        if (bOnMainThread)
            bRet = vcl::solarthread::syncExecute(
                [this, &pParams] { return m_pData->m_pObjectShell->Save_Impl(&*pParams); });
        else
            bRet = m_pData->m_pObjectShell->Save_Impl(&*pParams);
        m_pData->m_pObjectShell->GetMedium( )->SetInCheckIn( nSlotId != SID_CHECKIN );
    }

    pParams.reset();

    ErrCodeMsg nErrCode = m_pData->m_pObjectShell->GetErrorIgnoreWarning();
    m_pData->m_pObjectShell->ResetError();

    if ( bRet )
    {
        m_pData->m_aPreusedFilterName = GetMediumFilterName_Impl();

        SfxGetpApp()->NotifyEvent( SfxEventHint( SfxEventHintId::SaveDocDone, GlobalEventConfig::GetEventName(GlobalEventId::SAVEDOCDONE), m_pData->m_pObjectShell.get() ) );
    }
    else
    {
        if (!nErrCode)
            nErrCode = ERRCODE_IO_CANTWRITE;
        // write the contents of the logger to the file
        SfxGetpApp()->NotifyEvent( SfxEventHint( SfxEventHintId::SaveDocFailed, GlobalEventConfig::GetEventName(GlobalEventId::SAVEDOCFAILED), m_pData->m_pObjectShell.get() ) );

        throw task::ErrorCodeIOException(
            "SfxBaseModel::storeSelf: " + nErrCode.toString(),
            Reference< XInterface >(), sal_uInt32(nErrCode.GetCode()));
    }
}


//  XStorable


void SAL_CALL SfxBaseModel::store()
{
    comphelper::ProfileZone aZone("store");
    storeSelf( Sequence< beans::PropertyValue >() );
}


//  XStorable


void SAL_CALL SfxBaseModel::storeAsURL( const   OUString&                   rURL    ,
                                        const   Sequence< beans::PropertyValue >&  rArgs   )
{
    SfxModelGuard aGuard( *this );
    comphelper::ProfileZone aZone("storeAs");

    if ( !m_pData->m_pObjectShell.is() )
        return;

    SfxSaveGuard aSaveGuard(this, m_pData.get());

    utl::MediaDescriptor aDescriptor(rArgs);
    bool bOnMainThread = aDescriptor.getUnpackedValueOrDefault(u"OnMainThread"_ustr, false);
    if (bOnMainThread)
    {
        vcl::solarthread::syncExecute([this, rURL, rArgs]() { impl_store(rURL, rArgs, false); });
    }
    else
    {
        impl_store(rURL, rArgs, false);
    }

    Sequence< beans::PropertyValue > aSequence ;
    TransformItems( SID_OPENDOC, m_pData->m_pObjectShell->GetMedium()->GetItemSet(), aSequence );
    attachResource( rURL, aSequence );

    loadCmisProperties( );

#if OSL_DEBUG_LEVEL > 0
    const SfxStringItem* pPasswdItem = m_pData->m_pObjectShell->GetMedium()->GetItemSet().GetItem(SID_PASSWORD, false);
    OSL_ENSURE( !pPasswdItem, "There should be no Password property in the document MediaDescriptor!" );
#endif
}


//  XUndoManagerSupplier

Reference< XUndoManager > SAL_CALL SfxBaseModel::getUndoManager(  )
{
    SfxModelGuard aGuard( *this );
    if ( !m_pData->m_pDocumentUndoManager.is() )
        m_pData->m_pDocumentUndoManager.set( new ::sfx2::DocumentUndoManager( *this ) );
    return m_pData->m_pDocumentUndoManager;
}


//  XStorable


void SAL_CALL SfxBaseModel::storeToURL( const   OUString&                   rURL    ,
                                        const   Sequence< beans::PropertyValue >&  rArgs   )
{
    SfxModelGuard aGuard( *this );
    comphelper::ProfileZone aZone("storeToURL");

    if ( !m_pData->m_pObjectShell.is() )
        return;

    SfxSaveGuard aSaveGuard(this, m_pData.get());
    try {
        utl::MediaDescriptor aDescriptor(rArgs);
        bool bOnMainThread = aDescriptor.getUnpackedValueOrDefault(u"OnMainThread"_ustr, false);
        if (bOnMainThread)
            vcl::solarthread::syncExecute([this, rURL, rArgs]() { impl_store(rURL, rArgs, true); });
        else
            impl_store(rURL, rArgs, true);
    }
    catch (const uno::Exception &e)
    {
        // convert to the exception we announce in the throw
        // (eg. neon likes to throw InteractiveAugmentedIOException which
        // is not an io::IOException)
        throw io::IOException(e.Message, e.Context);
    }
}

sal_Bool SAL_CALL SfxBaseModel::wasModifiedSinceLastSave()
{
    SfxModelGuard aGuard( *this );
    return m_pData->m_oDirtyTimestamp.has_value();
}

void SAL_CALL SfxBaseModel::storeToRecoveryFile( const OUString& i_TargetLocationconst Sequence< PropertyValue >& i_MediaDescriptor )
{
    SfxModelGuard aGuard( *this );

    // delegate
    SfxSaveGuard aSaveGuard( this, m_pData.get() );
    impl_store( i_TargetLocation, i_MediaDescriptor, true );

    // no need for subsequent calls to storeToRecoveryFile, unless we're modified, again
    m_pData->setModifiedForAutoSave(false);
}

sal_Int64 SAL_CALL SfxBaseModel::getModifiedStateDuration()
{
    SfxModelGuard aGuard(*this);
    if (!m_pData->m_oDirtyTimestamp)
        return -1;
    auto ms = std::chrono::ceil<std::chrono::milliseconds>(std::chrono::steady_clock::now()
                                                           - *m_pData->m_oDirtyTimestamp);
    return ms.count();
}

void SAL_CALL SfxBaseModel::recoverFromFile( const OUString& i_SourceLocation, const OUString& i_SalvagedFile, const Sequence< PropertyValue >& i_MediaDescriptor )
{
    SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );

    // delegate to our "load" method
    ::comphelper::NamedValueCollection aMediaDescriptor( i_MediaDescriptor );

    // our load implementation expects the SalvagedFile to be in the media descriptor
    OSL_ENSURE( !aMediaDescriptor.has( u"SalvagedFile"_ustr ) || ( aMediaDescriptor.getOrDefault( u"SalvagedFile"_ustr, OUString() ) == i_SalvagedFile ),
        "SfxBaseModel::recoverFromFile: inconsistent information!" );
    aMediaDescriptor.put( u"SalvagedFile"_ustr, i_SalvagedFile );

    // similar for the to-be-loaded file
    OSL_ENSURE( !aMediaDescriptor.has( u"URL"_ustr ) || ( aMediaDescriptor.getOrDefault( u"URL"_ustr, OUString() ) == i_SourceLocation ),
        "SfxBaseModel::recoverFromFile: inconsistent information!" );
    aMediaDescriptor.put( u"URL"_ustr, i_SourceLocation );

    load( aMediaDescriptor.getPropertyValues() );

    // Note: The XDocumentRecovery interface specification requires us to do an attachResource after loading.
    // However, we will not do this here, as we know that our load implementation (respectively some method
    // called from there) already did so.
    // In particular, the load process might already have modified some elements of the media
    // descriptor, for instance the MacroExecMode (in case the user was involved to decide about it), and we do
    // not want to overwrite it with the "old" elements passed to this method here.
}


// XLoadable


void SAL_CALL SfxBaseModel::initNew()
{
    SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
    if ( IsInitialized() )
        throw frame::DoubleInitializationException( OUString(), *this );

    // the object shell should exist always
    DBG_ASSERT( m_pData->m_pObjectShell.is(), "Model is useless without an ObjectShell" );
    if ( !m_pData->m_pObjectShell.is() )
        return;

    if( m_pData->m_pObjectShell->GetMedium() )
        throw frame::DoubleInitializationException();

    bool bRes = m_pData->m_pObjectShell->DoInitNew();
    ErrCodeMsg nErrCode = m_pData->m_pObjectShell->GetErrorIgnoreWarning() ?
                       m_pData->m_pObjectShell->GetErrorIgnoreWarning() : ERRCODE_IO_CANTCREATE;
    m_pData->m_pObjectShell->ResetError();

    if ( !bRes )
        throw task::ErrorCodeIOException(
            "SfxBaseModel::initNew: " + nErrCode.toString(),
            Reference< XInterface >(), sal_uInt32(nErrCode.GetCode()));
}

namespace {

OUString getFilterProvider( SfxMedium const & rMedium )
{
    const std::shared_ptr<const SfxFilter>& pFilter = rMedium.GetFilter();
    if (!pFilter)
        return OUString();

    return pFilter->GetProviderName();
}

void setUpdatePickList( SfxMedium* pMedium )
{
    if (!pMedium)
        return;

    bool bHidden = false;
    const SfxBoolItem* pHidItem = pMedium->GetItemSet().GetItem(SID_HIDDEN, false);
    if (pHidItem)
        bHidden = pHidItem->GetValue();

    pMedium->SetUpdatePickList(!bHidden);
}

}

void SAL_CALL SfxBaseModel::load(   const Sequence< beans::PropertyValue >& seqArguments )
{
    SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
    if ( IsInitialized() )
        throw frame::DoubleInitializationException( OUString(), *this );

    // the object shell should exist always
    DBG_ASSERT( m_pData->m_pObjectShell.is(), "Model is useless without an ObjectShell" );

    if (!m_pData->m_pObjectShell.is())
        return;

    if( m_pData->m_pObjectShell->GetMedium() )
        // if a Medium is present, the document is already initialized
        throw frame::DoubleInitializationException();

    SfxMedium* pMedium = new SfxMedium( seqArguments );

    ErrCodeMsg nError = ERRCODE_NONE;
    if (!getFilterProvider(*pMedium).isEmpty())
    {
        if (!m_pData->m_pObjectShell->DoLoadExternal(pMedium))
            nError = ERRCODE_IO_GENERAL;

        pMedium = handleLoadError(nError, pMedium);
        setUpdatePickList(pMedium);
        return;
    }

    OUString aFilterName;
    const SfxStringItem* pFilterNameItem = pMedium->GetItemSet().GetItem(SID_FILTER_NAME, false);
    if( pFilterNameItem )
        aFilterName = pFilterNameItem->GetValue();
    if( !m_pData->m_pObjectShell->GetFactory().GetFilterContainer()->GetFilter4FilterName( aFilterName ) )
    {
        // filtername is not valid
        delete pMedium;
        throw frame::IllegalArgumentIOException();
    }

    const SfxStringItem* pSalvageItem = pMedium->GetItemSet().GetItem(SID_DOC_SALVAGE, false);
    bool bSalvage = pSalvageItem != nullptr;

    // load document
    if ( !m_pData->m_pObjectShell->DoLoad(pMedium) )
        nError=ERRCODE_IO_GENERAL;

    // QUESTION: if the following happens outside of DoLoad, something important is missing there!
    Reference< task::XInteractionHandler > xHandler = pMedium->GetInteractionHandler();
    if( m_pData->m_pObjectShell->GetErrorCode() )
    {
        nError = m_pData->m_pObjectShell->GetErrorCode();
        if ( nError == ERRCODE_IO_BROKENPACKAGE && xHandler.is() )
        {
            const OUString aDocName( pMedium->GetURLObject().getName( INetURLObject::LAST_SEGMENTtrue, INetURLObject::DecodeMechanism::WithCharset ) );
            if (!pMedium->IsRepairPackage())
            {
                RequestPackageReparation aRequest( aDocName );
                xHandler->handle( aRequest.GetRequest() );
                if( aRequest.isApproved() )
                {
                    // lok: we want to overwrite file in jail, so don't use template flag
                    bool bIsLOK = comphelper::LibreOfficeKit::isActive();
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=91 H=97 G=93

¤ Dauer der Verarbeitung: 0.21 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.