4640 lines
156 KiB
C++
4640 lines
156 KiB
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& 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& 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& 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& 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()
|
|
{
|
|
SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
|
|
|
|
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 >& aListener )
|
|
{
|
|
SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
|
|
m_pData->m_aEventListeners.addInterface( aListener );
|
|
}
|
|
|
|
|
|
// XChild
|
|
|
|
|
|
void SAL_CALL SfxBaseModel::removeEventListener( const Reference< lang::XEventListener >& 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> & 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 == "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 >& 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( this, true ) );
|
|
}
|
|
}
|
|
|
|
|
|
// 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( this, false ) );
|
|
}
|
|
}
|
|
|
|
|
|
// 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 >& 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 >& 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 >& xListener )
|
|
{
|
|
SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
|
|
|
|
m_pData->m_aCloseListeners.addInterface( xListener );
|
|
}
|
|
|
|
|
|
// XCloseBroadcaster
|
|
|
|
|
|
void SAL_CALL SfxBaseModel::removeCloseListener( const Reference< util::XCloseListener >& 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_TargetLocation, const 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_SEGMENT, true, 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();
|
|
// broken package: try second loading and allow repair
|
|
pMedium->GetItemSet().Put( SfxBoolItem( SID_REPAIRPACKAGE, true ) );
|
|
pMedium->GetItemSet().Put( SfxBoolItem( SID_TEMPLATE, !bIsLOK ) );
|
|
pMedium->GetItemSet().Put( SfxStringItem( SID_DOCINFO_TITLE, aDocName ) );
|
|
|
|
// the error must be reset and the storage must be reopened in new mode
|
|
pMedium->ResetError();
|
|
pMedium->CloseStorage();
|
|
m_pData->m_pObjectShell->PrepareSecondTryLoad_Impl();
|
|
nError = ERRCODE_NONE;
|
|
if ( !m_pData->m_pObjectShell->DoLoad(pMedium) )
|
|
nError=ERRCODE_IO_GENERAL;
|
|
if (m_pData->m_pObjectShell->GetErrorCode())
|
|
nError = m_pData->m_pObjectShell->GetErrorCode();
|
|
}
|
|
}
|
|
|
|
if ( nError == ERRCODE_IO_BROKENPACKAGE )
|
|
{
|
|
// repair either not allowed or not successful
|
|
NotifyBrokenPackage aRequest( aDocName );
|
|
xHandler->handle( aRequest.GetRequest() );
|
|
}
|
|
}
|
|
}
|
|
|
|
if( m_pData->m_pObjectShell->IsAbortingImport() )
|
|
nError = ERRCODE_ABORT;
|
|
|
|
if (bSalvage && nError == ERRCODE_NONE)
|
|
{
|
|
// file recovery: restore original filter
|
|
const SfxStringItem* pFilterItem = pMedium->GetItemSet().GetItem(SID_FILTER_NAME, false);
|
|
SfxFilterMatcher& rMatcher = SfxGetpApp()->GetFilterMatcher();
|
|
std::shared_ptr<const SfxFilter> pSetFilter = rMatcher.GetFilter4FilterName( pFilterItem->GetValue() );
|
|
pMedium->SetFilter( pSetFilter );
|
|
m_pData->m_pObjectShell->SetModified();
|
|
}
|
|
|
|
// TODO/LATER: maybe the mode should be retrieved from outside and the preused filter should not be set
|
|
if ( m_pData->m_pObjectShell->GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
|
|
{
|
|
const SfxStringItem* pFilterItem = pMedium->GetItemSet().GetItem(SID_FILTER_NAME, false);
|
|
if ( pFilterItem )
|
|
m_pData->m_aPreusedFilterName = pFilterItem->GetValue();
|
|
}
|
|
|
|
if ( !nError )
|
|
nError = pMedium->GetErrorIgnoreWarning();
|
|
|
|
m_pData->m_pObjectShell->ResetError();
|
|
|
|
pMedium = handleLoadError(nError, pMedium);
|
|
loadCmisProperties();
|
|
setUpdatePickList(pMedium);
|
|
|
|
#if OSL_DEBUG_LEVEL > 0
|
|
const SfxStringItem* pPasswdItem = pMedium->GetItemSet().GetItem(SID_PASSWORD, false);
|
|
OSL_ENSURE( !pPasswdItem, "There should be no Password property in the document MediaDescriptor!" );
|
|
#endif
|
|
}
|
|
|
|
|
|
// XTransferable
|
|
|
|
|
|
Any SAL_CALL SfxBaseModel::getTransferData( const datatransfer::DataFlavor& aFlavor )
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
Any aAny;
|
|
|
|
if ( m_pData->m_pObjectShell.is() )
|
|
{
|
|
if ( aFlavor.MimeType == "application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star Object Descriptor (XML)\"" )
|
|
{
|
|
if ( aFlavor.DataType != cppu::UnoType<Sequence< sal_Int8 >>::get() )
|
|
throw datatransfer::UnsupportedFlavorException();
|
|
|
|
TransferableObjectDescriptor aDesc;
|
|
|
|
aDesc.maClassName = m_pData->m_pObjectShell->GetClassName();
|
|
aDesc.maTypeName = aFlavor.HumanPresentableName;
|
|
|
|
// TODO/LATER: ViewAspect needs to be sal_Int64
|
|
aDesc.mnViewAspect = sal::static_int_cast< sal_uInt16 >( embed::Aspects::MSOLE_CONTENT );
|
|
|
|
Size aSize = m_pData->m_pObjectShell->GetVisArea().GetSize();
|
|
|
|
MapUnit aMapUnit = m_pData->m_pObjectShell->GetMapUnit();
|
|
aDesc.maSize = OutputDevice::LogicToLogic(aSize, MapMode(aMapUnit), MapMode(MapUnit::Map100thMM));
|
|
aDesc.maDragStartPos = Point();
|
|
aDesc.maDisplayName.clear();
|
|
|
|
SvMemoryStream aMemStm( 1024, 1024 );
|
|
WriteTransferableObjectDescriptor( aMemStm, aDesc );
|
|
aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.Tell() );
|
|
}
|
|
else if ( aFlavor.MimeType == "application/x-openoffice-embed-source;windows_formatname=\"Star EMBS\"" )
|
|
{
|
|
if ( aFlavor.DataType != cppu::UnoType<Sequence< sal_Int8 >>::get() )
|
|
throw datatransfer::UnsupportedFlavorException();
|
|
|
|
try
|
|
{
|
|
utl::TempFileNamed aTmp;
|
|
aTmp.EnableKillingFile();
|
|
storeToURL( aTmp.GetURL(), Sequence < beans::PropertyValue >() );
|
|
std::unique_ptr<SvStream> pStream(aTmp.GetStream( StreamMode::READ ));
|
|
const sal_uInt32 nLen = pStream->TellEnd();
|
|
Sequence< sal_Int8 > aSeq( nLen );
|
|
pStream->ReadBytes(aSeq.getArray(), nLen);
|
|
if( aSeq.hasElements() )
|
|
aAny <<= aSeq;
|
|
}
|
|
catch ( Exception& )
|
|
{
|
|
}
|
|
}
|
|
else if ( aFlavor.MimeType == "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"" )
|
|
{
|
|
if ( aFlavor.DataType != cppu::UnoType<Sequence< sal_Int8 >>::get() )
|
|
throw datatransfer::UnsupportedFlavorException();
|
|
|
|
|
|
std::shared_ptr<GDIMetaFile> xMetaFile =
|
|
m_pData->m_pObjectShell->GetPreviewMetaFile( true );
|
|
|
|
if (xMetaFile)
|
|
{
|
|
SvMemoryStream aMemStm( 65535, 65535 );
|
|
aMemStm.SetVersion( SOFFICE_FILEFORMAT_CURRENT );
|
|
|
|
SvmWriter aWriter( aMemStm );
|
|
aWriter.Write( *xMetaFile );
|
|
aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ),
|
|
aMemStm.TellEnd() );
|
|
}
|
|
}
|
|
else if ( aFlavor.MimeType == "application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\"" )
|
|
{
|
|
if ( aFlavor.DataType != cppu::UnoType<Sequence< sal_Int8 >>::get() )
|
|
throw datatransfer::UnsupportedFlavorException();
|
|
|
|
std::shared_ptr<GDIMetaFile> xMetaFile =
|
|
m_pData->m_pObjectShell->GetPreviewMetaFile( true );
|
|
|
|
if (xMetaFile)
|
|
{
|
|
SvMemoryStream aMemStm( 65535, 65535 );
|
|
aMemStm.SetVersion( SOFFICE_FILEFORMAT_CURRENT );
|
|
|
|
SvmWriter aWriter( aMemStm );
|
|
aWriter.Write( *xMetaFile );
|
|
aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ),
|
|
aMemStm.TellEnd() );
|
|
}
|
|
}
|
|
else if ( aFlavor.MimeType == "application/x-openoffice-emf;windows_formatname=\"Image EMF\"" )
|
|
{
|
|
if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
|
|
{
|
|
std::shared_ptr<GDIMetaFile> xMetaFile =
|
|
m_pData->m_pObjectShell->GetPreviewMetaFile( true );
|
|
|
|
if (xMetaFile)
|
|
{
|
|
std::unique_ptr<SvMemoryStream> xStream(
|
|
GraphicHelper::getFormatStrFromGDI_Impl(
|
|
xMetaFile.get(), ConvertDataFormat::EMF ) );
|
|
if (xStream)
|
|
{
|
|
xStream->SetVersion( SOFFICE_FILEFORMAT_CURRENT );
|
|
aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( xStream->GetData() ),
|
|
xStream->TellEnd() );
|
|
}
|
|
}
|
|
}
|
|
else if ( GraphicHelper::supportsMetaFileHandle_Impl()
|
|
&& aFlavor.DataType == cppu::UnoType<sal_uInt64>::get())
|
|
{
|
|
std::shared_ptr<GDIMetaFile> xMetaFile =
|
|
m_pData->m_pObjectShell->GetPreviewMetaFile( true );
|
|
|
|
if (xMetaFile)
|
|
{
|
|
aAny <<= reinterpret_cast< sal_uInt64 >(
|
|
GraphicHelper::getEnhMetaFileFromGDI_Impl( xMetaFile.get() ) );
|
|
}
|
|
}
|
|
else
|
|
throw datatransfer::UnsupportedFlavorException();
|
|
}
|
|
else if ( aFlavor.MimeType == "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"" )
|
|
{
|
|
if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
|
|
{
|
|
std::shared_ptr<GDIMetaFile> xMetaFile =
|
|
m_pData->m_pObjectShell->GetPreviewMetaFile( true );
|
|
|
|
if (xMetaFile)
|
|
{
|
|
std::unique_ptr<SvMemoryStream> xStream(
|
|
GraphicHelper::getFormatStrFromGDI_Impl(
|
|
xMetaFile.get(), ConvertDataFormat::WMF ) );
|
|
|
|
if (xStream)
|
|
{
|
|
xStream->SetVersion( SOFFICE_FILEFORMAT_CURRENT );
|
|
aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( xStream->GetData() ),
|
|
xStream->TellEnd() );
|
|
}
|
|
}
|
|
}
|
|
else if ( GraphicHelper::supportsMetaFileHandle_Impl()
|
|
&& aFlavor.DataType == cppu::UnoType<sal_uInt64>::get())
|
|
{
|
|
// means HGLOBAL handler to memory storage containing METAFILEPICT structure
|
|
|
|
std::shared_ptr<GDIMetaFile> xMetaFile =
|
|
m_pData->m_pObjectShell->GetPreviewMetaFile( true );
|
|
|
|
if (xMetaFile)
|
|
{
|
|
Size aMetaSize = xMetaFile->GetPrefSize();
|
|
aAny <<= reinterpret_cast< sal_uInt64 >(
|
|
GraphicHelper::getWinMetaFileFromGDI_Impl(
|
|
xMetaFile.get(), aMetaSize ) );
|
|
}
|
|
}
|
|
else
|
|
throw datatransfer::UnsupportedFlavorException();
|
|
}
|
|
else if ( aFlavor.MimeType == "image/svg+xml" )
|
|
{
|
|
if ( aFlavor.DataType != cppu::UnoType<Sequence< sal_Int8 >>::get() )
|
|
throw datatransfer::UnsupportedFlavorException();
|
|
|
|
std::shared_ptr<GDIMetaFile> xMetaFile =
|
|
m_pData->m_pObjectShell->GetPreviewMetaFile( true );
|
|
|
|
if (xMetaFile)
|
|
{
|
|
std::unique_ptr<SvMemoryStream> xStream(
|
|
GraphicHelper::getFormatStrFromGDI_Impl(
|
|
xMetaFile.get(), ConvertDataFormat::SVG ) );
|
|
|
|
if (xStream)
|
|
{
|
|
xStream->SetVersion( SOFFICE_FILEFORMAT_CURRENT );
|
|
aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( xStream->GetData() ),
|
|
xStream->TellEnd() );
|
|
}
|
|
}
|
|
}
|
|
else if ( aFlavor.MimeType == "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"" )
|
|
{
|
|
if ( aFlavor.DataType != cppu::UnoType<Sequence< sal_Int8 >>::get() )
|
|
throw datatransfer::UnsupportedFlavorException();
|
|
|
|
std::shared_ptr<GDIMetaFile> xMetaFile =
|
|
m_pData->m_pObjectShell->GetPreviewMetaFile( true );
|
|
|
|
if (xMetaFile)
|
|
{
|
|
std::unique_ptr<SvMemoryStream> xStream(
|
|
GraphicHelper::getFormatStrFromGDI_Impl(
|
|
xMetaFile.get(), ConvertDataFormat::BMP ) );
|
|
|
|
if (xStream)
|
|
{
|
|
xStream->SetVersion( SOFFICE_FILEFORMAT_CURRENT );
|
|
aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( xStream->GetData() ),
|
|
xStream->TellEnd() );
|
|
}
|
|
}
|
|
}
|
|
else if ( aFlavor.MimeType == "image/png" )
|
|
{
|
|
if ( aFlavor.DataType != cppu::UnoType<Sequence< sal_Int8 >>::get() )
|
|
throw datatransfer::UnsupportedFlavorException();
|
|
|
|
std::shared_ptr<GDIMetaFile> xMetaFile =
|
|
m_pData->m_pObjectShell->GetPreviewMetaFile( true );
|
|
|
|
if (xMetaFile)
|
|
{
|
|
std::unique_ptr<SvMemoryStream> xStream(
|
|
GraphicHelper::getFormatStrFromGDI_Impl(
|
|
xMetaFile.get(), ConvertDataFormat::PNG ) );
|
|
|
|
if (xStream)
|
|
{
|
|
xStream->SetVersion( SOFFICE_FILEFORMAT_CURRENT );
|
|
aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( xStream->GetData() ),
|
|
xStream->TellEnd() );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
throw datatransfer::UnsupportedFlavorException();
|
|
}
|
|
|
|
return aAny;
|
|
}
|
|
|
|
|
|
// XTransferable
|
|
|
|
|
|
Sequence< datatransfer::DataFlavor > SAL_CALL SfxBaseModel::getTransferDataFlavors()
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
const sal_Int32 nSuppFlavors = GraphicHelper::supportsMetaFileHandle_Impl() ? 11 : 9;
|
|
Sequence< datatransfer::DataFlavor > aFlavorSeq( nSuppFlavors );
|
|
auto pFlavorSeq = aFlavorSeq.getArray();
|
|
|
|
pFlavorSeq[0].MimeType =
|
|
"application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"";
|
|
pFlavorSeq[0].HumanPresentableName = "GDIMetaFile";
|
|
pFlavorSeq[0].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
|
|
|
|
pFlavorSeq[1].MimeType =
|
|
"application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\"";
|
|
pFlavorSeq[1].HumanPresentableName = "GDIMetaFile";
|
|
pFlavorSeq[1].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
|
|
|
|
pFlavorSeq[2].MimeType =
|
|
"application/x-openoffice-emf;windows_formatname=\"Image EMF\"" ;
|
|
pFlavorSeq[2].HumanPresentableName = "Enhanced Windows MetaFile";
|
|
pFlavorSeq[2].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
|
|
|
|
pFlavorSeq[3].MimeType =
|
|
"application/x-openoffice-wmf;windows_formatname=\"Image WMF\"";
|
|
pFlavorSeq[3].HumanPresentableName = "Windows MetaFile";
|
|
pFlavorSeq[3].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
|
|
|
|
pFlavorSeq[4].MimeType =
|
|
"application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star Object Descriptor (XML)\"";
|
|
pFlavorSeq[4].HumanPresentableName = "Star Object Descriptor (XML)";
|
|
pFlavorSeq[4].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
|
|
|
|
pFlavorSeq[5].MimeType =
|
|
"application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"";
|
|
pFlavorSeq[5].HumanPresentableName = "Star Embed Source (XML)";
|
|
pFlavorSeq[5].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
|
|
|
|
pFlavorSeq[6].MimeType =
|
|
"application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"";
|
|
pFlavorSeq[6].HumanPresentableName = "Bitmap";
|
|
pFlavorSeq[6].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
|
|
|
|
pFlavorSeq[7].MimeType = "image/png";
|
|
pFlavorSeq[7].HumanPresentableName = "PNG";
|
|
pFlavorSeq[7].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
|
|
|
|
pFlavorSeq[8].MimeType = "image/svg+xml";
|
|
pFlavorSeq[8].HumanPresentableName = "SVG";
|
|
pFlavorSeq[8].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
|
|
|
|
if ( nSuppFlavors == 11 )
|
|
{
|
|
pFlavorSeq[9].MimeType =
|
|
"application/x-openoffice-emf;windows_formatname=\"Image EMF\"";
|
|
pFlavorSeq[9].HumanPresentableName = "Enhanced Windows MetaFile";
|
|
pFlavorSeq[9].DataType = cppu::UnoType<sal_uInt64>::get();
|
|
|
|
pFlavorSeq[10].MimeType =
|
|
"application/x-openoffice-wmf;windows_formatname=\"Image WMF\"";
|
|
pFlavorSeq[10].HumanPresentableName = "Windows MetaFile";
|
|
pFlavorSeq[10].DataType = cppu::UnoType<sal_uInt64>::get();
|
|
}
|
|
|
|
return aFlavorSeq;
|
|
}
|
|
|
|
|
|
// XTransferable
|
|
|
|
|
|
sal_Bool SAL_CALL SfxBaseModel::isDataFlavorSupported( const datatransfer::DataFlavor& aFlavor )
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
if ( aFlavor.MimeType == "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"" )
|
|
{
|
|
if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
|
|
return true;
|
|
}
|
|
else if ( aFlavor.MimeType == "application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\"" )
|
|
{
|
|
if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
|
|
return true;
|
|
}
|
|
else if ( aFlavor.MimeType == "application/x-openoffice-emf;windows_formatname=\"Image EMF\"" )
|
|
{
|
|
if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
|
|
return true;
|
|
else if ( GraphicHelper::supportsMetaFileHandle_Impl()
|
|
&& aFlavor.DataType == cppu::UnoType<sal_uInt64>::get())
|
|
return true;
|
|
}
|
|
else if ( aFlavor.MimeType == "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"" )
|
|
{
|
|
if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
|
|
return true;
|
|
else if ( GraphicHelper::supportsMetaFileHandle_Impl()
|
|
&& aFlavor.DataType == cppu::UnoType<sal_uInt64>::get())
|
|
return true;
|
|
}
|
|
else if ( aFlavor.MimeType == "image/svg+xml" )
|
|
{
|
|
if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
|
|
return true;
|
|
}
|
|
else if ( aFlavor.MimeType == "application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star Object Descriptor (XML)\"" )
|
|
{
|
|
if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
|
|
return true;
|
|
}
|
|
else if ( aFlavor.MimeType == "application/x-openoffice-embed-source;windows_formatname=\"Star EMBS\"" )
|
|
{
|
|
if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
|
|
return true;
|
|
}
|
|
else if ( aFlavor.MimeType == "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"" )
|
|
{
|
|
if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
|
|
return true;
|
|
}
|
|
else if ( aFlavor.MimeType == "image/png" )
|
|
{
|
|
if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
// XEventsSupplier
|
|
|
|
|
|
Reference< container::XNameReplace > SAL_CALL SfxBaseModel::getEvents()
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
if ( ! m_pData->m_xEvents.is() )
|
|
{
|
|
m_pData->m_xEvents = new SfxEvents_Impl( m_pData->m_pObjectShell.get(), this );
|
|
}
|
|
|
|
return m_pData->m_xEvents;
|
|
}
|
|
|
|
|
|
// XEmbeddedScripts
|
|
|
|
|
|
Reference< script::XStorageBasedLibraryContainer > SAL_CALL SfxBaseModel::getBasicLibraries()
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
Reference< script::XStorageBasedLibraryContainer > xBasicLibraries;
|
|
if ( m_pData->m_pObjectShell.is() )
|
|
xBasicLibraries.set(m_pData->m_pObjectShell->GetBasicContainer(), UNO_QUERY);
|
|
return xBasicLibraries;
|
|
}
|
|
|
|
Reference< script::XStorageBasedLibraryContainer > SAL_CALL SfxBaseModel::getDialogLibraries()
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
Reference< script::XStorageBasedLibraryContainer > xDialogLibraries;
|
|
if ( m_pData->m_pObjectShell.is() )
|
|
xDialogLibraries.set(m_pData->m_pObjectShell->GetDialogContainer(), UNO_QUERY);
|
|
return xDialogLibraries;
|
|
}
|
|
|
|
sal_Bool SAL_CALL SfxBaseModel::getAllowMacroExecution()
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
if ( m_pData->m_pObjectShell.is() )
|
|
return m_pData->m_pObjectShell->AdjustMacroMode();
|
|
return false;
|
|
}
|
|
|
|
|
|
// XScriptInvocationContext
|
|
|
|
|
|
Reference< document::XEmbeddedScripts > SAL_CALL SfxBaseModel::getScriptContainer()
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
Reference< document::XEmbeddedScripts > xDocumentScripts;
|
|
|
|
try
|
|
{
|
|
Reference< frame::XModel > xDocument( this );
|
|
xDocumentScripts.set( xDocument, UNO_QUERY );
|
|
while ( !xDocumentScripts.is() && xDocument.is() )
|
|
{
|
|
Reference< container::XChild > xDocAsChild( xDocument, UNO_QUERY );
|
|
if ( !xDocAsChild.is() )
|
|
{
|
|
xDocument = nullptr;
|
|
break;
|
|
}
|
|
|
|
xDocument.set( xDocAsChild->getParent(), UNO_QUERY );
|
|
xDocumentScripts.set( xDocument, UNO_QUERY );
|
|
}
|
|
}
|
|
catch( const Exception& )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION("sfx.doc");
|
|
xDocumentScripts = nullptr;
|
|
}
|
|
|
|
return xDocumentScripts;
|
|
}
|
|
|
|
|
|
// XEventBroadcaster
|
|
|
|
|
|
void SAL_CALL SfxBaseModel::addEventListener( const Reference< document::XEventListener >& aListener )
|
|
{
|
|
SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
|
|
|
|
m_pData->m_aDocumentEventListeners1.addInterface( aListener );
|
|
}
|
|
|
|
|
|
// XEventBroadcaster
|
|
|
|
|
|
void SAL_CALL SfxBaseModel::removeEventListener( const Reference< document::XEventListener >& aListener )
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
m_pData->m_aDocumentEventListeners1.removeInterface( aListener );
|
|
}
|
|
|
|
// XShapeEventBroadcaster
|
|
|
|
void SAL_CALL SfxBaseModel::addShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape, const Reference< document::XShapeEventListener >& xListener )
|
|
{
|
|
assert(xShape.is() && "no shape?");
|
|
SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
|
|
|
|
m_pData->maShapeListeners[xShape].push_back(xListener);
|
|
}
|
|
|
|
|
|
// XShapeEventBroadcaster
|
|
|
|
|
|
void SAL_CALL SfxBaseModel::removeShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape, const Reference< document::XShapeEventListener >& xListener )
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
auto it = m_pData->maShapeListeners.find(xShape);
|
|
if (it != m_pData->maShapeListeners.end())
|
|
{
|
|
auto rVec = it->second;
|
|
auto it2 = std::find(rVec.begin(), rVec.end(), xListener);
|
|
if (it2 != rVec.end())
|
|
{
|
|
rVec.erase(it2);
|
|
if (rVec.empty())
|
|
m_pData->maShapeListeners.erase(it);
|
|
}
|
|
}
|
|
}
|
|
|
|
// XDocumentEventBroadcaster
|
|
|
|
|
|
void SAL_CALL SfxBaseModel::addDocumentEventListener( const Reference< document::XDocumentEventListener >& aListener )
|
|
{
|
|
SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
|
|
m_pData->m_aDocumentEventListeners2.addInterface( aListener );
|
|
}
|
|
|
|
|
|
void SAL_CALL SfxBaseModel::removeDocumentEventListener( const Reference< document::XDocumentEventListener >& aListener )
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
m_pData->m_aDocumentEventListeners2.removeInterface( aListener );
|
|
}
|
|
|
|
|
|
void SAL_CALL SfxBaseModel::notifyDocumentEvent( const OUString&, const Reference< frame::XController2 >&, const Any& )
|
|
{
|
|
throw lang::NoSupportException(u"SfxBaseModel controls all the sent notifications itself!"_ustr );
|
|
}
|
|
|
|
Sequence<document::CmisProperty> SAL_CALL SfxBaseModel::getCmisProperties()
|
|
{
|
|
if (impl_isDisposed())
|
|
return Sequence<document::CmisProperty>();
|
|
return m_pData->m_cmisProperties;
|
|
}
|
|
|
|
void SAL_CALL SfxBaseModel::setCmisProperties( const Sequence< document::CmisProperty >& _cmisproperties )
|
|
{
|
|
m_pData->m_cmisProperties = _cmisproperties;
|
|
}
|
|
|
|
void SAL_CALL SfxBaseModel::updateCmisProperties( const Sequence< document::CmisProperty >& aProperties )
|
|
{
|
|
SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
|
|
if ( !pMedium )
|
|
return;
|
|
|
|
try
|
|
{
|
|
::ucbhelper::Content aContent( pMedium->GetName( ),
|
|
Reference<ucb::XCommandEnvironment>(),
|
|
comphelper::getProcessComponentContext() );
|
|
|
|
aContent.executeCommand( u"updateProperties"_ustr, uno::Any( aProperties ) );
|
|
loadCmisProperties( );
|
|
}
|
|
catch (const Exception & e)
|
|
{
|
|
css::uno::Any anyEx = cppu::getCaughtException();
|
|
throw lang::WrappedTargetRuntimeException( e.Message,
|
|
e.Context, anyEx );
|
|
}
|
|
|
|
}
|
|
|
|
void SAL_CALL SfxBaseModel::checkOut( )
|
|
{
|
|
SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
|
|
if ( !pMedium )
|
|
return;
|
|
|
|
try
|
|
{
|
|
::ucbhelper::Content aContent( pMedium->GetName(),
|
|
Reference<ucb::XCommandEnvironment>(),
|
|
comphelper::getProcessComponentContext() );
|
|
|
|
Any aResult = aContent.executeCommand( u"checkout"_ustr, Any( ) );
|
|
OUString sURL;
|
|
aResult >>= sURL;
|
|
|
|
m_pData->m_pObjectShell->GetMedium( )->SetName( sURL );
|
|
m_pData->m_pObjectShell->GetMedium( )->GetMedium_Impl( );
|
|
m_pData->m_xDocumentProperties->setTitle( getTitle( ) );
|
|
Sequence< beans::PropertyValue > aSequence ;
|
|
TransformItems( SID_OPENDOC, pMedium->GetItemSet(), aSequence );
|
|
attachResource( sURL, aSequence );
|
|
|
|
// Reload the CMIS properties
|
|
loadCmisProperties( );
|
|
}
|
|
catch ( const Exception & e )
|
|
{
|
|
css::uno::Any anyEx = cppu::getCaughtException();
|
|
throw lang::WrappedTargetRuntimeException( e.Message,
|
|
e.Context, anyEx );
|
|
}
|
|
}
|
|
|
|
void SAL_CALL SfxBaseModel::cancelCheckOut( )
|
|
{
|
|
SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
|
|
if ( !pMedium )
|
|
return;
|
|
|
|
try
|
|
{
|
|
::ucbhelper::Content aContent( pMedium->GetName(),
|
|
Reference<ucb::XCommandEnvironment>(),
|
|
comphelper::getProcessComponentContext() );
|
|
|
|
Any aResult = aContent.executeCommand( u"cancelCheckout"_ustr, Any( ) );
|
|
OUString sURL;
|
|
aResult >>= sURL;
|
|
|
|
m_pData->m_pObjectShell->GetMedium( )->SetName( sURL );
|
|
}
|
|
catch ( const Exception & e )
|
|
{
|
|
css::uno::Any anyEx = cppu::getCaughtException();
|
|
throw lang::WrappedTargetRuntimeException( e.Message,
|
|
e.Context, anyEx );
|
|
}
|
|
}
|
|
|
|
void SAL_CALL SfxBaseModel::checkIn( sal_Bool bIsMajor, const OUString& rMessage )
|
|
{
|
|
SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
|
|
if ( !pMedium )
|
|
return;
|
|
|
|
try
|
|
{
|
|
Sequence< beans::PropertyValue > aProps{
|
|
comphelper::makePropertyValue(u"VersionMajor"_ustr, bIsMajor),
|
|
comphelper::makePropertyValue(u"VersionComment"_ustr, rMessage),
|
|
comphelper::makePropertyValue(u"CheckIn"_ustr, true)
|
|
};
|
|
|
|
const OUString sName( pMedium->GetName( ) );
|
|
storeSelf( aProps );
|
|
|
|
// Refresh pMedium as it has probably changed during the storeSelf call
|
|
pMedium = m_pData->m_pObjectShell->GetMedium( );
|
|
const OUString sNewName( pMedium->GetName( ) );
|
|
|
|
// URL has changed, update the document
|
|
if ( sName != sNewName )
|
|
{
|
|
m_pData->m_xDocumentProperties->setTitle( getTitle( ) );
|
|
Sequence< beans::PropertyValue > aSequence ;
|
|
TransformItems( SID_OPENDOC, pMedium->GetItemSet(), aSequence );
|
|
attachResource( sNewName, aSequence );
|
|
|
|
// Reload the CMIS properties
|
|
loadCmisProperties( );
|
|
}
|
|
}
|
|
catch ( const Exception & e )
|
|
{
|
|
css::uno::Any anyEx = cppu::getCaughtException();
|
|
throw lang::WrappedTargetRuntimeException( e.Message,
|
|
e.Context, anyEx );
|
|
}
|
|
}
|
|
|
|
uno::Sequence< document::CmisVersion > SAL_CALL SfxBaseModel::getAllVersions( )
|
|
{
|
|
uno::Sequence<document::CmisVersion> aVersions;
|
|
if (impl_isDisposed())
|
|
return aVersions;
|
|
SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
|
|
if ( pMedium )
|
|
{
|
|
try
|
|
{
|
|
::ucbhelper::Content aContent( pMedium->GetName(),
|
|
Reference<ucb::XCommandEnvironment>(),
|
|
comphelper::getProcessComponentContext() );
|
|
|
|
Any aResult = aContent.executeCommand( u"getAllVersions"_ustr, Any( ) );
|
|
aResult >>= aVersions;
|
|
}
|
|
catch ( const Exception & e )
|
|
{
|
|
css::uno::Any anyEx = cppu::getCaughtException();
|
|
throw lang::WrappedTargetRuntimeException( e.Message,
|
|
e.Context, anyEx );
|
|
}
|
|
}
|
|
return aVersions;
|
|
}
|
|
|
|
bool SfxBaseModel::getBoolPropertyValue( const OUString& rName )
|
|
{
|
|
bool bValue = false;
|
|
if ( m_pData->m_pObjectShell.is() )
|
|
{
|
|
SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
|
|
if ( pMedium )
|
|
{
|
|
try
|
|
{
|
|
::ucbhelper::Content aContent( pMedium->GetName( ),
|
|
utl::UCBContentHelper::getDefaultCommandEnvironment(),
|
|
comphelper::getProcessComponentContext() );
|
|
Reference < beans::XPropertySetInfo > xProps = aContent.getProperties();
|
|
if ( xProps->hasPropertyByName( rName ) )
|
|
{
|
|
aContent.getPropertyValue( rName ) >>= bValue;
|
|
}
|
|
}
|
|
catch ( const Exception & )
|
|
{
|
|
// Simply ignore it: it's likely the document isn't versionable in that case
|
|
bValue = false;
|
|
}
|
|
}
|
|
}
|
|
return bValue;
|
|
}
|
|
|
|
sal_Bool SAL_CALL SfxBaseModel::isVersionable( )
|
|
{
|
|
return getBoolPropertyValue( u"IsVersionable"_ustr );
|
|
}
|
|
|
|
sal_Bool SAL_CALL SfxBaseModel::canCheckOut( )
|
|
{
|
|
return getBoolPropertyValue( u"CanCheckOut"_ustr );
|
|
}
|
|
|
|
sal_Bool SAL_CALL SfxBaseModel::canCancelCheckOut( )
|
|
{
|
|
return getBoolPropertyValue( u"CanCancelCheckOut"_ustr );
|
|
}
|
|
|
|
sal_Bool SAL_CALL SfxBaseModel::canCheckIn( )
|
|
{
|
|
return getBoolPropertyValue( u"CanCheckIn"_ustr );
|
|
}
|
|
|
|
void SfxBaseModel::loadCmisProperties( )
|
|
{
|
|
SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
|
|
if ( !pMedium )
|
|
return;
|
|
|
|
try
|
|
{
|
|
::ucbhelper::Content aContent( pMedium->GetName( ),
|
|
utl::UCBContentHelper::getDefaultCommandEnvironment(),
|
|
comphelper::getProcessComponentContext() );
|
|
Reference < beans::XPropertySetInfo > xProps = aContent.getProperties();
|
|
static constexpr OUString aCmisProps( u"CmisProperties"_ustr );
|
|
if ( xProps->hasPropertyByName( aCmisProps ) )
|
|
{
|
|
Sequence< document::CmisProperty> aCmisProperties;
|
|
aContent.getPropertyValue( aCmisProps ) >>= aCmisProperties;
|
|
setCmisProperties( aCmisProperties );
|
|
}
|
|
}
|
|
catch (const ucb::ContentCreationException &)
|
|
{
|
|
}
|
|
catch (const ucb::CommandAbortedException &)
|
|
{
|
|
}
|
|
}
|
|
|
|
SfxMedium* SfxBaseModel::handleLoadError( const ErrCodeMsg& rError, SfxMedium* pMedium )
|
|
{
|
|
if (!rError)
|
|
{
|
|
// No error condition.
|
|
return pMedium;
|
|
}
|
|
|
|
ErrCodeMsg nError = rError;
|
|
bool bSilent = false;
|
|
const SfxBoolItem* pSilentItem = pMedium->GetItemSet().GetItem(SID_SILENT, false);
|
|
if( pSilentItem )
|
|
bSilent = pSilentItem->GetValue();
|
|
|
|
bool bWarning = nError.IsWarning();
|
|
if ( nError != ERRCODE_IO_BROKENPACKAGE && !bSilent )
|
|
{
|
|
// broken package was handled already
|
|
if ( SfxObjectShell::UseInteractionToHandleError(pMedium->GetInteractionHandler(), nError) && !bWarning)
|
|
{
|
|
// abort loading (except for warnings)
|
|
nError = ERRCODE_IO_ABORT;
|
|
}
|
|
}
|
|
|
|
if ( m_pData->m_pObjectShell->GetMedium() != pMedium )
|
|
{
|
|
// for whatever reason document now has another medium
|
|
OSL_FAIL("Document has rejected the medium?!");
|
|
delete pMedium;
|
|
pMedium = nullptr;
|
|
}
|
|
|
|
if ( !bWarning ) // #i30711# don't abort loading if it's only a warning
|
|
{
|
|
nError = nError ? nError : ERRCODE_IO_CANTREAD;
|
|
throw task::ErrorCodeIOException(
|
|
"SfxBaseModel::handleLoadError: 0x" + nError.toString(),
|
|
Reference< XInterface >(), sal_uInt32(nError.GetCode()));
|
|
}
|
|
else
|
|
pMedium->SetWarningError(nError);
|
|
|
|
return pMedium;
|
|
}
|
|
|
|
|
|
// SfxListener
|
|
|
|
|
|
static void addTitle_Impl( Sequence < beans::PropertyValue >& rSeq, const OUString& rTitle )
|
|
{
|
|
auto [begin, end] = asNonConstRange(rSeq);
|
|
auto pProp = std::find_if(begin, end,
|
|
[](const beans::PropertyValue& rProp) { return rProp.Name == "Title"; });
|
|
if (pProp != end)
|
|
{
|
|
pProp->Value <<= rTitle;
|
|
}
|
|
else
|
|
{
|
|
sal_Int32 nCount = rSeq.getLength();
|
|
rSeq.realloc( nCount+1 );
|
|
auto& el = rSeq.getArray()[nCount];
|
|
el.Name = "Title";
|
|
el.Value <<= rTitle;
|
|
}
|
|
}
|
|
|
|
void SfxBaseModel::Notify( SfxBroadcaster& rBC ,
|
|
const SfxHint& rHint )
|
|
{
|
|
if ( !m_pData )
|
|
return;
|
|
|
|
if ( &rBC != m_pData->m_pObjectShell.get() )
|
|
return;
|
|
|
|
if ( rHint.GetId() == SfxHintId::DocChanged )
|
|
changing();
|
|
else if (rHint.GetId() == SfxHintId::ThisIsAnSfxEventHint)
|
|
{
|
|
const SfxEventHint& rNamedHint = static_cast<const SfxEventHint&>(rHint);
|
|
switch (rNamedHint.GetEventId())
|
|
{
|
|
case SfxEventHintId::StorageChanged:
|
|
{
|
|
if ( m_pData->m_xUIConfigurationManager.is()
|
|
&& m_pData->m_pObjectShell->GetCreateMode() != SfxObjectCreateMode::EMBEDDED )
|
|
{
|
|
Reference< embed::XStorage > xConfigStorage;
|
|
static constexpr OUString aUIConfigFolderName( u"Configurations2"_ustr );
|
|
|
|
xConfigStorage = getDocumentSubStorage( aUIConfigFolderName, embed::ElementModes::READWRITE );
|
|
if ( !xConfigStorage.is() )
|
|
xConfigStorage = getDocumentSubStorage( aUIConfigFolderName, embed::ElementModes::READ );
|
|
|
|
if ( xConfigStorage.is() || !m_pData->m_pObjectShell->GetStorage()->hasByName( aUIConfigFolderName ) )
|
|
{
|
|
// the storage is different, since otherwise it could not be opened, so it must be exchanged
|
|
m_pData->m_xUIConfigurationManager->setStorage( xConfigStorage );
|
|
}
|
|
else
|
|
{
|
|
OSL_FAIL( "Unexpected scenario!" );
|
|
}
|
|
}
|
|
|
|
ListenForStorage_Impl( m_pData->m_pObjectShell->GetStorage() );
|
|
}
|
|
break;
|
|
|
|
case SfxEventHintId::LoadFinished:
|
|
{
|
|
impl_getPrintHelper();
|
|
ListenForStorage_Impl( m_pData->m_pObjectShell->GetStorage() );
|
|
m_pData->setModifiedForAutoSave(false);
|
|
}
|
|
break;
|
|
|
|
case SfxEventHintId::SaveAsDocDone:
|
|
{
|
|
m_pData->m_sURL = m_pData->m_pObjectShell->GetMedium()->GetName();
|
|
|
|
Sequence< beans::PropertyValue > aArgs;
|
|
TransformItems( SID_SAVEASDOC, m_pData->m_pObjectShell->GetMedium()->GetItemSet(), aArgs );
|
|
addTitle_Impl( aArgs, m_pData->m_pObjectShell->GetTitle() );
|
|
attachResource( m_pData->m_pObjectShell->GetMedium()->GetName(), aArgs );
|
|
}
|
|
break;
|
|
|
|
case SfxEventHintId::DocCreated:
|
|
{
|
|
impl_getPrintHelper();
|
|
m_pData->setModifiedForAutoSave(false);
|
|
}
|
|
break;
|
|
|
|
case SfxEventHintId::ModifyChanged:
|
|
{
|
|
m_pData->setModifiedForAutoSave(isModified());
|
|
}
|
|
break;
|
|
default: break;
|
|
}
|
|
|
|
Any aSupplement;
|
|
if (rNamedHint.GetEventId() == SfxEventHintId::PrintDoc)
|
|
aSupplement <<= static_cast<const SfxPrintingHint*>(&rHint)->GetWhich();
|
|
const SfxViewEventHint* pViewHint = dynamic_cast<const SfxViewEventHint*>(&rHint);
|
|
postEvent_Impl( rNamedHint.GetEventName(), pViewHint ? pViewHint->GetController() : Reference< frame::XController2 >(), aSupplement );
|
|
}
|
|
else if ( rHint.GetId() == SfxHintId::TitleChanged )
|
|
{
|
|
addTitle_Impl( m_pData->m_seqArguments, m_pData->m_pObjectShell->GetTitle() );
|
|
postEvent_Impl( GlobalEventConfig::GetEventName( GlobalEventId::TITLECHANGED ) );
|
|
}
|
|
else if ( rHint.GetId() == SfxHintId::ModeChanged )
|
|
{
|
|
postEvent_Impl( GlobalEventConfig::GetEventName( GlobalEventId::MODECHANGED ) );
|
|
}
|
|
}
|
|
|
|
|
|
// public impl.
|
|
|
|
|
|
void SfxBaseModel::NotifyModifyListeners_Impl() const
|
|
{
|
|
if ( m_pData->m_aModifyListeners.getLength() )
|
|
{
|
|
lang::EventObject aEvent( static_cast<frame::XModel *>(const_cast<SfxBaseModel *>(this)) );
|
|
m_pData->m_aModifyListeners.notifyEach( &util::XModifyListener::modified, aEvent );
|
|
}
|
|
|
|
// this notification here is done too generously, we cannot simply assume that we're really modified
|
|
// now, but we need to check it ...
|
|
m_pData->setModifiedForAutoSave(const_cast<SfxBaseModel*>(this)->isModified());
|
|
}
|
|
|
|
void SfxBaseModel::changing()
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
// the notification should not be sent if the document can not be modified
|
|
if ( !m_pData->m_pObjectShell.is() || !m_pData->m_pObjectShell->IsEnableSetModified() )
|
|
return;
|
|
|
|
NotifyModifyListeners_Impl();
|
|
}
|
|
|
|
|
|
// public impl.
|
|
|
|
|
|
SfxObjectShell* SfxBaseModel::GetObjectShell() const
|
|
{
|
|
return m_pData ? m_pData->m_pObjectShell.get() : nullptr;
|
|
}
|
|
|
|
|
|
// public impl.
|
|
|
|
|
|
bool SfxBaseModel::IsInitialized() const
|
|
{
|
|
if ( !m_pData || !m_pData->m_pObjectShell.is() )
|
|
{
|
|
OSL_FAIL( "SfxBaseModel::IsInitialized: this should have been caught earlier!" );
|
|
return false;
|
|
}
|
|
|
|
return m_pData->m_pObjectShell->GetMedium() != nullptr;
|
|
}
|
|
|
|
void SfxBaseModel::MethodEntryCheck( const bool i_mustBeInitialized ) const
|
|
{
|
|
if ( impl_isDisposed() )
|
|
throw lang::DisposedException( OUString(), *const_cast< SfxBaseModel* >( this ) );
|
|
if ( i_mustBeInitialized && !IsInitialized() )
|
|
throw lang::NotInitializedException( OUString(), *const_cast< SfxBaseModel* >( this ) );
|
|
}
|
|
|
|
bool SfxBaseModel::impl_isDisposed() const
|
|
{
|
|
return ( m_pData == nullptr ) ;
|
|
}
|
|
|
|
|
|
// private impl.
|
|
|
|
|
|
OUString SfxBaseModel::GetMediumFilterName_Impl() const
|
|
{
|
|
std::shared_ptr<const SfxFilter> pFilter;
|
|
SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
|
|
if ( pMedium )
|
|
pFilter = pMedium->GetFilter();
|
|
|
|
if ( pFilter )
|
|
return pFilter->GetName();
|
|
|
|
return OUString();
|
|
}
|
|
|
|
void SfxBaseModel::impl_store( const OUString& sURL ,
|
|
const Sequence< beans::PropertyValue >& seqArguments ,
|
|
bool bSaveTo )
|
|
{
|
|
if( sURL.isEmpty() )
|
|
throw frame::IllegalArgumentIOException();
|
|
|
|
if (!m_pData->m_pObjectShell)
|
|
return;
|
|
|
|
::comphelper::SequenceAsHashMap aArgHash(seqArguments);
|
|
if ( !bSaveTo && !sURL.isEmpty()
|
|
&& !sURL.startsWith( "private:stream" )
|
|
&& ::utl::UCBContentHelper::EqualURLs( getLocation(), sURL ) )
|
|
{
|
|
// this is the same file URL as the current document location, try to use storeOwn if possible
|
|
|
|
static constexpr OUString aFilterString( u"FilterName"_ustr );
|
|
const OUString aFilterName( aArgHash.getUnpackedValueOrDefault( aFilterString, OUString() ) );
|
|
if ( !aFilterName.isEmpty() )
|
|
{
|
|
SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
|
|
if ( pMedium )
|
|
{
|
|
const std::shared_ptr<const SfxFilter>& pFilter = pMedium->GetFilter();
|
|
if ( pFilter && aFilterName == pFilter->GetFilterName() )
|
|
{
|
|
// #i119366# - If the former file saving with password, do not trying in StoreSelf anyway...
|
|
bool bFormerPassword = false;
|
|
{
|
|
uno::Sequence< beans::NamedValue > aOldEncryptionData;
|
|
if (GetEncryptionData_Impl( &pMedium->GetItemSet(), aOldEncryptionData ))
|
|
{
|
|
bFormerPassword = true;
|
|
}
|
|
}
|
|
if ( !bFormerPassword )
|
|
{
|
|
aArgHash.erase( aFilterString );
|
|
aArgHash.erase( u"URL"_ustr );
|
|
|
|
try
|
|
{
|
|
storeSelf( aArgHash.getAsConstPropertyValueList() );
|
|
return;
|
|
}
|
|
catch( const lang::IllegalArgumentException& )
|
|
{
|
|
#if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
|
|
// some additional arguments do not allow to use saving, SaveAs should be done
|
|
// but only for normal documents, the shared documents would be overwritten in this case
|
|
// that would mean an information loss
|
|
// TODO/LATER: need a new interaction for this case
|
|
if ( m_pData->m_pObjectShell->IsDocShared() )
|
|
{
|
|
uno::Sequence< beans::NamedValue > aNewEncryptionData = aArgHash.getUnpackedValueOrDefault(u"EncryptionData"_ustr, uno::Sequence< beans::NamedValue >() );
|
|
if ( !aNewEncryptionData.hasElements() )
|
|
{
|
|
aNewEncryptionData = ::comphelper::OStorageHelper::CreatePackageEncryptionData( aArgHash.getUnpackedValueOrDefault(u"Password"_ustr, OUString()) );
|
|
}
|
|
|
|
uno::Sequence< beans::NamedValue > aOldEncryptionData;
|
|
(void)GetEncryptionData_Impl( &pMedium->GetItemSet(), aOldEncryptionData );
|
|
|
|
if ( !aOldEncryptionData.hasElements() && !aNewEncryptionData.hasElements() )
|
|
throw;
|
|
else
|
|
{
|
|
// if the password is changed a special error should be used in case of shared document
|
|
throw task::ErrorCodeIOException(u"Can not change password for shared document."_ustr, uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_SFX_SHARED_NOPASSWORDCHANGE) );
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SfxGetpApp()->NotifyEvent( SfxEventHint( bSaveTo ? SfxEventHintId::SaveToDoc : SfxEventHintId::SaveAsDoc, GlobalEventConfig::GetEventName( bSaveTo ? GlobalEventId::SAVETODOC : GlobalEventId::SAVEASDOC ),
|
|
m_pData->m_pObjectShell.get() ) );
|
|
|
|
const OUString aFilterName(aArgHash.getUnpackedValueOrDefault(u"FilterName"_ustr, OUString()));
|
|
OUString aPassword, aPasswordToModify;
|
|
if (!aArgHash.getUnpackedValueOrDefault(u"EncryptionData"_ustr, Sequence<beans::NamedValue>())
|
|
.hasElements())
|
|
aPassword = aArgHash.getUnpackedValueOrDefault(u"Password"_ustr, OUString());
|
|
if (!aArgHash.getUnpackedValueOrDefault(u"ModifyPasswordInfo"_ustr, Sequence<beans::PropertyValue>())
|
|
.hasElements()
|
|
&& aArgHash.getUnpackedValueOrDefault(u"ModifyPasswordInfo"_ustr, static_cast<sal_Int32>(0)) == 0)
|
|
aPasswordToModify = aArgHash.getUnpackedValueOrDefault(u"PasswordToModify"_ustr, OUString());
|
|
aArgHash.erase(u"PasswordToModify"_ustr);
|
|
|
|
std::optional<SfxAllItemSet> pItemSet(SfxGetpApp()->GetPool());
|
|
pItemSet->Put(SfxStringItem(SID_FILE_NAME, sURL));
|
|
if ( bSaveTo )
|
|
pItemSet->Put(SfxBoolItem(SID_SAVETO, true));
|
|
|
|
if (!aFilterName.isEmpty() && (!aPassword.isEmpty() || !aPasswordToModify.isEmpty()))
|
|
sfx2::SetPassword(SfxGetpApp()->GetFilterMatcher().GetFilter4FilterName(aFilterName),
|
|
&*pItemSet, aPassword, aPasswordToModify, false);
|
|
|
|
TransformParameters(SID_SAVEASDOC, seqArguments, *pItemSet);
|
|
|
|
const SfxBoolItem* pCopyStreamItem = pItemSet->GetItem<SfxBoolItem>(SID_COPY_STREAM_IF_POSSIBLE, false);
|
|
|
|
if ( pCopyStreamItem && pCopyStreamItem->GetValue() && !bSaveTo )
|
|
{
|
|
throw frame::IllegalArgumentIOException(
|
|
u"CopyStreamIfPossible parameter is not acceptable for storeAsURL() call!"_ustr );
|
|
}
|
|
|
|
sal_uInt32 nModifyPasswordHash = 0;
|
|
Sequence< beans::PropertyValue > aModifyPasswordInfo;
|
|
const SfxUnoAnyItem* pModifyPasswordInfoItem = pItemSet->GetItem<SfxUnoAnyItem>(SID_MODIFYPASSWORDINFO, false);
|
|
if ( pModifyPasswordInfoItem )
|
|
{
|
|
// it contains either a simple hash or a set of PropertyValues
|
|
// TODO/LATER: the sequence of PropertyValue should replace the hash completely in future
|
|
sal_Int32 nMPHTmp = 0;
|
|
pModifyPasswordInfoItem->GetValue() >>= nMPHTmp;
|
|
nModifyPasswordHash = static_cast<sal_uInt32>(nMPHTmp);
|
|
pModifyPasswordInfoItem->GetValue() >>= aModifyPasswordInfo;
|
|
}
|
|
pItemSet->ClearItem(SID_MODIFYPASSWORDINFO);
|
|
sal_uInt32 nOldModifyPasswordHash = m_pData->m_pObjectShell->GetModifyPasswordHash();
|
|
m_pData->m_pObjectShell->SetModifyPasswordHash( nModifyPasswordHash );
|
|
Sequence< beans::PropertyValue > aOldModifyPasswordInfo = m_pData->m_pObjectShell->GetModifyPasswordInfo();
|
|
m_pData->m_pObjectShell->SetModifyPasswordInfo( aModifyPasswordInfo );
|
|
|
|
// since saving a document modifies its DocumentProperties, the current
|
|
// DocumentProperties must be saved on "SaveTo", so it can be restored
|
|
// after saving
|
|
bool bCopyTo = bSaveTo ||
|
|
m_pData->m_pObjectShell->GetCreateMode() == SfxObjectCreateMode::EMBEDDED;
|
|
Reference<document::XDocumentProperties> xOldDocProps;
|
|
if ( bCopyTo )
|
|
{
|
|
xOldDocProps = getDocumentProperties();
|
|
const Reference<util::XCloneable> xCloneable(xOldDocProps,
|
|
UNO_QUERY_THROW);
|
|
const Reference<document::XDocumentProperties> xNewDocProps(
|
|
xCloneable->createClone(), UNO_QUERY_THROW);
|
|
m_pData->m_xDocumentProperties = xNewDocProps;
|
|
}
|
|
|
|
bool bRet = m_pData->m_pObjectShell->APISaveAs_Impl(sURL, *pItemSet, seqArguments);
|
|
|
|
if ( bCopyTo )
|
|
{
|
|
// restore DocumentProperties if a copy was created
|
|
m_pData->m_xDocumentProperties = std::move(xOldDocProps);
|
|
}
|
|
|
|
Reference < task::XInteractionHandler > xHandler;
|
|
const SfxUnoAnyItem* pItem = pItemSet->GetItem<SfxUnoAnyItem>(SID_INTERACTIONHANDLER, false);
|
|
if ( pItem )
|
|
pItem->GetValue() >>= xHandler;
|
|
|
|
pItemSet.reset();
|
|
|
|
ErrCodeMsg nErrCode = m_pData->m_pObjectShell->GetErrorCode();
|
|
if ( !bRet && !nErrCode )
|
|
{
|
|
SAL_WARN("sfx.doc", "Storing has failed, no error is set!");
|
|
nErrCode = ERRCODE_IO_CANTWRITE;
|
|
}
|
|
m_pData->m_pObjectShell->ResetError();
|
|
|
|
if ( bRet )
|
|
{
|
|
if ( nErrCode )
|
|
{
|
|
// must be a warning - use Interactionhandler if possible or abandon
|
|
if ( xHandler.is() )
|
|
{
|
|
// TODO/LATER: a general way to set the error context should be available
|
|
SfxErrorContext aEc( ERRCTX_SFX_SAVEASDOC, m_pData->m_pObjectShell->GetTitle() );
|
|
|
|
task::ErrorCodeRequest2 aErrorCode(OUString(), uno::Reference<XInterface>(),
|
|
sal_Int32(sal_uInt32(nErrCode.GetCode())), nErrCode.GetArg1(), nErrCode.GetArg2(),
|
|
static_cast<sal_Int16>(nErrCode.GetDialogMask()));
|
|
SfxMedium::CallApproveHandler( xHandler, Any( aErrorCode ), false );
|
|
}
|
|
}
|
|
|
|
if ( !bSaveTo )
|
|
{
|
|
m_pData->m_aPreusedFilterName = GetMediumFilterName_Impl();
|
|
m_pData->m_pObjectShell->SetModifyPasswordEntered();
|
|
|
|
SfxGetpApp()->NotifyEvent( SfxEventHint( SfxEventHintId::SaveAsDocDone, GlobalEventConfig::GetEventName(GlobalEventId::SAVEASDOCDONE), m_pData->m_pObjectShell.get() ) );
|
|
}
|
|
else
|
|
{
|
|
m_pData->m_pObjectShell->SetModifyPasswordHash( nOldModifyPasswordHash );
|
|
m_pData->m_pObjectShell->SetModifyPasswordInfo( aOldModifyPasswordInfo );
|
|
|
|
SfxGetpApp()->NotifyEvent( SfxEventHint( SfxEventHintId::SaveToDocDone, GlobalEventConfig::GetEventName(GlobalEventId::SAVETODOCDONE), m_pData->m_pObjectShell.get() ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_pData->m_pObjectShell->SetModifyPasswordHash( nOldModifyPasswordHash );
|
|
m_pData->m_pObjectShell->SetModifyPasswordInfo( aOldModifyPasswordInfo );
|
|
|
|
|
|
SfxGetpApp()->NotifyEvent( SfxEventHint( bSaveTo ? SfxEventHintId::SaveToDocFailed : SfxEventHintId::SaveAsDocFailed, GlobalEventConfig::GetEventName( bSaveTo ? GlobalEventId::SAVETODOCFAILED : GlobalEventId::SAVEASDOCFAILED),
|
|
m_pData->m_pObjectShell.get() ) );
|
|
|
|
if (SfxViewShell* pNotifyView = comphelper::LibreOfficeKit::isActive() ? SfxViewShell::Current() : nullptr)
|
|
pNotifyView->libreOfficeKitViewCallback(LOK_CALLBACK_EXPORT_FILE, "ERROR"_ostr);
|
|
|
|
std::stringstream aErrCode;
|
|
aErrCode << nErrCode;
|
|
throw task::ErrorCodeIOException(
|
|
"SfxBaseModel::impl_store <" + sURL + "> failed: " + OUString::fromUtf8(aErrCode.str()),
|
|
Reference< XInterface >(), sal_uInt32(nErrCode.GetCode()));
|
|
}
|
|
}
|
|
|
|
|
|
namespace {
|
|
template< typename ListenerT, typename EventT >
|
|
class NotifySingleListenerIgnoreRE
|
|
{
|
|
private:
|
|
typedef void ( SAL_CALL ListenerT::*NotificationMethod )( const EventT& );
|
|
NotificationMethod m_pMethod;
|
|
const EventT& m_rEvent;
|
|
public:
|
|
NotifySingleListenerIgnoreRE( NotificationMethod method, const EventT& event ) : m_pMethod( method ), m_rEvent( event ) { }
|
|
|
|
void operator()( const Reference<ListenerT>& listener ) const
|
|
{
|
|
try
|
|
{
|
|
(listener.get()->*m_pMethod)( m_rEvent );
|
|
}
|
|
catch( RuntimeException& )
|
|
{
|
|
// this exception is ignored to avoid problems with invalid listeners, the listener should be probably thrown away in future
|
|
TOOLS_WARN_EXCEPTION("sfx.appl", "ignoring");
|
|
}
|
|
}
|
|
};
|
|
} // anonymous namespace
|
|
|
|
void SfxBaseModel::postEvent_Impl( const OUString& aName, const Reference< frame::XController2 >& xController, const Any& supplement )
|
|
{
|
|
if (aName.isEmpty())
|
|
{
|
|
SAL_WARN("sfx.doc", "postEvent_Impl: Empty event name!");
|
|
return;
|
|
}
|
|
|
|
// also make sure this object doesn't self-destruct while notifying
|
|
rtl::Reference<SfxBaseModel> xHoldAlive(this);
|
|
// keep m_pData alive, if notified target would dispose the document
|
|
std::shared_ptr<IMPL_SfxBaseModel_DataContainer> xKeepAlive(m_pData);
|
|
|
|
// object already disposed?
|
|
if ( impl_isDisposed() )
|
|
return;
|
|
|
|
if ( xKeepAlive->m_aDocumentEventListeners2.getLength() )
|
|
{
|
|
SAL_INFO("sfx.doc", "SfxDocumentEvent: " + aName);
|
|
|
|
document::DocumentEvent aDocumentEvent( static_cast<frame::XModel*>(this), aName, xController, supplement );
|
|
|
|
xKeepAlive->m_aDocumentEventListeners2.forEach(
|
|
NotifySingleListenerIgnoreRE< document::XDocumentEventListener, document::DocumentEvent >(
|
|
&document::XDocumentEventListener::documentEventOccured,
|
|
aDocumentEvent ) );
|
|
}
|
|
|
|
if ( xKeepAlive->m_aDocumentEventListeners1.getLength() )
|
|
{
|
|
SAL_INFO("sfx.doc", "SfxEvent: " + aName);
|
|
|
|
document::EventObject aEvent( static_cast<frame::XModel*>(this), aName );
|
|
|
|
xKeepAlive->m_aDocumentEventListeners1.forEach(
|
|
NotifySingleListenerIgnoreRE< document::XEventListener, document::EventObject >(
|
|
&document::XEventListener::notifyEvent,
|
|
aEvent ) );
|
|
}
|
|
}
|
|
|
|
Reference < container::XIndexAccess > SAL_CALL SfxBaseModel::getViewData()
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
if ( m_pData->m_pObjectShell.is() && !m_pData->m_contViewData.is() )
|
|
{
|
|
SfxViewFrame *pActFrame = SfxViewFrame::Current();
|
|
if ( !pActFrame || pActFrame->GetObjectShell() != m_pData->m_pObjectShell.get() )
|
|
pActFrame = SfxViewFrame::GetFirst( m_pData->m_pObjectShell.get() );
|
|
|
|
if ( !pActFrame || !pActFrame->GetViewShell() )
|
|
// currently no frame for this document at all or View is under construction
|
|
return Reference < container::XIndexAccess >();
|
|
|
|
m_pData->m_contViewData = new comphelper::IndexedPropertyValuesContainer();
|
|
|
|
if ( !m_pData->m_contViewData.is() )
|
|
{
|
|
// error: no container class available!
|
|
return Reference < container::XIndexAccess >();
|
|
}
|
|
|
|
Reference < container::XIndexContainer > xCont( m_pData->m_contViewData, UNO_QUERY );
|
|
sal_Int32 nCount = 0;
|
|
Sequence < beans::PropertyValue > aSeq;
|
|
for ( SfxViewFrame *pFrame = SfxViewFrame::GetFirst( m_pData->m_pObjectShell.get() ); pFrame;
|
|
pFrame = SfxViewFrame::GetNext( *pFrame, m_pData->m_pObjectShell.get() ) )
|
|
{
|
|
bool bIsActive = ( pFrame == pActFrame );
|
|
pFrame->GetViewShell()->WriteUserDataSequence( aSeq );
|
|
xCont->insertByIndex( bIsActive ? 0 : nCount, Any(aSeq) );
|
|
nCount++;
|
|
}
|
|
}
|
|
|
|
return m_pData->m_contViewData;
|
|
}
|
|
|
|
void SAL_CALL SfxBaseModel::setViewData( const Reference < container::XIndexAccess >& aData )
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
m_pData->m_contViewData = aData;
|
|
}
|
|
|
|
/** calls all XEventListeners */
|
|
void SfxBaseModel::notifyEvent( const document::EventObject& aEvent ) const
|
|
{
|
|
// object already disposed?
|
|
if ( impl_isDisposed() )
|
|
return;
|
|
|
|
if( !m_pData->m_aDocumentEventListeners1.getLength() )
|
|
|
|
return;
|
|
|
|
comphelper::OInterfaceIteratorHelper3 aIt( m_pData->m_aDocumentEventListeners1 );
|
|
while( aIt.hasMoreElements() )
|
|
{
|
|
try
|
|
{
|
|
aIt.next()->notifyEvent( aEvent );
|
|
}
|
|
catch( RuntimeException& )
|
|
{
|
|
aIt.remove();
|
|
}
|
|
}
|
|
// for right now, we're only doing the event that this particular performance problem needed
|
|
if (aEvent.EventName == "ShapeModified")
|
|
{
|
|
uno::Reference<drawing::XShape> xShape(aEvent.Source, uno::UNO_QUERY);
|
|
if (xShape.is())
|
|
{
|
|
auto it = m_pData->maShapeListeners.find(xShape);
|
|
if (it != m_pData->maShapeListeners.end())
|
|
for (auto const & rListenerUnoRef : it->second)
|
|
rListenerUnoRef->notifyShapeEvent(aEvent);
|
|
}
|
|
}
|
|
}
|
|
|
|
/** returns true if someone added a XEventListener to this XEventBroadcaster */
|
|
bool SfxBaseModel::hasEventListeners() const
|
|
{
|
|
return !impl_isDisposed()
|
|
&& ( m_pData->m_aDocumentEventListeners1.getLength() != 0
|
|
|| !m_pData->maShapeListeners.empty());
|
|
}
|
|
|
|
void SAL_CALL SfxBaseModel::addPrintJobListener( const Reference< view::XPrintJobListener >& xListener )
|
|
{
|
|
SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
|
|
|
|
impl_getPrintHelper();
|
|
if ( m_pData->m_xPrintable.is() )
|
|
m_pData->m_xPrintable->addPrintJobListener( xListener );
|
|
}
|
|
|
|
void SAL_CALL SfxBaseModel::removePrintJobListener( const Reference< view::XPrintJobListener >& xListener )
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
impl_getPrintHelper();
|
|
if ( m_pData->m_xPrintable.is() )
|
|
m_pData->m_xPrintable->removePrintJobListener( xListener );
|
|
}
|
|
|
|
sal_Int64 SAL_CALL SfxBaseModel::getSomething( const Sequence< sal_Int8 >& aIdentifier )
|
|
{
|
|
SvGlobalName aName( aIdentifier );
|
|
if (aName == SvGlobalName( SFX_GLOBAL_CLASSID ))
|
|
{
|
|
SolarMutexGuard aGuard;
|
|
SfxObjectShell *const pObjectShell(GetObjectShell());
|
|
if (pObjectShell)
|
|
{
|
|
return comphelper::getSomething_cast(pObjectShell);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
// XDocumentSubStorageSupplier
|
|
|
|
|
|
void SfxBaseModel::ListenForStorage_Impl( const Reference< embed::XStorage >& xStorage )
|
|
{
|
|
Reference< util::XModifiable > xModifiable( xStorage, UNO_QUERY );
|
|
if ( xModifiable.is() )
|
|
{
|
|
if ( !m_pData->m_pStorageModifyListen.is() )
|
|
{
|
|
m_pData->m_pStorageModifyListen = new ::sfx2::DocumentStorageModifyListener( *m_pData, Application::GetSolarMutex() );
|
|
}
|
|
|
|
// no need to deregister the listening for old storage since it should be disposed automatically
|
|
xModifiable->addModifyListener( m_pData->m_pStorageModifyListen );
|
|
}
|
|
}
|
|
|
|
Reference< embed::XStorage > SAL_CALL SfxBaseModel::getDocumentSubStorage( const OUString& aStorageName, sal_Int32 nMode )
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
Reference< embed::XStorage > xResult;
|
|
if ( m_pData->m_pObjectShell.is() )
|
|
{
|
|
Reference< embed::XStorage > xStorage = m_pData->m_pObjectShell->GetStorage();
|
|
if ( xStorage.is() )
|
|
{
|
|
try
|
|
{
|
|
xResult = xStorage->openStorageElement( aStorageName, nMode );
|
|
}
|
|
catch ( Exception& )
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
return xResult;
|
|
}
|
|
|
|
Sequence< OUString > SAL_CALL SfxBaseModel::getDocumentSubStoragesNames()
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
Sequence< OUString > aResult;
|
|
bool bSuccess = false;
|
|
if ( m_pData->m_pObjectShell.is() )
|
|
{
|
|
Reference < embed::XStorage > xStorage = m_pData->m_pObjectShell->GetStorage();
|
|
if ( xStorage.is() )
|
|
{
|
|
const Sequence< OUString > aTemp = xStorage->getElementNames();
|
|
sal_Int32 nResultSize = 0;
|
|
for ( const auto& rName : aTemp )
|
|
{
|
|
if ( xStorage->isStorageElement( rName ) )
|
|
{
|
|
aResult.realloc( ++nResultSize );
|
|
aResult.getArray()[ nResultSize - 1 ] = rName;
|
|
}
|
|
}
|
|
|
|
bSuccess = true;
|
|
}
|
|
}
|
|
|
|
if ( !bSuccess )
|
|
throw io::IOException();
|
|
|
|
return aResult;
|
|
}
|
|
|
|
|
|
// XScriptProviderSupplier
|
|
|
|
|
|
Reference< script::provider::XScriptProvider > SAL_CALL SfxBaseModel::getScriptProvider()
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
Reference< script::provider::XScriptProviderFactory > xScriptProviderFactory =
|
|
script::provider::theMasterScriptProviderFactory::get( ::comphelper::getProcessComponentContext() );
|
|
|
|
Reference< XScriptInvocationContext > xScriptContext( this );
|
|
|
|
Reference< script::provider::XScriptProvider > xScriptProvider(
|
|
xScriptProviderFactory->createScriptProvider( Any( xScriptContext ) ),
|
|
UNO_SET_THROW );
|
|
|
|
return xScriptProvider;
|
|
}
|
|
|
|
|
|
// XUIConfigurationManagerSupplier
|
|
|
|
|
|
OUString const & SfxBaseModel::getRuntimeUID() const
|
|
{
|
|
OSL_ENSURE( !m_pData->m_sRuntimeUID.isEmpty(),
|
|
"SfxBaseModel::getRuntimeUID - ID is empty!" );
|
|
return m_pData->m_sRuntimeUID;
|
|
}
|
|
|
|
bool SfxBaseModel::hasValidSignatures() const
|
|
{
|
|
SolarMutexGuard aGuard;
|
|
if ( m_pData->m_pObjectShell.is() )
|
|
return ( m_pData->m_pObjectShell->ImplGetSignatureState() == SignatureState::OK );
|
|
return false;
|
|
}
|
|
|
|
void SfxBaseModel::getGrabBagItem(css::uno::Any& rVal) const
|
|
{
|
|
if (m_pData->m_xGrabBagItem)
|
|
m_pData->m_xGrabBagItem->QueryValue(rVal);
|
|
else
|
|
rVal <<= uno::Sequence<beans::PropertyValue>();
|
|
}
|
|
|
|
void SfxBaseModel::setGrabBagItem(const css::uno::Any& rVal)
|
|
{
|
|
if (!m_pData->m_xGrabBagItem)
|
|
m_pData->m_xGrabBagItem = std::make_shared<SfxGrabBagItem>();
|
|
|
|
m_pData->m_xGrabBagItem->PutValue(rVal, 0);
|
|
}
|
|
|
|
static void GetCommandFromSequence( OUString& rCommand, sal_Int32& nIndex, const Sequence< beans::PropertyValue >& rSeqPropValue )
|
|
{
|
|
nIndex = -1;
|
|
|
|
auto pPropValue = std::find_if(rSeqPropValue.begin(), rSeqPropValue.end(),
|
|
[](const beans::PropertyValue& rPropValue) { return rPropValue.Name == "Command"; });
|
|
if (pPropValue != rSeqPropValue.end())
|
|
{
|
|
pPropValue->Value >>= rCommand;
|
|
nIndex = static_cast<sal_Int32>(std::distance(rSeqPropValue.begin(), pPropValue));
|
|
}
|
|
}
|
|
|
|
static void ConvertSlotsToCommands( SfxObjectShell const * pDoc, Reference< container::XIndexContainer > const & rToolbarDefinition )
|
|
{
|
|
if ( !pDoc )
|
|
return;
|
|
|
|
SfxModule* pModule( pDoc->GetFactory().GetModule() );
|
|
Sequence< beans::PropertyValue > aSeqPropValue;
|
|
|
|
for ( sal_Int32 i = 0; i < rToolbarDefinition->getCount(); i++ )
|
|
{
|
|
if ( rToolbarDefinition->getByIndex( i ) >>= aSeqPropValue )
|
|
{
|
|
OUString aCommand;
|
|
sal_Int32 nIndex( -1 );
|
|
GetCommandFromSequence( aCommand, nIndex, aSeqPropValue );
|
|
if ( nIndex >= 0 && aCommand.startsWith( "slot:" ) )
|
|
{
|
|
const sal_uInt16 nSlot = o3tl::toInt32(aCommand.subView( 5 ));
|
|
|
|
// We have to replace the old "slot-Command" with our new ".uno:-Command"
|
|
const SfxSlot* pSlot = pModule->GetSlotPool()->GetSlot( nSlot );
|
|
if ( pSlot )
|
|
{
|
|
aCommand = pSlot->GetCommand();
|
|
aSeqPropValue.getArray()[nIndex].Value <<= aCommand;
|
|
rToolbarDefinition->replaceByIndex( i, Any( aSeqPropValue ));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Reference< ui::XUIConfigurationManager > SAL_CALL SfxBaseModel::getUIConfigurationManager()
|
|
{
|
|
return Reference< ui::XUIConfigurationManager >( getUIConfigurationManager2(), UNO_QUERY_THROW );
|
|
}
|
|
|
|
Reference< ui::XUIConfigurationManager2 > SfxBaseModel::getUIConfigurationManager2()
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
if ( !m_pData->m_xUIConfigurationManager.is() )
|
|
{
|
|
Reference< ui::XUIConfigurationManager2 > xNewUIConfMan =
|
|
ui::UIConfigurationManager::create( comphelper::getProcessComponentContext() );
|
|
|
|
Reference< embed::XStorage > xConfigStorage;
|
|
|
|
OUString aUIConfigFolderName( u"Configurations2"_ustr );
|
|
// First try to open with READWRITE and then READ
|
|
xConfigStorage = getDocumentSubStorage( aUIConfigFolderName, embed::ElementModes::READWRITE );
|
|
if ( xConfigStorage.is() )
|
|
{
|
|
static constexpr OUString aMediaTypeProp( u"MediaType"_ustr );
|
|
OUString aMediaType;
|
|
Reference< beans::XPropertySet > xPropSet( xConfigStorage, UNO_QUERY );
|
|
Any a = xPropSet->getPropertyValue( aMediaTypeProp );
|
|
if ( !( a >>= aMediaType ) || aMediaType.isEmpty())
|
|
{
|
|
xPropSet->setPropertyValue( aMediaTypeProp, Any(u"application/vnd.sun.xml.ui.configuration"_ustr) );
|
|
}
|
|
}
|
|
else
|
|
xConfigStorage = getDocumentSubStorage( aUIConfigFolderName, embed::ElementModes::READ );
|
|
|
|
// initialize ui configuration manager with document substorage
|
|
xNewUIConfMan->setStorage( xConfigStorage );
|
|
|
|
// embedded objects did not support local configuration data until OOo 3.0, so there's nothing to
|
|
// migrate
|
|
if ( m_pData->m_pObjectShell->GetCreateMode() != SfxObjectCreateMode::EMBEDDED )
|
|
{
|
|
// Import old UI configuration from OOo 1.x
|
|
|
|
// Try to open with READ
|
|
Reference< embed::XStorage > xOOo1ConfigStorage = getDocumentSubStorage( u"Configurations"_ustr, embed::ElementModes::READ );
|
|
if ( xOOo1ConfigStorage.is() )
|
|
{
|
|
const Reference< XComponentContext >& xContext( ::comphelper::getProcessComponentContext() );
|
|
std::vector< Reference< container::XIndexContainer > > rToolbars;
|
|
|
|
bool bImported = framework::UIConfigurationImporterOOo1x::ImportCustomToolbars(
|
|
xNewUIConfMan, rToolbars, xContext, xOOo1ConfigStorage );
|
|
if ( bImported )
|
|
{
|
|
SfxObjectShell* pObjShell = SfxBaseModel::GetObjectShell();
|
|
|
|
for ( size_t i = 0; i < rToolbars.size(); i++ )
|
|
{
|
|
const OUString sId(OUString::number( i + 1 ));
|
|
const OUString aCustomTbxName = "private:resource/toolbar/custom_OOo1x_" + sId;
|
|
|
|
const Reference< container::XIndexContainer >& xToolbar = rToolbars[i];
|
|
ConvertSlotsToCommands( pObjShell, xToolbar );
|
|
if ( !xNewUIConfMan->hasSettings( aCustomTbxName ))
|
|
{
|
|
// Set UIName for the toolbar with container property
|
|
Reference< beans::XPropertySet > xPropSet( xToolbar, UNO_QUERY );
|
|
if ( xPropSet.is() )
|
|
{
|
|
try
|
|
{
|
|
xPropSet->setPropertyValue( u"UIName"_ustr, Any( "Toolbar " + sId ) );
|
|
}
|
|
catch ( beans::UnknownPropertyException& )
|
|
{
|
|
}
|
|
}
|
|
|
|
xNewUIConfMan->insertSettings( aCustomTbxName, xToolbar );
|
|
xNewUIConfMan->store();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
m_pData->m_xUIConfigurationManager = std::move(xNewUIConfMan);
|
|
}
|
|
|
|
return m_pData->m_xUIConfigurationManager;
|
|
}
|
|
|
|
|
|
// XVisualObject
|
|
|
|
|
|
void SAL_CALL SfxBaseModel::setVisualAreaSize( sal_Int64 nAspect, const awt::Size& aSize )
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
if ( !m_pData->m_pObjectShell.is() )
|
|
throw Exception(u"no object shell"_ustr, nullptr); // TODO: error handling
|
|
|
|
SfxViewFrame* pViewFrm = SfxViewFrame::GetFirst( m_pData->m_pObjectShell.get(), false );
|
|
if ( pViewFrm && m_pData->m_pObjectShell->GetCreateMode() == SfxObjectCreateMode::EMBEDDED && !pViewFrm->GetFrame().IsInPlace() )
|
|
{
|
|
VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( pViewFrm->GetFrame().GetFrameInterface()->getContainerWindow() );
|
|
Size aWinSize = pWindow->GetSizePixel();
|
|
awt::Size aCurrent = getVisualAreaSize( nAspect );
|
|
Size aDiff( aSize.Width-aCurrent.Width, aSize.Height-aCurrent.Height );
|
|
aDiff = pViewFrm->GetViewShell()->GetWindow()->LogicToPixel( aDiff );
|
|
aWinSize.AdjustWidth(aDiff.Width() );
|
|
aWinSize.AdjustHeight(aDiff.Height() );
|
|
pWindow->SetSizePixel( aWinSize );
|
|
}
|
|
else
|
|
{
|
|
tools::Rectangle aTmpRect = m_pData->m_pObjectShell->GetVisArea( ASPECT_CONTENT );
|
|
aTmpRect.SetSize( Size( aSize.Width, aSize.Height ) );
|
|
m_pData->m_pObjectShell->SetVisArea( aTmpRect );
|
|
}
|
|
}
|
|
|
|
awt::Size SAL_CALL SfxBaseModel::getVisualAreaSize( sal_Int64 /*nAspect*/ )
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
if ( !m_pData->m_pObjectShell.is() )
|
|
throw Exception(u"no object shell"_ustr, nullptr); // TODO: error handling
|
|
|
|
tools::Rectangle aTmpRect = m_pData->m_pObjectShell->GetVisArea( ASPECT_CONTENT );
|
|
|
|
return awt::Size( aTmpRect.GetWidth(), aTmpRect.GetHeight() );
|
|
}
|
|
|
|
|
|
sal_Int32 SAL_CALL SfxBaseModel::getMapUnit( sal_Int64 /*nAspect*/ )
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
if ( !m_pData->m_pObjectShell.is() )
|
|
throw Exception(u"no object shell"_ustr, nullptr); // TODO: error handling
|
|
|
|
return VCLUnoHelper::VCL2UnoEmbedMapUnit( m_pData->m_pObjectShell->GetMapUnit() );
|
|
}
|
|
|
|
embed::VisualRepresentation SAL_CALL SfxBaseModel::getPreferredVisualRepresentation( ::sal_Int64 /*nAspect*/ )
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
datatransfer::DataFlavor aDataFlavor(
|
|
u"application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\""_ustr,
|
|
u"GDIMetaFile"_ustr,
|
|
cppu::UnoType<Sequence< sal_Int8 >>::get() );
|
|
|
|
embed::VisualRepresentation aVisualRepresentation;
|
|
aVisualRepresentation.Data = getTransferData( aDataFlavor );
|
|
aVisualRepresentation.Flavor = std::move(aDataFlavor);
|
|
|
|
return aVisualRepresentation;
|
|
}
|
|
|
|
|
|
// XStorageBasedDocument
|
|
|
|
|
|
void SAL_CALL SfxBaseModel::loadFromStorage( const Reference< embed::XStorage >& xStorage,
|
|
const Sequence< beans::PropertyValue >& aMediaDescriptor )
|
|
{
|
|
SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
|
|
if ( IsInitialized() )
|
|
throw frame::DoubleInitializationException( OUString(), *this );
|
|
|
|
// after i36090 is fixed the pool from object shell can be used
|
|
// SfxAllItemSet aSet( m_pData->m_pObjectShell->GetPool() );
|
|
SfxAllItemSet aSet( SfxGetpApp()->GetPool() );
|
|
|
|
// the BaseURL is part of the ItemSet
|
|
SfxMedium* pMedium = new SfxMedium( xStorage, OUString() );
|
|
TransformParameters( SID_OPENDOC, aMediaDescriptor, aSet );
|
|
pMedium->GetItemSet().Put( aSet );
|
|
|
|
// allow to use an interactionhandler (if there is one)
|
|
pMedium->UseInteractionHandler( true );
|
|
|
|
const SfxBoolItem* pTemplateItem = aSet.GetItem<SfxBoolItem>(SID_TEMPLATE, false);
|
|
bool bTemplate = pTemplateItem && pTemplateItem->GetValue();
|
|
m_pData->m_pObjectShell->SetActivateEvent_Impl( bTemplate ? SfxEventHintId::CreateDoc : SfxEventHintId::OpenDoc );
|
|
m_pData->m_pObjectShell->Get_Impl()->bOwnsStorage = false;
|
|
|
|
// load document
|
|
if ( !m_pData->m_pObjectShell->DoLoad(pMedium) )
|
|
{
|
|
ErrCodeMsg nError = m_pData->m_pObjectShell->GetErrorCode();
|
|
nError = nError ? nError : ERRCODE_IO_CANTREAD;
|
|
throw task::ErrorCodeIOException(
|
|
"SfxBaseModel::loadFromStorage: " + nError.toString(),
|
|
Reference< XInterface >(), sal_uInt32(nError.GetCode()));
|
|
}
|
|
loadCmisProperties( );
|
|
}
|
|
|
|
void SAL_CALL SfxBaseModel::storeToStorage( const Reference< embed::XStorage >& xStorage,
|
|
const Sequence< beans::PropertyValue >& aMediaDescriptor )
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
if ( !m_pData->m_pObjectShell.is() )
|
|
throw io::IOException(); // TODO:
|
|
|
|
auto xSet = std::make_shared<SfxAllItemSet>(m_pData->m_pObjectShell->GetPool());
|
|
TransformParameters( SID_SAVEASDOC, aMediaDescriptor, *xSet );
|
|
|
|
// TODO/LATER: maybe a special URL "private:storage" should be used
|
|
const SfxStringItem* pItem = xSet->GetItem<SfxStringItem>(SID_FILTER_NAME, false);
|
|
sal_Int32 nVersion = SOFFICE_FILEFORMAT_CURRENT;
|
|
if( pItem )
|
|
{
|
|
std::shared_ptr<const SfxFilter> pFilter = SfxGetpApp()->GetFilterMatcher().GetFilter4FilterName( pItem->GetValue() );
|
|
if ( pFilter && pFilter->UsesStorage() )
|
|
nVersion = pFilter->GetVersion();
|
|
}
|
|
|
|
bool bSuccess = false;
|
|
if ( xStorage == m_pData->m_pObjectShell->GetStorage() )
|
|
{
|
|
// storing to the own storage
|
|
bSuccess = m_pData->m_pObjectShell->DoSave();
|
|
}
|
|
else
|
|
{
|
|
// TODO/LATER: if the provided storage has some data inside the storing might fail, probably the storage must be truncated
|
|
// TODO/LATER: is it possible to have a template here?
|
|
m_pData->m_pObjectShell->SetupStorage( xStorage, nVersion, false );
|
|
|
|
// BaseURL is part of the ItemSet
|
|
SfxMedium aMedium( xStorage, OUString(), xSet );
|
|
aMedium.CanDisposeStorage_Impl( false );
|
|
if ( aMedium.GetFilter() )
|
|
{
|
|
// storing without a valid filter will often crash
|
|
bSuccess = m_pData->m_pObjectShell->DoSaveObjectAs( aMedium, true );
|
|
m_pData->m_pObjectShell->DoSaveCompleted();
|
|
}
|
|
}
|
|
|
|
ErrCodeMsg nError = m_pData->m_pObjectShell->GetErrorCode();
|
|
m_pData->m_pObjectShell->ResetError();
|
|
|
|
// the warnings are currently not transported
|
|
if ( !bSuccess )
|
|
{
|
|
nError = nError ? nError : ERRCODE_IO_GENERAL;
|
|
throw task::ErrorCodeIOException(
|
|
"SfxBaseModel::storeToStorage: " + nError.toString(),
|
|
Reference< XInterface >(), sal_uInt32(nError.GetCode()));
|
|
}
|
|
}
|
|
|
|
void SAL_CALL SfxBaseModel::switchToStorage( const Reference< embed::XStorage >& xStorage )
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
if ( !m_pData->m_pObjectShell.is() )
|
|
throw io::IOException(); // TODO:
|
|
|
|
// the persistence should be switched only if the storage is different
|
|
if ( xStorage != m_pData->m_pObjectShell->GetStorage() )
|
|
{
|
|
if ( !m_pData->m_pObjectShell->SwitchPersistence( xStorage ) )
|
|
{
|
|
ErrCodeMsg nError = m_pData->m_pObjectShell->GetErrorCode();
|
|
nError = nError ? nError : ERRCODE_IO_GENERAL;
|
|
throw task::ErrorCodeIOException(
|
|
"SfxBaseModel::switchToStorage: " + nError.toString(),
|
|
Reference< XInterface >(), sal_uInt32(nError.GetCode()));
|
|
}
|
|
else
|
|
{
|
|
// UICfgMgr has a reference to the old storage, update it
|
|
getUIConfigurationManager2()->setStorage( xStorage );
|
|
}
|
|
}
|
|
m_pData->m_pObjectShell->Get_Impl()->bOwnsStorage = false;
|
|
}
|
|
|
|
Reference< embed::XStorage > SAL_CALL SfxBaseModel::getDocumentStorage()
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
if ( !m_pData->m_pObjectShell.is() )
|
|
throw io::IOException(); // TODO
|
|
|
|
return m_pData->m_pObjectShell->GetStorage();
|
|
}
|
|
|
|
void SAL_CALL SfxBaseModel::addStorageChangeListener(
|
|
const Reference< document::XStorageChangeListener >& xListener )
|
|
{
|
|
SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
|
|
|
|
m_pData->m_aStorageChangeListeners.addInterface( xListener );
|
|
}
|
|
|
|
void SAL_CALL SfxBaseModel::removeStorageChangeListener(
|
|
const Reference< document::XStorageChangeListener >& xListener )
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
m_pData->m_aStorageChangeListeners.removeInterface( xListener );
|
|
}
|
|
|
|
void SfxBaseModel::impl_getPrintHelper()
|
|
{
|
|
if ( m_pData->m_xPrintable.is() )
|
|
return;
|
|
m_pData->m_xPrintable = new SfxPrintHelper();
|
|
m_pData->m_xPrintable->initialize( { Any(Reference < frame::XModel > (this)) } );
|
|
m_pData->m_xPrintable->addPrintJobListener( new SfxPrintHelperListener_Impl( m_pData.get() ) );
|
|
}
|
|
|
|
|
|
// css.frame.XModule
|
|
void SAL_CALL SfxBaseModel::setIdentifier(const OUString& Identifier)
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
m_pData->m_sModuleIdentifier = Identifier;
|
|
}
|
|
|
|
|
|
// css.frame.XModule
|
|
OUString SAL_CALL SfxBaseModel::getIdentifier()
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
if (!m_pData->m_sModuleIdentifier.isEmpty())
|
|
return m_pData->m_sModuleIdentifier;
|
|
if (m_pData->m_pObjectShell.is())
|
|
return m_pData->m_pObjectShell->GetFactory().GetDocumentServiceName();
|
|
return OUString();
|
|
}
|
|
|
|
|
|
Reference< frame::XTitle > SfxBaseModel::impl_getTitleHelper ()
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
if ( ! m_pData->m_xTitleHelper.is ())
|
|
{
|
|
const Reference< XComponentContext >& xContext = ::comphelper::getProcessComponentContext();
|
|
Reference< frame::XUntitledNumbers > xDesktop( frame::Desktop::create(xContext), UNO_QUERY_THROW);
|
|
|
|
m_pData->m_xTitleHelper = new ::framework::TitleHelper(xContext, Reference< frame::XModel >(this), xDesktop);
|
|
}
|
|
|
|
return m_pData->m_xTitleHelper;
|
|
}
|
|
|
|
|
|
Reference< frame::XUntitledNumbers > SfxBaseModel::impl_getUntitledHelper ()
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
if ( ! m_pData->m_xNumberedControllers.is ())
|
|
{
|
|
m_pData->m_xNumberedControllers = new ::comphelper::NumberedCollection();
|
|
m_pData->m_xNumberedControllers->setOwner (Reference< frame::XModel >(this));
|
|
m_pData->m_xNumberedControllers->setUntitledPrefix (u" : "_ustr);
|
|
}
|
|
|
|
return m_pData->m_xNumberedControllers;
|
|
}
|
|
|
|
|
|
// css.frame.XTitle
|
|
OUString SAL_CALL SfxBaseModel::getTitle()
|
|
{
|
|
// SYNCHRONIZED ->
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
OUString aResult = impl_getTitleHelper()->getTitle ();
|
|
if ( !m_pData->m_bExternalTitle && m_pData->m_pObjectShell )
|
|
{
|
|
SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
|
|
if ( pMedium )
|
|
{
|
|
try {
|
|
::ucbhelper::Content aContent( pMedium->GetName(),
|
|
utl::UCBContentHelper::getDefaultCommandEnvironment(),
|
|
comphelper::getProcessComponentContext() );
|
|
const Reference < beans::XPropertySetInfo > xProps
|
|
= aContent.getProperties();
|
|
if ( xProps.is() )
|
|
{
|
|
static constexpr OUString aServerTitle( u"TitleOnServer"_ustr );
|
|
if ( xProps->hasPropertyByName( aServerTitle ) )
|
|
{
|
|
Any aAny = aContent.getPropertyValue( aServerTitle );
|
|
aAny >>= aResult;
|
|
}
|
|
}
|
|
}
|
|
catch (const ucb::ContentCreationException &)
|
|
{
|
|
}
|
|
catch (const ucb::CommandAbortedException &)
|
|
{
|
|
}
|
|
if (pMedium->IsRepairPackage())
|
|
aResult += SfxResId(STR_REPAIREDDOCUMENT);
|
|
}
|
|
|
|
if ( m_pData->m_pObjectShell->IsReadOnlyUI() || (pMedium && pMedium->IsReadOnly()) )
|
|
aResult += SfxResId(STR_READONLY);
|
|
else if ( m_pData->m_pObjectShell->IsDocShared() )
|
|
aResult += SfxResId(STR_SHARED);
|
|
|
|
if ( m_pData->m_pObjectShell->GetDocumentSignatureState() == SignatureState::OK )
|
|
aResult += SfxResId(RID_XMLSEC_DOCUMENTSIGNED);
|
|
}
|
|
|
|
return aResult;
|
|
}
|
|
|
|
|
|
// css.frame.XTitle
|
|
void SAL_CALL SfxBaseModel::setTitle( const OUString& sTitle )
|
|
{
|
|
// SYNCHRONIZED ->
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
impl_getTitleHelper()->setTitle (sTitle);
|
|
m_pData->m_bExternalTitle = true;
|
|
}
|
|
|
|
|
|
// css.frame.XTitleChangeBroadcaster
|
|
void SAL_CALL SfxBaseModel::addTitleChangeListener( const Reference< frame::XTitleChangeListener >& xListener )
|
|
{
|
|
// SYNCHRONIZED ->
|
|
SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
|
|
|
|
Reference< frame::XTitleChangeBroadcaster > xBroadcaster(impl_getTitleHelper(), UNO_QUERY);
|
|
if (xBroadcaster.is ())
|
|
xBroadcaster->addTitleChangeListener (xListener);
|
|
}
|
|
|
|
|
|
// css.frame.XTitleChangeBroadcaster
|
|
void SAL_CALL SfxBaseModel::removeTitleChangeListener( const Reference< frame::XTitleChangeListener >& xListener )
|
|
{
|
|
// SYNCHRONIZED ->
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
Reference< frame::XTitleChangeBroadcaster > xBroadcaster(impl_getTitleHelper(), UNO_QUERY);
|
|
if (xBroadcaster.is ())
|
|
xBroadcaster->removeTitleChangeListener (xListener);
|
|
}
|
|
|
|
|
|
// css.frame.XUntitledNumbers
|
|
::sal_Int32 SAL_CALL SfxBaseModel::leaseNumber( const Reference< XInterface >& xComponent )
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
return impl_getUntitledHelper ()->leaseNumber (xComponent);
|
|
}
|
|
|
|
|
|
// css.frame.XUntitledNumbers
|
|
void SAL_CALL SfxBaseModel::releaseNumber( ::sal_Int32 nNumber )
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
impl_getUntitledHelper ()->releaseNumber (nNumber);
|
|
}
|
|
|
|
|
|
// css.frame.XUntitledNumbers
|
|
void SAL_CALL SfxBaseModel::releaseNumberForComponent( const Reference< XInterface >& xComponent )
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
impl_getUntitledHelper ()->releaseNumberForComponent (xComponent);
|
|
}
|
|
|
|
|
|
// css.frame.XUntitledNumbers
|
|
OUString SAL_CALL SfxBaseModel::getUntitledPrefix()
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
return impl_getUntitledHelper ()->getUntitledPrefix ();
|
|
}
|
|
|
|
|
|
// frame::XModel2
|
|
Reference< container::XEnumeration > SAL_CALL SfxBaseModel::getControllers()
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
sal_Int32 c = m_pData->m_seqControllers.size();
|
|
Sequence< Any > lEnum(c);
|
|
std::transform(m_pData->m_seqControllers.begin(), m_pData->m_seqControllers.end(),
|
|
lEnum.getArray(), [](const auto& x) { return css::uno::Any(x); });
|
|
|
|
return new ::comphelper::OAnyEnumeration(lEnum);
|
|
}
|
|
|
|
|
|
// frame::XModel2
|
|
Sequence< OUString > SAL_CALL SfxBaseModel::getAvailableViewControllerNames()
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
const SfxObjectFactory& rDocumentFactory = GetObjectShell()->GetFactory();
|
|
const sal_Int16 nViewFactoryCount = rDocumentFactory.GetViewFactoryCount();
|
|
|
|
Sequence< OUString > aViewNames( nViewFactoryCount );
|
|
auto aViewNamesRange = asNonConstRange(aViewNames);
|
|
for ( sal_Int16 nViewNo = 0; nViewNo < nViewFactoryCount; ++nViewNo )
|
|
aViewNamesRange[nViewNo] = rDocumentFactory.GetViewFactory( nViewNo ).GetAPIViewName();
|
|
return aViewNames;
|
|
}
|
|
|
|
|
|
// frame::XModel2
|
|
Reference< frame::XController2 > SAL_CALL SfxBaseModel::createDefaultViewController( const Reference< frame::XFrame >& i_rFrame )
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
const SfxObjectFactory& rDocumentFactory = GetObjectShell()->GetFactory();
|
|
const OUString sDefaultViewName = rDocumentFactory.GetViewFactory().GetAPIViewName();
|
|
|
|
aGuard.clear();
|
|
|
|
return createViewController( sDefaultViewName, Sequence< PropertyValue >(), i_rFrame );
|
|
}
|
|
|
|
|
|
namespace sfx::intern {
|
|
|
|
/** a class which, in its dtor, cleans up various objects (well, at the moment only the frame) collected during
|
|
the creation of a document view, unless the creation was successful.
|
|
*/
|
|
class ViewCreationGuard
|
|
{
|
|
public:
|
|
ViewCreationGuard()
|
|
:m_bSuccess( false )
|
|
{
|
|
}
|
|
|
|
~ViewCreationGuard()
|
|
{
|
|
if ( !m_bSuccess && m_aWeakFrame && !m_aWeakFrame->GetCurrentDocument() )
|
|
{
|
|
m_aWeakFrame->SetFrameInterface_Impl( nullptr );
|
|
m_aWeakFrame->DoClose();
|
|
}
|
|
}
|
|
|
|
void takeFrameOwnership( SfxFrame* i_pFrame )
|
|
{
|
|
OSL_PRECOND( !m_aWeakFrame, "ViewCreationGuard::takeFrameOwnership: already have a frame!" );
|
|
OSL_PRECOND( i_pFrame != nullptr, "ViewCreationGuard::takeFrameOwnership: invalid frame!" );
|
|
m_aWeakFrame = i_pFrame;
|
|
}
|
|
|
|
void releaseAll()
|
|
{
|
|
m_bSuccess = true;
|
|
}
|
|
|
|
private:
|
|
bool m_bSuccess;
|
|
SfxFrameWeakRef m_aWeakFrame;
|
|
};
|
|
}
|
|
|
|
|
|
SfxViewFrame* SfxBaseModel::FindOrCreateViewFrame_Impl( const Reference< XFrame >& i_rFrame, ::sfx::intern::ViewCreationGuard& i_rGuard ) const
|
|
{
|
|
SfxViewFrame* pViewFrame = nullptr;
|
|
for ( pViewFrame = SfxViewFrame::GetFirst( GetObjectShell(), false );
|
|
pViewFrame;
|
|
pViewFrame= SfxViewFrame::GetNext( *pViewFrame, GetObjectShell(), false )
|
|
)
|
|
{
|
|
if ( pViewFrame->GetFrame().GetFrameInterface() == i_rFrame )
|
|
break;
|
|
}
|
|
if ( !pViewFrame )
|
|
{
|
|
#if OSL_DEBUG_LEVEL > 0
|
|
for ( SfxFrame* pCheckFrame = SfxFrame::GetFirst();
|
|
pCheckFrame;
|
|
pCheckFrame = SfxFrame::GetNext( *pCheckFrame )
|
|
)
|
|
{
|
|
if ( pCheckFrame->GetFrameInterface() == i_rFrame )
|
|
{
|
|
if ( ( pCheckFrame->GetCurrentViewFrame() != nullptr )
|
|
|| ( pCheckFrame->GetCurrentDocument() != nullptr )
|
|
)
|
|
// Note that it is perfectly legitimate that during loading into an XFrame which already contains
|
|
// a document, there exist two SfxFrame instances bound to this XFrame - the old one, which will be
|
|
// destroyed later, and the new one, which we're going to create
|
|
continue;
|
|
|
|
OSL_FAIL( "SfxBaseModel::FindOrCreateViewFrame_Impl: there already is an SfxFrame for the given XFrame, but no view in it!" );
|
|
// nowadays, we're the only instance allowed to create an SfxFrame for an XFrame, so this case here should not happen
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
SfxFrame* pTargetFrame = SfxFrame::Create( i_rFrame );
|
|
ENSURE_OR_THROW( pTargetFrame, "could not create an SfxFrame" );
|
|
i_rGuard.takeFrameOwnership( pTargetFrame );
|
|
|
|
// prepare it
|
|
pTargetFrame->PrepareForDoc_Impl( *GetObjectShell() );
|
|
|
|
// create view frame
|
|
pViewFrame = new SfxViewFrame( *pTargetFrame, GetObjectShell() );
|
|
}
|
|
return pViewFrame;
|
|
}
|
|
|
|
|
|
// frame::XModel2
|
|
Reference< frame::XController2 > SAL_CALL SfxBaseModel::createViewController(
|
|
const OUString& i_rViewName, const Sequence< PropertyValue >& i_rArguments, const Reference< XFrame >& i_rFrame )
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
if ( !i_rFrame.is() )
|
|
throw lang::IllegalArgumentException( OUString(), *this, 3 );
|
|
|
|
// find the proper SFX view factory
|
|
SfxViewFactory* pViewFactory = GetObjectShell()->GetFactory().GetViewFactoryByViewName( i_rViewName );
|
|
if ( !pViewFactory )
|
|
throw IllegalArgumentException( OUString(), *this, 1 );
|
|
|
|
// determine previous shell (used in some special cases)
|
|
Reference< XController > xPreviousController( i_rFrame->getController() );
|
|
const Reference< XModel > xMe( this );
|
|
if ( ( xPreviousController.is() )
|
|
&& ( xMe != xPreviousController->getModel() )
|
|
)
|
|
{
|
|
xPreviousController.clear();
|
|
}
|
|
SfxViewShell* pOldViewShell = SfxViewShell::Get( xPreviousController );
|
|
OSL_ENSURE( !xPreviousController.is() || ( pOldViewShell != nullptr ),
|
|
"SfxBaseModel::createViewController: invalid old controller!" );
|
|
|
|
// a guard which will clean up in case of failure
|
|
::sfx::intern::ViewCreationGuard aViewCreationGuard;
|
|
|
|
// determine the ViewFrame belonging to the given XFrame
|
|
SfxViewFrame* pViewFrame = FindOrCreateViewFrame_Impl( i_rFrame, aViewCreationGuard );
|
|
assert(pViewFrame && "SfxBaseModel::createViewController: no frame");
|
|
|
|
// delegate to SFX' view factory
|
|
pViewFrame->GetBindings().ENTERREGISTRATIONS();
|
|
SfxViewShell* pViewShell = pViewFactory->CreateInstance(*pViewFrame, pOldViewShell);
|
|
pViewFrame->GetBindings().LEAVEREGISTRATIONS();
|
|
ENSURE_OR_THROW( pViewShell, "invalid view shell provided by factory" );
|
|
|
|
// by setting the ViewShell it is prevented that disposing the Controller will destroy this ViewFrame also
|
|
pViewFrame->GetDispatcher()->SetDisableFlags( SfxDisableFlags::NONE );
|
|
pViewFrame->SetViewShell_Impl( pViewShell );
|
|
|
|
// remember ViewID
|
|
pViewFrame->SetCurViewId_Impl( pViewFactory->GetOrdinal() );
|
|
|
|
// ensure a default controller, if the view shell did not provide an own implementation
|
|
if ( !pViewShell->GetController().is() )
|
|
pViewShell->SetController( new SfxBaseController( pViewShell ) );
|
|
|
|
// pass the creation arguments to the controller
|
|
SfxBaseController* pBaseController = pViewShell->GetBaseController_Impl();
|
|
ENSURE_OR_THROW( pBaseController, "invalid controller implementation!" );
|
|
pBaseController->SetCreationArguments_Impl( i_rArguments );
|
|
|
|
// some initial view settings, coming from our most recent attachResource call
|
|
::comphelper::NamedValueCollection aDocumentLoadArgs( getArgs2( { u"ViewOnly"_ustr, u"PluginMode"_ustr } ) );
|
|
if ( aDocumentLoadArgs.getOrDefault( u"ViewOnly"_ustr, false ) )
|
|
pViewFrame->GetFrame().SetMenuBarOn_Impl( false );
|
|
|
|
const sal_Int16 nPluginMode = aDocumentLoadArgs.getOrDefault( u"PluginMode"_ustr, sal_Int16( 0 ) );
|
|
if ( nPluginMode == 1 )
|
|
{
|
|
pViewFrame->ForceOuterResize_Impl();
|
|
pViewFrame->GetBindings().HidePopups();
|
|
|
|
SfxFrame& rFrame = pViewFrame->GetFrame();
|
|
// MBA: layoutmanager of inplace frame starts locked and invisible
|
|
rFrame.GetWorkWindow_Impl()->MakeVisible_Impl( false );
|
|
rFrame.GetWorkWindow_Impl()->Lock_Impl( true );
|
|
|
|
rFrame.GetWindow().SetBorderStyle( WindowBorderStyle::NOBORDER );
|
|
pViewFrame->GetWindow().SetBorderStyle( WindowBorderStyle::NOBORDER );
|
|
}
|
|
|
|
// tell the guard we were successful
|
|
aViewCreationGuard.releaseAll();
|
|
|
|
// outta here
|
|
return pBaseController;
|
|
}
|
|
|
|
|
|
// RDF DocumentMetadataAccess
|
|
|
|
// rdf::XRepositorySupplier:
|
|
Reference< rdf::XRepository > SAL_CALL
|
|
SfxBaseModel::getRDFRepository()
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
|
|
if (!xDMA.is()) {
|
|
throw RuntimeException( u"model has no document metadata"_ustr, *this );
|
|
}
|
|
|
|
return xDMA->getRDFRepository();
|
|
}
|
|
|
|
// rdf::XNode:
|
|
OUString SAL_CALL
|
|
SfxBaseModel::getStringValue()
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
|
|
if (!xDMA.is()) {
|
|
throw RuntimeException( u"model has no document metadata"_ustr, *this );
|
|
}
|
|
|
|
return xDMA->getStringValue();
|
|
}
|
|
|
|
// rdf::XURI:
|
|
OUString SAL_CALL
|
|
SfxBaseModel::getNamespace()
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
|
|
if (!xDMA.is()) {
|
|
throw RuntimeException( u"model has no document metadata"_ustr, *this );
|
|
}
|
|
|
|
return xDMA->getNamespace();
|
|
}
|
|
|
|
OUString SAL_CALL
|
|
SfxBaseModel::getLocalName()
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
|
|
if (!xDMA.is()) {
|
|
throw RuntimeException( u"model has no document metadata"_ustr, *this );
|
|
}
|
|
|
|
return xDMA->getLocalName();
|
|
}
|
|
|
|
// rdf::XDocumentMetadataAccess:
|
|
Reference< rdf::XMetadatable > SAL_CALL
|
|
SfxBaseModel::getElementByMetadataReference(
|
|
const beans::StringPair & i_rReference)
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
|
|
if (!xDMA.is()) {
|
|
throw RuntimeException( u"model has no document metadata"_ustr, *this );
|
|
}
|
|
|
|
return xDMA->getElementByMetadataReference(i_rReference);
|
|
}
|
|
|
|
Reference< rdf::XMetadatable > SAL_CALL
|
|
SfxBaseModel::getElementByURI(const Reference< rdf::XURI > & i_xURI)
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
|
|
if (!xDMA.is()) {
|
|
throw RuntimeException( u"model has no document metadata"_ustr, *this );
|
|
}
|
|
|
|
return xDMA->getElementByURI(i_xURI);
|
|
}
|
|
|
|
Sequence< Reference< rdf::XURI > > SAL_CALL
|
|
SfxBaseModel::getMetadataGraphsWithType(
|
|
const Reference<rdf::XURI> & i_xType)
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
|
|
if (!xDMA.is()) {
|
|
throw RuntimeException( u"model has no document metadata"_ustr, *this );
|
|
}
|
|
|
|
return xDMA->getMetadataGraphsWithType(i_xType);
|
|
}
|
|
|
|
Reference<rdf::XURI> SAL_CALL
|
|
SfxBaseModel::addMetadataFile(const OUString & i_rFileName,
|
|
const Sequence < Reference< rdf::XURI > > & i_rTypes)
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
|
|
if (!xDMA.is()) {
|
|
throw RuntimeException( u"model has no document metadata"_ustr, *this );
|
|
}
|
|
|
|
return xDMA->addMetadataFile(i_rFileName, i_rTypes);
|
|
}
|
|
|
|
Reference<rdf::XURI> SAL_CALL
|
|
SfxBaseModel::importMetadataFile(::sal_Int16 i_Format,
|
|
const Reference< io::XInputStream > & i_xInStream,
|
|
const OUString & i_rFileName,
|
|
const Reference< rdf::XURI > & i_xBaseURI,
|
|
const Sequence < Reference< rdf::XURI > > & i_rTypes)
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
|
|
if (!xDMA.is()) {
|
|
throw RuntimeException( u"model has no document metadata"_ustr, *this );
|
|
}
|
|
|
|
return xDMA->importMetadataFile(i_Format,
|
|
i_xInStream, i_rFileName, i_xBaseURI, i_rTypes);
|
|
}
|
|
|
|
void SAL_CALL
|
|
SfxBaseModel::removeMetadataFile(
|
|
const Reference< rdf::XURI > & i_xGraphName)
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
|
|
if (!xDMA.is()) {
|
|
throw RuntimeException( u"model has no document metadata"_ustr, *this );
|
|
}
|
|
|
|
return xDMA->removeMetadataFile(i_xGraphName);
|
|
}
|
|
|
|
void SAL_CALL
|
|
SfxBaseModel::addContentOrStylesFile(const OUString & i_rFileName)
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
|
|
if (!xDMA.is()) {
|
|
throw RuntimeException( u"model has no document metadata"_ustr, *this );
|
|
}
|
|
|
|
return xDMA->addContentOrStylesFile(i_rFileName);
|
|
}
|
|
|
|
void SAL_CALL
|
|
SfxBaseModel::removeContentOrStylesFile(const OUString & i_rFileName)
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
|
|
if (!xDMA.is()) {
|
|
throw RuntimeException( u"model has no document metadata"_ustr, *this );
|
|
}
|
|
|
|
return xDMA->removeContentOrStylesFile(i_rFileName);
|
|
}
|
|
|
|
void SAL_CALL
|
|
SfxBaseModel::loadMetadataFromStorage(
|
|
Reference< embed::XStorage > const & i_xStorage,
|
|
Reference<rdf::XURI> const & i_xBaseURI,
|
|
Reference<task::XInteractionHandler> const & i_xHandler)
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
rtl::Reference<::sfx2::DocumentMetadataAccess> xDMA(
|
|
m_pData->CreateDMAUninitialized());
|
|
if (!xDMA.is()) {
|
|
throw RuntimeException( u"model has no document metadata"_ustr, *this );
|
|
}
|
|
|
|
try {
|
|
xDMA->loadMetadataFromStorage(i_xStorage, i_xBaseURI, i_xHandler);
|
|
} catch (lang::IllegalArgumentException &) {
|
|
throw; // not initialized
|
|
} catch (Exception &) {
|
|
// UGLY: if it's a RuntimeException, we can't be sure DMA is initialized
|
|
m_pData->m_xDocumentMetadata = xDMA;
|
|
throw;
|
|
}
|
|
m_pData->m_xDocumentMetadata = std::move(xDMA);
|
|
}
|
|
|
|
void SAL_CALL
|
|
SfxBaseModel::storeMetadataToStorage(
|
|
Reference< embed::XStorage > const & i_xStorage)
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
|
|
if (!xDMA.is()) {
|
|
throw RuntimeException( u"model has no document metadata"_ustr, *this );
|
|
}
|
|
|
|
return xDMA->storeMetadataToStorage(i_xStorage);
|
|
}
|
|
|
|
void SAL_CALL
|
|
SfxBaseModel::loadMetadataFromMedium(
|
|
const Sequence< beans::PropertyValue > & i_rMedium)
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
rtl::Reference<::sfx2::DocumentMetadataAccess> xDMA(
|
|
m_pData->CreateDMAUninitialized());
|
|
if (!xDMA.is()) {
|
|
throw RuntimeException( u"model has no document metadata"_ustr, *this );
|
|
}
|
|
|
|
try {
|
|
xDMA->loadMetadataFromMedium(i_rMedium);
|
|
} catch (lang::IllegalArgumentException &) {
|
|
throw; // not initialized
|
|
} catch (Exception &) {
|
|
// UGLY: if it's a RuntimeException, we can't be sure DMA is initialized
|
|
m_pData->m_xDocumentMetadata = xDMA;
|
|
throw;
|
|
}
|
|
m_pData->m_xDocumentMetadata = std::move(xDMA);
|
|
}
|
|
|
|
void SAL_CALL
|
|
SfxBaseModel::storeMetadataToMedium(
|
|
const Sequence< beans::PropertyValue > & i_rMedium)
|
|
{
|
|
SfxModelGuard aGuard( *this );
|
|
|
|
const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
|
|
if (!xDMA.is()) {
|
|
throw RuntimeException( u"model has no document metadata"_ustr, *this );
|
|
}
|
|
|
|
return xDMA->storeMetadataToMedium(i_rMedium);
|
|
}
|
|
|
|
|
|
// = SfxModelSubComponent
|
|
|
|
|
|
SfxModelSubComponent::~SfxModelSubComponent()
|
|
{
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|