1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <commonembobj.hxx>
21 #include <com/sun/star/embed/Aspects.hpp>
22 #include <com/sun/star/document/XStorageBasedDocument.hpp>
23 #include <com/sun/star/embed/EmbedStates.hpp>
24 #include <com/sun/star/embed/EntryInitModes.hpp>
25 #include <com/sun/star/embed/StorageWrappedTargetException.hpp>
26 #include <com/sun/star/embed/WrongStateException.hpp>
27 #include <com/sun/star/embed/XStorage.hpp>
28 #include <com/sun/star/embed/XOptimizedStorage.hpp>
29 #include <com/sun/star/embed/ElementModes.hpp>
30 #include <com/sun/star/embed/EmbedUpdateModes.hpp>
31 #include <com/sun/star/embed/StorageFactory.hpp>
32 #include <com/sun/star/io/IOException.hpp>
33 #include <com/sun/star/io/TempFile.hpp>
34 #include <com/sun/star/frame/XModel.hpp>
35 #include <com/sun/star/frame/XStorable.hpp>
36 #include <com/sun/star/frame/XLoadable.hpp>
37 #include <com/sun/star/frame/XModule.hpp>
38 #include <com/sun/star/lang/NoSupportException.hpp>
39 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
40 #include <com/sun/star/lang/DisposedException.hpp>
41 #include <com/sun/star/util/XModifiable.hpp>
43 #include <com/sun/star/container/XNameAccess.hpp>
44 #include <com/sun/star/container/XChild.hpp>
45 #include <com/sun/star/util/XCloseable.hpp>
46 #include <com/sun/star/beans/XPropertySet.hpp>
47 #include <com/sun/star/beans/IllegalTypeException.hpp>
48 #include <com/sun/star/chart2/XChartDocument.hpp>
50 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
52 #include <comphelper/fileformat.h>
53 #include <comphelper/storagehelper.hxx>
54 #include <comphelper/mimeconfighelper.hxx>
55 #include <comphelper/namedvaluecollection.hxx>
56 #include <comphelper/propertyvalue.hxx>
57 #include <unotools/mediadescriptor.hxx>
59 #include <comphelper/diagnose_ex.hxx>
60 #include <sal/log.hxx>
61 #include <unotools/configmgr.hxx>
62 #include "persistence.hxx"
64 using namespace ::com::sun::star
;
67 uno::Sequence
< beans::PropertyValue
> GetValuableArgs_Impl( const uno::Sequence
< beans::PropertyValue
>& aMedDescr
,
68 bool bCanUseDocumentBaseURL
)
70 uno::Sequence
< beans::PropertyValue
> aResult
;
71 sal_Int32 nResLen
= 0;
73 for ( beans::PropertyValue
const & prop
: aMedDescr
)
75 if ( prop
.Name
== "ComponentData" || prop
.Name
== "DocumentTitle"
76 || prop
.Name
== "InteractionHandler" || prop
.Name
== "JumpMark"
77 // || prop.Name == "Password" // makes no sense for embedded objects
78 || prop
.Name
== "Preview" || prop
.Name
== "ReadOnly"
79 || prop
.Name
== "StartPresentation" || prop
.Name
== "RepairPackage"
80 || prop
.Name
== "StatusIndicator" || prop
.Name
== "ViewData"
81 || prop
.Name
== "ViewId" || prop
.Name
== "MacroExecutionMode"
82 || prop
.Name
== "UpdateDocMode"
83 || (prop
.Name
== "DocumentBaseURL" && bCanUseDocumentBaseURL
) )
85 aResult
.realloc( ++nResLen
);
86 aResult
.getArray()[nResLen
-1] = prop
;
94 static uno::Sequence
< beans::PropertyValue
> addAsTemplate( const uno::Sequence
< beans::PropertyValue
>& aOrig
)
96 bool bAsTemplateSet
= false;
97 sal_Int32 nLength
= aOrig
.getLength();
98 uno::Sequence
< beans::PropertyValue
> aResult( aOrig
);
100 for ( sal_Int32 nInd
= 0; nInd
< nLength
; nInd
++ )
102 if ( aResult
[nInd
].Name
== "AsTemplate" )
104 aResult
.getArray()[nInd
].Value
<<= true;
105 bAsTemplateSet
= true;
109 if ( !bAsTemplateSet
)
111 aResult
.realloc( nLength
+ 1 );
112 auto pResult
= aResult
.getArray();
113 pResult
[nLength
].Name
= "AsTemplate";
114 pResult
[nLength
].Value
<<= true;
121 static uno::Reference
< io::XInputStream
> createTempInpStreamFromStor(
122 const uno::Reference
< embed::XStorage
>& xStorage
,
123 const uno::Reference
< uno::XComponentContext
>& xContext
)
125 SAL_WARN_IF( !xStorage
.is(), "embeddedobj.common", "The storage can not be empty!" );
127 uno::Reference
< io::XInputStream
> xResult
;
129 uno::Reference
< io::XStream
> xTempStream( io::TempFile::create(xContext
), uno::UNO_QUERY_THROW
);
131 uno::Reference
< lang::XSingleServiceFactory
> xStorageFactory( embed::StorageFactory::create(xContext
) );
133 uno::Sequence
< uno::Any
> aArgs
{ uno::Any(xTempStream
),
134 uno::Any(embed::ElementModes::READWRITE
) };
135 uno::Reference
< embed::XStorage
> xTempStorage( xStorageFactory
->createInstanceWithArguments( aArgs
),
136 uno::UNO_QUERY_THROW
);
140 xStorage
->copyToStorage( xTempStorage
);
141 } catch( const uno::Exception
& )
143 css::uno::Any anyEx
= cppu::getCaughtException();
144 throw embed::StorageWrappedTargetException(
145 "Can't copy storage!",
146 uno::Reference
< uno::XInterface
>(),
151 if ( xTempStorage
.is() )
152 xTempStorage
->dispose();
154 catch ( const uno::Exception
& )
159 uno::Reference
< io::XOutputStream
> xTempOut
= xTempStream
->getOutputStream();
161 xTempOut
->closeOutput();
163 catch ( const uno::Exception
& )
167 xResult
= xTempStream
->getInputStream();
174 static void TransferMediaType( const uno::Reference
< embed::XStorage
>& i_rSource
, const uno::Reference
< embed::XStorage
>& i_rTarget
)
178 const uno::Reference
< beans::XPropertySet
> xSourceProps( i_rSource
, uno::UNO_QUERY_THROW
);
179 const uno::Reference
< beans::XPropertySet
> xTargetProps( i_rTarget
, uno::UNO_QUERY_THROW
);
180 static const OUStringLiteral
sMediaTypePropName( u
"MediaType" );
181 xTargetProps
->setPropertyValue( sMediaTypePropName
, xSourceProps
->getPropertyValue( sMediaTypePropName
) );
183 catch( const uno::Exception
& )
185 DBG_UNHANDLED_EXCEPTION("embeddedobj.common");
190 static uno::Reference
< util::XCloseable
> CreateDocument( const uno::Reference
< uno::XComponentContext
>& _rxContext
,
191 const OUString
& _rDocumentServiceName
, bool _bEmbeddedScriptSupport
, const bool i_bDocumentRecoverySupport
)
193 static constexpr OUStringLiteral sEmbeddedObject
= u
"EmbeddedObject";
194 static constexpr OUStringLiteral sEmbeddedScriptSupport
= u
"EmbeddedScriptSupport";
195 static constexpr OUStringLiteral sDocumentRecoverySupport
= u
"DocumentRecoverySupport";
196 ::comphelper::NamedValueCollection aArguments
;
197 aArguments
.put( sEmbeddedObject
, true );
198 aArguments
.put( sEmbeddedScriptSupport
, _bEmbeddedScriptSupport
);
199 aArguments
.put( sDocumentRecoverySupport
, i_bDocumentRecoverySupport
);
201 uno::Reference
< uno::XInterface
> xDocument
;
204 xDocument
= _rxContext
->getServiceManager()->createInstanceWithArgumentsAndContext(
205 _rDocumentServiceName
, aArguments
.getWrappedPropertyValues(), _rxContext
);
207 catch( const uno::Exception
& )
209 // if an embedded object implementation does not support XInitialization,
210 // the default factory from cppuhelper will throw an
211 // IllegalArgumentException when we try to create the instance with arguments.
212 // Okay, so we fall back to creating the instance without any arguments.
213 OSL_FAIL("Consider implementing interface XInitialization to avoid duplicate construction");
214 xDocument
= _rxContext
->getServiceManager()->createInstanceWithContext( _rDocumentServiceName
, _rxContext
);
217 SAL_WARN_IF(!xDocument
.is(), "embeddedobj.common", "Service " << _rDocumentServiceName
<< " is not available?");
218 return uno::Reference
< util::XCloseable
>( xDocument
, uno::UNO_QUERY
);
222 static void SetDocToEmbedded( const uno::Reference
< frame::XModel
>& rDocument
, const OUString
& aModuleName
)
227 uno::Sequence
< beans::PropertyValue
> aSeq
{ comphelper::makePropertyValue("SetEmbedded", true) };
228 rDocument
->attachResource( OUString(), aSeq
);
230 if ( !aModuleName
.isEmpty() )
234 uno::Reference
< frame::XModule
> xModule( rDocument
, uno::UNO_QUERY_THROW
);
235 xModule
->setIdentifier( aModuleName
);
237 catch( const uno::Exception
& )
243 void OCommonEmbeddedObject::SwitchOwnPersistence( const uno::Reference
< embed::XStorage
>& xNewParentStorage
,
244 const uno::Reference
< embed::XStorage
>& xNewObjectStorage
,
245 const OUString
& aNewName
)
247 if ( xNewParentStorage
== m_xParentStorage
&& aNewName
== m_aEntryName
)
249 SAL_WARN_IF( xNewObjectStorage
!= m_xObjectStorage
, "embeddedobj.common", "The storage must be the same!" );
253 auto xOldObjectStorage
= m_xObjectStorage
;
254 m_xObjectStorage
= xNewObjectStorage
;
255 m_xParentStorage
= xNewParentStorage
;
256 m_aEntryName
= aNewName
;
258 // the linked document should not be switched
261 uno::Reference
< document::XStorageBasedDocument
> xDoc( m_xDocHolder
->GetComponent(), uno::UNO_QUERY
);
263 SwitchDocToStorage_Impl( xDoc
, m_xObjectStorage
);
267 if ( xOldObjectStorage
.is() )
268 xOldObjectStorage
->dispose();
270 catch ( const uno::Exception
& )
276 void OCommonEmbeddedObject::SwitchOwnPersistence( const uno::Reference
< embed::XStorage
>& xNewParentStorage
,
277 const OUString
& aNewName
)
279 if ( xNewParentStorage
== m_xParentStorage
&& aNewName
== m_aEntryName
)
282 sal_Int32 nStorageMode
= m_bReadOnly
? embed::ElementModes::READ
: embed::ElementModes::READWRITE
;
284 uno::Reference
< embed::XStorage
> xNewOwnStorage
= xNewParentStorage
->openStorageElement( aNewName
, nStorageMode
);
285 SAL_WARN_IF( !xNewOwnStorage
.is(), "embeddedobj.common", "The method can not return empty reference!" );
287 SwitchOwnPersistence( xNewParentStorage
, xNewOwnStorage
, aNewName
);
291 void OCommonEmbeddedObject::EmbedAndReparentDoc_Impl( const uno::Reference
< util::XCloseable
>& i_rxDocument
) const
293 SetDocToEmbedded( uno::Reference
< frame::XModel
>( i_rxDocument
, uno::UNO_QUERY
), m_aModuleName
);
297 uno::Reference
< container::XChild
> xChild( i_rxDocument
, uno::UNO_QUERY
);
299 xChild
->setParent( m_xParent
);
301 catch( const lang::NoSupportException
& )
303 SAL_WARN( "embeddedobj.common", "OCommonEmbeddedObject::EmbedAndReparentDoc: cannot set parent at document!" );
308 uno::Reference
< util::XCloseable
> OCommonEmbeddedObject::InitNewDocument_Impl()
310 uno::Reference
< util::XCloseable
> xDocument( CreateDocument( m_xContext
, GetDocumentServiceName(),
311 m_bEmbeddedScriptSupport
, m_bDocumentRecoverySupport
) );
313 uno::Reference
< frame::XModel
> xModel( xDocument
, uno::UNO_QUERY
);
314 uno::Reference
< frame::XLoadable
> xLoadable( xModel
, uno::UNO_QUERY_THROW
);
318 // set the document mode to embedded as the first action on document!!!
319 EmbedAndReparentDoc_Impl( xDocument
);
321 // if we have a storage to recover the document from, do not use initNew, but instead load from that storage
322 bool bInitNew
= true;
323 if ( m_xRecoveryStorage
.is() )
325 uno::Reference
< document::XStorageBasedDocument
> xDoc( xLoadable
, uno::UNO_QUERY
);
326 SAL_WARN_IF( !xDoc
.is(), "embeddedobj.common", "OCommonEmbeddedObject::InitNewDocument_Impl: cannot recover from a storage when the document is not storage based!" );
329 ::comphelper::NamedValueCollection aLoadArgs
;
330 FillDefaultLoadArgs_Impl( m_xRecoveryStorage
, aLoadArgs
);
332 xDoc
->loadFromStorage( m_xRecoveryStorage
, aLoadArgs
.getPropertyValues() );
333 SwitchDocToStorage_Impl( xDoc
, m_xObjectStorage
);
340 // init document as a new
341 xLoadable
->initNew();
343 xModel
->attachResource( xModel
->getURL(), m_aDocMediaDescriptor
);
345 catch( const uno::Exception
& )
347 if ( xDocument
.is() )
351 xDocument
->close( true );
353 catch( const uno::Exception
& )
365 uno::Reference
< util::XCloseable
> OCommonEmbeddedObject::LoadLink_Impl()
367 uno::Reference
< util::XCloseable
> xDocument( CreateDocument( m_xContext
, GetDocumentServiceName(),
368 m_bEmbeddedScriptSupport
, m_bDocumentRecoverySupport
) );
370 uno::Reference
< frame::XLoadable
> xLoadable( xDocument
, uno::UNO_QUERY_THROW
);
372 sal_Int32 nLen
= m_bLinkHasPassword
? 3 : 2;
373 uno::Sequence
< beans::PropertyValue
> aArgs( m_aDocMediaDescriptor
.getLength() + nLen
);
374 auto pArgs
= aArgs
.getArray();
376 pArgs
[0].Name
= "URL";
377 if(m_aLinkTempFile
.is())
378 pArgs
[0].Value
<<= m_aLinkTempFile
->getUri();
380 pArgs
[0].Value
<<= m_aLinkURL
;
382 pArgs
[1].Name
= "FilterName";
383 pArgs
[1].Value
<<= m_aLinkFilterName
;
385 if ( m_bLinkHasPassword
)
387 pArgs
[2].Name
= "Password";
388 pArgs
[2].Value
<<= m_aLinkPassword
;
391 for ( sal_Int32 nInd
= 0; nInd
< m_aDocMediaDescriptor
.getLength(); nInd
++ )
393 pArgs
[nInd
+nLen
].Name
= m_aDocMediaDescriptor
[nInd
].Name
;
394 pArgs
[nInd
+nLen
].Value
= m_aDocMediaDescriptor
[nInd
].Value
;
399 handleLinkedOLE(CopyBackToOLELink::CopyLinkToTemp
);
401 // the document is not really an embedded one, it is a link
402 EmbedAndReparentDoc_Impl( xDocument
);
405 xLoadable
->load( aArgs
);
407 if ( !m_bLinkHasPassword
)
409 // check if there is a password to cache
410 uno::Reference
< frame::XModel
> xModel( xLoadable
, uno::UNO_QUERY_THROW
);
411 const uno::Sequence
< beans::PropertyValue
> aProps
= xModel
->getArgs();
412 for ( beans::PropertyValue
const & prop
: aProps
)
413 if ( prop
.Name
== "Password" && ( prop
.Value
>>= m_aLinkPassword
) )
415 m_bLinkHasPassword
= true;
420 catch( const uno::Exception
& )
422 if ( xDocument
.is() )
426 xDocument
->close( true );
428 catch( const uno::Exception
& )
441 OUString
OCommonEmbeddedObject::GetFilterName( sal_Int32 nVersion
) const
443 OUString aFilterName
= GetPresetFilterName();
444 if ( aFilterName
.isEmpty() )
446 OUString sDocumentServiceName
= GetDocumentServiceName();
447 if (utl::ConfigManager::IsFuzzing() && nVersion
== SOFFICE_FILEFORMAT_CURRENT
&&
448 sDocumentServiceName
== "com.sun.star.chart2.ChartDocument")
453 ::comphelper::MimeConfigurationHelper
aHelper( m_xContext
);
454 aFilterName
= aHelper
.GetDefaultFilterFromServiceName(sDocumentServiceName
, nVersion
);
456 // If no filter is found, fall back to the FileFormatVersion=6200 filter, Base only has that.
457 if (aFilterName
.isEmpty() && nVersion
== SOFFICE_FILEFORMAT_CURRENT
)
458 aFilterName
= aHelper
.GetDefaultFilterFromServiceName(GetDocumentServiceName(), SOFFICE_FILEFORMAT_60
);
459 } catch( const uno::Exception
& )
467 void OCommonEmbeddedObject::FillDefaultLoadArgs_Impl( const uno::Reference
< embed::XStorage
>& i_rxStorage
,
468 ::comphelper::NamedValueCollection
& o_rLoadArgs
) const
470 o_rLoadArgs
.put( "DocumentBaseURL", GetBaseURL_Impl() );
471 o_rLoadArgs
.put( "HierarchicalDocumentName", m_aEntryName
);
472 o_rLoadArgs
.put( "ReadOnly", m_bReadOnly
);
474 OUString aFilterName
= GetFilterName( ::comphelper::OStorageHelper::GetXStorageFormat( i_rxStorage
) );
475 SAL_WARN_IF( aFilterName
.isEmpty(), "embeddedobj.common", "OCommonEmbeddedObject::FillDefaultLoadArgs_Impl: Wrong document service name!" );
476 if ( aFilterName
.isEmpty() )
477 throw io::IOException(); // TODO: error message/code
479 o_rLoadArgs
.put( "FilterName", aFilterName
);
483 uno::Reference
< util::XCloseable
> OCommonEmbeddedObject::LoadDocumentFromStorage_Impl()
485 ENSURE_OR_THROW( m_xObjectStorage
.is(), "no object storage" );
487 const uno::Reference
< embed::XStorage
> xSourceStorage( m_xRecoveryStorage
.is() ? m_xRecoveryStorage
: m_xObjectStorage
);
489 uno::Reference
< util::XCloseable
> xDocument( CreateDocument( m_xContext
, GetDocumentServiceName(),
490 m_bEmbeddedScriptSupport
, m_bDocumentRecoverySupport
) );
492 //#i103460# ODF: take the size given from the parent frame as default
493 uno::Reference
< chart2::XChartDocument
> xChart( xDocument
, uno::UNO_QUERY
);
496 uno::Reference
< embed::XVisualObject
> xChartVisualObject( xChart
, uno::UNO_QUERY
);
497 if( xChartVisualObject
.is() )
498 xChartVisualObject
->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT
, m_aDefaultSizeForChart_In_100TH_MM
);
501 uno::Reference
< frame::XLoadable
> xLoadable( xDocument
, uno::UNO_QUERY
);
502 uno::Reference
< document::XStorageBasedDocument
> xDoc( xDocument
, uno::UNO_QUERY
);
503 if ( !xDoc
.is() && !xLoadable
.is() )
504 throw uno::RuntimeException();
506 ::comphelper::NamedValueCollection aLoadArgs
;
507 FillDefaultLoadArgs_Impl( xSourceStorage
, aLoadArgs
);
509 uno::Reference
< io::XInputStream
> xTempInpStream
;
512 xTempInpStream
= createTempInpStreamFromStor( xSourceStorage
, m_xContext
);
513 if ( !xTempInpStream
.is() )
514 throw uno::RuntimeException();
516 OUString aTempFileURL
;
519 // no need to let the file stay after the stream is removed since the embedded document
520 // can not be stored directly
521 uno::Reference
< beans::XPropertySet
> xTempStreamProps( xTempInpStream
, uno::UNO_QUERY_THROW
);
522 xTempStreamProps
->getPropertyValue("Uri") >>= aTempFileURL
;
524 catch( const uno::Exception
& )
528 SAL_WARN_IF( aTempFileURL
.isEmpty(), "embeddedobj.common", "Couldn't retrieve temporary file URL!" );
530 aLoadArgs
.put( "URL", aTempFileURL
);
531 aLoadArgs
.put( "InputStream", xTempInpStream
);
535 aLoadArgs
.merge( m_aDocMediaDescriptor
, true );
539 // set the document mode to embedded as the first step!!!
540 EmbedAndReparentDoc_Impl( xDocument
);
544 aLoadArgs
.put("ReadOnly", true);
549 xDoc
->loadFromStorage( xSourceStorage
, aLoadArgs
.getPropertyValues() );
550 if ( xSourceStorage
!= m_xObjectStorage
)
551 SwitchDocToStorage_Impl( xDoc
, m_xObjectStorage
);
554 xLoadable
->load( aLoadArgs
.getPropertyValues() );
556 catch( const uno::Exception
& )
558 if ( xDocument
.is() )
562 xDocument
->close( true );
564 catch( const uno::Exception
& )
566 DBG_UNHANDLED_EXCEPTION("embeddedobj.common");
577 uno::Reference
< io::XInputStream
> OCommonEmbeddedObject::StoreDocumentToTempStream_Impl(
578 sal_Int32 nStorageFormat
,
579 const OUString
& aBaseURL
,
580 const OUString
& aHierarchName
)
582 uno::Reference
< io::XOutputStream
> xTempOut(
583 io::TempFile::create(m_xContext
),
584 uno::UNO_QUERY_THROW
);
585 uno::Reference
< io::XInputStream
> aResult( xTempOut
, uno::UNO_QUERY_THROW
);
587 uno::Reference
< frame::XStorable
> xStorable
;
589 osl::MutexGuard
aGuard( m_aMutex
);
590 if ( m_xDocHolder
.is() )
591 xStorable
.set( m_xDocHolder
->GetComponent(), uno::UNO_QUERY
);
594 if( !xStorable
.is() )
595 throw uno::RuntimeException("No storage is provided for storing!"); // TODO:
597 OUString aFilterName
= GetFilterName( nStorageFormat
);
599 SAL_WARN_IF( aFilterName
.isEmpty(), "embeddedobj.common", "Wrong document service name!" );
600 if ( aFilterName
.isEmpty() )
601 throw io::IOException("No filter name provided / Wrong document service name"); // TODO:
603 uno::Sequence
< beans::PropertyValue
> aArgs
{
604 comphelper::makePropertyValue("FilterName", aFilterName
),
605 comphelper::makePropertyValue("OutputStream", xTempOut
),
606 comphelper::makePropertyValue("DocumentBaseURL", aBaseURL
),
607 comphelper::makePropertyValue("HierarchicalDocumentName", aHierarchName
)
610 xStorable
->storeToURL( "private:stream", aArgs
);
613 xTempOut
->closeOutput();
615 catch( const uno::Exception
& )
617 SAL_WARN( "embeddedobj.common", "Looks like stream was closed already" );
624 void OCommonEmbeddedObject::SaveObject_Impl()
626 if ( !m_xClientSite
.is() )
631 // check whether the component is modified,
632 // if not there is no need for storing
633 uno::Reference
< util::XModifiable
> xModifiable( m_xDocHolder
->GetComponent(), uno::UNO_QUERY
);
634 if ( xModifiable
.is() && !xModifiable
->isModified() )
637 catch( const uno::Exception
& )
641 m_xClientSite
->saveObject();
643 catch( const uno::Exception
& )
645 SAL_WARN( "embeddedobj.common", "The object was not stored!" );
650 OUString
OCommonEmbeddedObject::GetBaseURL_Impl() const
654 if ( m_xClientSite
.is() )
658 uno::Reference
< frame::XModel
> xParentModel( m_xClientSite
->getComponent(), uno::UNO_QUERY_THROW
);
659 const uno::Sequence
< beans::PropertyValue
> aModelProps
= xParentModel
->getArgs();
660 for ( beans::PropertyValue
const & prop
: aModelProps
)
661 if ( prop
.Name
== "DocumentBaseURL" )
663 prop
.Value
>>= aBaseURL
;
667 catch( const uno::Exception
& )
671 if ( aBaseURL
.isEmpty() )
673 for ( beans::PropertyValue
const & prop
: m_aDocMediaDescriptor
)
674 if ( prop
.Name
== "DocumentBaseURL" )
676 prop
.Value
>>= aBaseURL
;
681 if ( aBaseURL
.isEmpty() )
682 aBaseURL
= m_aDefaultParentBaseURL
;
688 OUString
OCommonEmbeddedObject::GetBaseURLFrom_Impl(
689 const uno::Sequence
< beans::PropertyValue
>& lArguments
,
690 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
694 for ( beans::PropertyValue
const & prop
: lArguments
)
695 if ( prop
.Name
== "DocumentBaseURL" )
697 prop
.Value
>>= aBaseURL
;
701 if ( aBaseURL
.isEmpty() )
703 for ( beans::PropertyValue
const & prop
: lObjArgs
)
704 if ( prop
.Name
== "DefaultParentBaseURL" )
706 prop
.Value
>>= aBaseURL
;
715 void OCommonEmbeddedObject::SwitchDocToStorage_Impl( const uno::Reference
< document::XStorageBasedDocument
>& xDoc
, const uno::Reference
< embed::XStorage
>& xStorage
)
717 xDoc
->switchToStorage( xStorage
);
719 uno::Reference
< util::XModifiable
> xModif( xDoc
, uno::UNO_QUERY
);
721 xModif
->setModified( false );
723 if ( m_xRecoveryStorage
.is() )
724 m_xRecoveryStorage
.clear();
729 OUString
getStringPropertyValue( const uno::Sequence
<beans::PropertyValue
>& rProps
, std::u16string_view rName
)
733 for (beans::PropertyValue
const & prop
: rProps
)
735 if (prop
.Name
== rName
)
747 void OCommonEmbeddedObject::StoreDocToStorage_Impl(
748 const uno::Reference
<embed::XStorage
>& xStorage
,
749 const uno::Sequence
<beans::PropertyValue
>& rMediaArgs
,
750 const uno::Sequence
<beans::PropertyValue
>& rObjArgs
,
751 sal_Int32 nStorageFormat
,
752 const OUString
& aHierarchName
,
753 bool bAttachToTheStorage
)
755 SAL_WARN_IF( !xStorage
.is(), "embeddedobj.common", "No storage is provided for storing!" );
757 if ( !xStorage
.is() )
758 throw uno::RuntimeException(); // TODO:
760 uno::Reference
< document::XStorageBasedDocument
> xDoc
;
762 osl::MutexGuard
aGuard( m_aMutex
);
763 if ( m_xDocHolder
.is() )
764 xDoc
.set( m_xDocHolder
->GetComponent(), uno::UNO_QUERY
);
767 OUString aBaseURL
= GetBaseURLFrom_Impl(rMediaArgs
, rObjArgs
);
771 OUString aFilterName
= GetFilterName( nStorageFormat
);
773 // No filter found? Try the older format, e.g. Base has only that.
774 if (aFilterName
.isEmpty() && nStorageFormat
== SOFFICE_FILEFORMAT_CURRENT
)
775 aFilterName
= GetFilterName( SOFFICE_FILEFORMAT_60
);
777 SAL_WARN_IF( aFilterName
.isEmpty(), "embeddedobj.common", "Wrong document service name!" );
778 if ( aFilterName
.isEmpty() )
779 throw io::IOException(); // TODO:
781 static constexpr OUStringLiteral sFilterName
= u
"FilterName";
782 static constexpr OUStringLiteral sHierarchicalDocumentName
= u
"HierarchicalDocumentName";
783 static constexpr OUStringLiteral sDocumentBaseURL
= u
"DocumentBaseURL";
784 static constexpr OUStringLiteral sSourceShellID
= u
"SourceShellID";
785 static constexpr OUStringLiteral sDestinationShellID
= u
"DestinationShellID";
786 uno::Sequence
<beans::PropertyValue
> aArgs
{
787 comphelper::makePropertyValue(sFilterName
, aFilterName
),
788 comphelper::makePropertyValue(sHierarchicalDocumentName
, aHierarchName
),
789 comphelper::makePropertyValue(sDocumentBaseURL
, aBaseURL
),
790 comphelper::makePropertyValue(sSourceShellID
,
791 getStringPropertyValue(rObjArgs
, sSourceShellID
)),
792 comphelper::makePropertyValue(
793 sDestinationShellID
, getStringPropertyValue(rObjArgs
, sDestinationShellID
))
796 xDoc
->storeToStorage( xStorage
, aArgs
);
797 if ( bAttachToTheStorage
)
798 SwitchDocToStorage_Impl( xDoc
, xStorage
);
802 // store document to temporary stream based on temporary file
803 uno::Reference
< io::XInputStream
> xTempIn
= StoreDocumentToTempStream_Impl( nStorageFormat
, aBaseURL
, aHierarchName
);
805 SAL_WARN_IF( !xTempIn
.is(), "embeddedobj.common", "The stream reference can not be empty!" );
807 // open storage based on document temporary file for reading
808 uno::Reference
< lang::XSingleServiceFactory
> xStorageFactory
= embed::StorageFactory::create(m_xContext
);
810 uno::Sequence
< uno::Any
> aArgs
{ uno::Any(xTempIn
) };
811 uno::Reference
< embed::XStorage
> xTempStorage( xStorageFactory
->createInstanceWithArguments( aArgs
),
812 uno::UNO_QUERY_THROW
);
814 // object storage must be committed automatically
815 xTempStorage
->copyToStorage( xStorage
);
820 uno::Reference
< util::XCloseable
> OCommonEmbeddedObject::CreateDocFromMediaDescr_Impl(
821 const uno::Sequence
< beans::PropertyValue
>& aMedDescr
)
823 uno::Reference
< util::XCloseable
> xDocument( CreateDocument( m_xContext
, GetDocumentServiceName(),
824 m_bEmbeddedScriptSupport
, m_bDocumentRecoverySupport
) );
826 uno::Reference
< frame::XLoadable
> xLoadable( xDocument
, uno::UNO_QUERY_THROW
);
830 // set the document mode to embedded as the first action on the document!!!
831 EmbedAndReparentDoc_Impl( xDocument
);
833 xLoadable
->load( addAsTemplate( aMedDescr
) );
835 catch( const uno::Exception
& )
837 if ( xDocument
.is() )
841 xDocument
->close( true );
843 catch( const uno::Exception
& )
855 uno::Reference
< util::XCloseable
> OCommonEmbeddedObject::CreateTempDocFromLink_Impl()
857 uno::Reference
< util::XCloseable
> xResult
;
859 SAL_WARN_IF( !m_bIsLinkURL
, "embeddedobj.common", "The object is not a linked one!" );
861 uno::Sequence
< beans::PropertyValue
> aTempMediaDescr
;
863 sal_Int32 nStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
865 nStorageFormat
= ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage
);
867 catch ( const beans::IllegalTypeException
& )
869 // the container just has an unknown type, use current file format
871 catch ( const uno::Exception
& )
873 SAL_WARN( "embeddedobj.common", "Can not retrieve storage media type!" );
876 if ( m_xDocHolder
->GetComponent().is() )
878 aTempMediaDescr
.realloc( 4 );
880 // TODO/LATER: may be private:stream should be used as target URL
881 OUString aTempFileURL
;
882 uno::Reference
< io::XInputStream
> xTempStream
= StoreDocumentToTempStream_Impl( SOFFICE_FILEFORMAT_CURRENT
,
887 // no need to let the file stay after the stream is removed since the embedded document
888 // can not be stored directly
889 uno::Reference
< beans::XPropertySet
> xTempStreamProps( xTempStream
, uno::UNO_QUERY_THROW
);
890 xTempStreamProps
->getPropertyValue("Uri") >>= aTempFileURL
;
892 catch( const uno::Exception
& )
896 SAL_WARN_IF( aTempFileURL
.isEmpty(), "embeddedobj.common", "Couldn't retrieve temporary file URL!" );
899 = { comphelper::makePropertyValue("URL", aTempFileURL
),
900 comphelper::makePropertyValue("InputStream", xTempStream
),
901 comphelper::makePropertyValue("FilterName", GetFilterName( nStorageFormat
)),
902 comphelper::makePropertyValue("AsTemplate", true) };
906 aTempMediaDescr
= { comphelper::makePropertyValue(
908 // tdf#141529 use URL of the linked TempFile if it exists
909 m_aLinkTempFile
.is() ? m_aLinkTempFile
->getUri() : m_aLinkURL
),
910 comphelper::makePropertyValue("FilterName", m_aLinkFilterName
) };
913 xResult
= CreateDocFromMediaDescr_Impl( aTempMediaDescr
);
919 void SAL_CALL
OCommonEmbeddedObject::setPersistentEntry(
920 const uno::Reference
< embed::XStorage
>& xStorage
,
921 const OUString
& sEntName
,
922 sal_Int32 nEntryConnectionMode
,
923 const uno::Sequence
< beans::PropertyValue
>& lArguments
,
924 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
926 // the type of the object must be already set
927 // a kind of typedetection should be done in the factory
929 ::osl::MutexGuard
aGuard( m_aMutex
);
931 throw lang::DisposedException(); // TODO
933 if ( !xStorage
.is() )
934 throw lang::IllegalArgumentException( "No parent storage is provided!",
935 static_cast< ::cppu::OWeakObject
* >(this),
938 if ( sEntName
.isEmpty() )
939 throw lang::IllegalArgumentException( "Empty element name is provided!",
940 static_cast< ::cppu::OWeakObject
* >(this),
943 // May be LOADED should be forbidden here ???
944 if ( ( m_nObjectState
!= -1 || nEntryConnectionMode
== embed::EntryInitModes::NO_INIT
)
945 && ( m_nObjectState
== -1 || nEntryConnectionMode
!= embed::EntryInitModes::NO_INIT
) )
947 // if the object is not loaded
948 // it can not get persistent representation without initialization
950 // if the object is loaded
951 // it can switch persistent representation only without initialization
953 throw embed::WrongStateException(
954 "Can't change persistent representation of activated object!",
955 static_cast< ::cppu::OWeakObject
* >(this) );
958 if ( m_bWaitSaveCompleted
)
960 if ( nEntryConnectionMode
!= embed::EntryInitModes::NO_INIT
)
961 throw embed::WrongStateException(
962 "The object waits for saveCompleted() call!",
963 static_cast< ::cppu::OWeakObject
* >(this) );
964 // saveCompleted is expected, handle it accordingly
965 if ( m_xNewParentStorage
== xStorage
&& m_aNewEntryName
== sEntName
)
967 saveCompleted( true );
971 // if a completely different entry is provided, switch first back to the old persistence in saveCompleted
972 // and then switch to the target persistence
973 bool bSwitchFurther
= ( m_xParentStorage
!= xStorage
|| m_aEntryName
!= sEntName
);
974 saveCompleted( false );
975 if ( !bSwitchFurther
)
979 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
980 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
981 // OSL_ENSURE( !m_bIsLinkURL, "This method implementation must not be used for links!" );
984 m_aEntryName
= sEntName
;
988 uno::Reference
< container::XNameAccess
> xNameAccess( xStorage
, uno::UNO_QUERY_THROW
);
990 // detect entry existence
991 bool bElExists
= xNameAccess
->hasByName( sEntName
);
993 m_aDocMediaDescriptor
= GetValuableArgs_Impl( lArguments
,
994 nEntryConnectionMode
!= embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT
);
997 for ( beans::PropertyValue
const & prop
: lArguments
)
998 if ( prop
.Name
== "ReadOnly" )
999 prop
.Value
>>= m_bReadOnly
;
1001 // TODO: use lObjArgs for StoreVisualReplacement
1002 for ( beans::PropertyValue
const & prop
: lObjArgs
)
1003 if ( prop
.Name
== "OutplaceDispatchInterceptor" )
1005 uno::Reference
< frame::XDispatchProviderInterceptor
> xDispatchInterceptor
;
1006 if ( prop
.Value
>>= xDispatchInterceptor
)
1007 m_xDocHolder
->SetOutplaceDispatchInterceptor( xDispatchInterceptor
);
1009 else if ( prop
.Name
== "DefaultParentBaseURL" )
1011 prop
.Value
>>= m_aDefaultParentBaseURL
;
1013 else if ( prop
.Name
== "Parent" )
1015 prop
.Value
>>= m_xParent
;
1017 else if ( prop
.Name
== "IndividualMiscStatus" )
1019 sal_Int64 nMiscStatus
=0;
1020 prop
.Value
>>= nMiscStatus
;
1021 m_nMiscStatus
|= nMiscStatus
;
1023 else if ( prop
.Name
== "CloneFrom" )
1025 uno::Reference
< embed::XEmbeddedObject
> xObj
;
1026 prop
.Value
>>= xObj
;
1029 m_bHasClonedSize
= true;
1030 m_aClonedSize
= xObj
->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT
);
1031 m_nClonedMapUnit
= xObj
->getMapUnit( embed::Aspects::MSOLE_CONTENT
);
1034 else if ( prop
.Name
== "OutplaceFrameProperties" )
1036 uno::Sequence
< uno::Any
> aOutFrameProps
;
1037 uno::Sequence
< beans::NamedValue
> aOutFramePropsTyped
;
1038 if ( prop
.Value
>>= aOutFrameProps
)
1040 m_xDocHolder
->SetOutplaceFrameProperties( aOutFrameProps
);
1042 else if ( prop
.Value
>>= aOutFramePropsTyped
)
1044 aOutFrameProps
.realloc( aOutFramePropsTyped
.getLength() );
1045 uno::Any
* pProp
= aOutFrameProps
.getArray();
1046 for ( const beans::NamedValue
* pTypedProp
= aOutFramePropsTyped
.getConstArray();
1047 pTypedProp
!= aOutFramePropsTyped
.getConstArray() + aOutFramePropsTyped
.getLength();
1048 ++pTypedProp
, ++pProp
1051 *pProp
<<= *pTypedProp
;
1053 m_xDocHolder
->SetOutplaceFrameProperties( aOutFrameProps
);
1056 SAL_WARN( "embeddedobj.common", "OCommonEmbeddedObject::setPersistentEntry: illegal type for argument 'OutplaceFrameProperties'!" );
1058 else if ( prop
.Name
== "ModuleName" )
1060 prop
.Value
>>= m_aModuleName
;
1062 else if ( prop
.Name
== "EmbeddedScriptSupport" )
1064 OSL_VERIFY( prop
.Value
>>= m_bEmbeddedScriptSupport
);
1066 else if ( prop
.Name
== "DocumentRecoverySupport" )
1068 OSL_VERIFY( prop
.Value
>>= m_bDocumentRecoverySupport
);
1070 else if ( prop
.Name
== "RecoveryStorage" )
1072 OSL_VERIFY( prop
.Value
>>= m_xRecoveryStorage
);
1076 sal_Int32 nStorageMode
= m_bReadOnly
? embed::ElementModes::READ
: embed::ElementModes::READWRITE
;
1078 SwitchOwnPersistence( xStorage
, sEntName
);
1080 if ( nEntryConnectionMode
== embed::EntryInitModes::DEFAULT_INIT
)
1084 // the initialization from existing storage allows to leave object in loaded state
1085 m_nObjectState
= embed::EmbedStates::LOADED
;
1089 m_xDocHolder
->SetComponent( InitNewDocument_Impl(), m_bReadOnly
);
1090 if ( !m_xDocHolder
->GetComponent().is() )
1091 throw io::IOException(); // TODO: can not create document
1093 m_nObjectState
= embed::EmbedStates::RUNNING
;
1098 if ( ( nStorageMode
& embed::ElementModes::READWRITE
) != embed::ElementModes::READWRITE
)
1099 throw io::IOException();
1101 if ( nEntryConnectionMode
== embed::EntryInitModes::NO_INIT
)
1103 // the document just already changed its storage to store to
1104 // the links to OOo documents for now ignore this call
1105 // TODO: OOo links will have persistence so it will be switched here
1107 else if ( nEntryConnectionMode
== embed::EntryInitModes::TRUNCATE_INIT
)
1109 if ( m_xRecoveryStorage
.is() )
1110 TransferMediaType( m_xRecoveryStorage
, m_xObjectStorage
);
1113 m_xDocHolder
->SetComponent( InitNewDocument_Impl(), m_bReadOnly
);
1115 if ( !m_xDocHolder
->GetComponent().is() )
1116 throw io::IOException(); // TODO: can not create document
1118 m_nObjectState
= embed::EmbedStates::RUNNING
;
1120 else if ( nEntryConnectionMode
== embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT
)
1122 m_xDocHolder
->SetComponent( CreateDocFromMediaDescr_Impl( lArguments
), m_bReadOnly
);
1123 m_nObjectState
= embed::EmbedStates::RUNNING
;
1125 //else if ( nEntryConnectionMode == embed::EntryInitModes::TRANSFERABLE_INIT )
1130 throw lang::IllegalArgumentException( "Wrong connection mode is provided!",
1131 static_cast< ::cppu::OWeakObject
* >(this),
1137 void SAL_CALL
OCommonEmbeddedObject::storeToEntry( const uno::Reference
< embed::XStorage
>& xStorage
,
1138 const OUString
& sEntName
,
1139 const uno::Sequence
< beans::PropertyValue
>& lArguments
,
1140 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
1142 ::osl::ResettableMutexGuard
aGuard( m_aMutex
);
1144 throw lang::DisposedException(); // TODO
1146 if ( m_nObjectState
== -1 )
1148 // the object is still not loaded
1149 throw embed::WrongStateException( "Can't store object without persistence!",
1150 static_cast< ::cppu::OWeakObject
* >(this) );
1153 if ( m_bWaitSaveCompleted
)
1154 throw embed::WrongStateException(
1155 "The object waits for saveCompleted() call!",
1156 static_cast< ::cppu::OWeakObject
* >(this) );
1158 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1159 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1160 // OSL_ENSURE( !m_bIsLinkURL, "This method implementation must not be used for links!" );
1164 OSL_ENSURE( m_xParentStorage
.is() && m_xObjectStorage
.is(), "The object has no valid persistence!" );
1166 sal_Int32 nTargetStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1167 sal_Int32 nOriginalStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1169 nTargetStorageFormat
= ::comphelper::OStorageHelper::GetXStorageFormat( xStorage
);
1171 catch ( const beans::IllegalTypeException
& )
1173 // the container just has an unknown type, use current file format
1175 catch ( const uno::Exception
& )
1177 SAL_WARN( "embeddedobj.common", "Can not retrieve target storage media type!" );
1179 if (nTargetStorageFormat
== SOFFICE_FILEFORMAT_60
)
1181 SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1182 nTargetStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1183 // setting MediaType is done later anyway, no need to do it here
1188 nOriginalStorageFormat
= ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage
);
1190 catch ( const beans::IllegalTypeException
& )
1192 // the container just has an unknown type, use current file format
1194 catch ( const uno::Exception
& )
1196 SAL_WARN( "embeddedobj.common", "Can not retrieve own storage media type!" );
1199 bool bTryOptimization
= false;
1200 for ( beans::PropertyValue
const & prop
: lObjArgs
)
1202 // StoreVisualReplacement and VisualReplacement args have no sense here
1203 if ( prop
.Name
== "CanTryOptimization" )
1204 prop
.Value
>>= bTryOptimization
;
1207 bool bSwitchBackToLoaded
= false;
1209 // Storing to different format can be done only in running state.
1210 if ( m_nObjectState
== embed::EmbedStates::LOADED
)
1212 // TODO/LATER: copying is not legal for documents with relative links.
1213 if ( nTargetStorageFormat
== nOriginalStorageFormat
)
1215 bool bOptimizationWorks
= false;
1216 if ( bTryOptimization
)
1220 // try to use optimized copying
1221 uno::Reference
< embed::XOptimizedStorage
> xSource( m_xParentStorage
, uno::UNO_QUERY_THROW
);
1222 uno::Reference
< embed::XOptimizedStorage
> xTarget( xStorage
, uno::UNO_QUERY_THROW
);
1223 xSource
->copyElementDirectlyTo( m_aEntryName
, xTarget
, sEntName
);
1224 bOptimizationWorks
= true;
1226 catch( const uno::Exception
& )
1231 if ( !bOptimizationWorks
)
1232 m_xParentStorage
->copyElementTo( m_aEntryName
, xStorage
, sEntName
);
1236 changeState( embed::EmbedStates::RUNNING
);
1237 bSwitchBackToLoaded
= true;
1241 if ( m_nObjectState
== embed::EmbedStates::LOADED
)
1244 uno::Reference
< embed::XStorage
> xSubStorage
=
1245 xStorage
->openStorageElement( sEntName
, embed::ElementModes::READWRITE
);
1247 if ( !xSubStorage
.is() )
1248 throw uno::RuntimeException(); //TODO
1251 // TODO/LATER: support hierarchical name for embedded objects in embedded objects
1252 StoreDocToStorage_Impl(
1253 xSubStorage
, lArguments
, lObjArgs
, nTargetStorageFormat
, sEntName
, false );
1256 if ( bSwitchBackToLoaded
)
1257 changeState( embed::EmbedStates::LOADED
);
1259 // TODO: should the listener notification be done?
1263 void SAL_CALL
OCommonEmbeddedObject::storeAsEntry( const uno::Reference
< embed::XStorage
>& xStorage
,
1264 const OUString
& sEntName
,
1265 const uno::Sequence
< beans::PropertyValue
>& lArguments
,
1266 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
1268 ::osl::ResettableMutexGuard
aGuard( m_aMutex
);
1270 throw lang::DisposedException(); // TODO
1272 bool AutoSaveEvent
= false;
1273 utl::MediaDescriptor
lArgs(lObjArgs
);
1274 lArgs
[utl::MediaDescriptor::PROP_AUTOSAVEEVENT
] >>= AutoSaveEvent
;
1276 if ( m_nObjectState
== -1 )
1278 // the object is still not loaded
1279 throw embed::WrongStateException( "Can't store object without persistence!",
1280 static_cast< ::cppu::OWeakObject
* >(this) );
1283 if ( m_bWaitSaveCompleted
)
1284 throw embed::WrongStateException(
1285 "The object waits for saveCompleted() call!",
1286 static_cast< ::cppu::OWeakObject
* >(this) );
1288 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1289 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1290 // OSL_ENSURE( !m_bIsLinkURL, "This method implementation must not be used for links!" );
1293 m_aNewEntryName
= sEntName
;
1295 if ( !AutoSaveEvent
)
1296 handleLinkedOLE(CopyBackToOLELink::CopyTempToLink
);
1301 OSL_ENSURE( m_xParentStorage
.is() && m_xObjectStorage
.is(), "The object has no valid persistence!" );
1303 sal_Int32 nTargetStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1304 sal_Int32 nOriginalStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1306 nTargetStorageFormat
= ::comphelper::OStorageHelper::GetXStorageFormat( xStorage
);
1308 catch ( const beans::IllegalTypeException
& )
1310 // the container just has an unknown type, use current file format
1312 catch ( const uno::Exception
& )
1314 SAL_WARN( "embeddedobj.common", "Can not retrieve target storage media type!" );
1316 if (nTargetStorageFormat
== SOFFICE_FILEFORMAT_60
)
1318 SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1319 nTargetStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1320 // setting MediaType is done later anyway, no need to do it here
1325 nOriginalStorageFormat
= ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage
);
1327 catch ( const beans::IllegalTypeException
& )
1329 // the container just has an unknown type, use current file format
1331 catch ( const uno::Exception
& )
1333 SAL_WARN( "embeddedobj.common", "Can not retrieve own storage media type!" );
1336 PostEvent_Impl( "OnSaveAs" );
1338 bool bTryOptimization
= false;
1339 for ( beans::PropertyValue
const & prop
: lObjArgs
)
1341 // StoreVisualReplacement and VisualReplacement args have no sense here
1342 if ( prop
.Name
== "CanTryOptimization" )
1343 prop
.Value
>>= bTryOptimization
;
1346 bool bSwitchBackToLoaded
= false;
1348 // Storing to different format can be done only in running state.
1349 if ( m_nObjectState
== embed::EmbedStates::LOADED
)
1351 // TODO/LATER: copying is not legal for documents with relative links.
1352 if ( nTargetStorageFormat
== nOriginalStorageFormat
)
1354 bool bOptimizationWorks
= false;
1355 if ( bTryOptimization
)
1359 // try to use optimized copying
1360 uno::Reference
< embed::XOptimizedStorage
> xSource( m_xParentStorage
, uno::UNO_QUERY_THROW
);
1361 uno::Reference
< embed::XOptimizedStorage
> xTarget( xStorage
, uno::UNO_QUERY_THROW
);
1362 xSource
->copyElementDirectlyTo( m_aEntryName
, xTarget
, sEntName
);
1363 bOptimizationWorks
= true;
1365 catch( const uno::Exception
& )
1370 if ( !bOptimizationWorks
)
1371 m_xParentStorage
->copyElementTo( m_aEntryName
, xStorage
, sEntName
);
1375 changeState( embed::EmbedStates::RUNNING
);
1376 bSwitchBackToLoaded
= true;
1380 uno::Reference
< embed::XStorage
> xSubStorage
=
1381 xStorage
->openStorageElement( sEntName
, embed::ElementModes::READWRITE
);
1383 if ( !xSubStorage
.is() )
1384 throw uno::RuntimeException(); //TODO
1386 if ( m_nObjectState
!= embed::EmbedStates::LOADED
)
1389 // TODO/LATER: support hierarchical name for embedded objects in embedded objects
1390 StoreDocToStorage_Impl(
1391 xSubStorage
, lArguments
, lObjArgs
, nTargetStorageFormat
, sEntName
, false );
1394 if ( bSwitchBackToLoaded
)
1395 changeState( embed::EmbedStates::LOADED
);
1398 m_bWaitSaveCompleted
= true;
1399 m_xNewObjectStorage
= xSubStorage
;
1400 m_xNewParentStorage
= xStorage
;
1401 m_aNewEntryName
= sEntName
;
1402 m_aNewDocMediaDescriptor
= GetValuableArgs_Impl( lArguments
, true );
1404 // TODO: register listeners for storages above, in case they are disposed
1405 // an exception will be thrown on saveCompleted( true )
1407 // TODO: should the listener notification be done here or in saveCompleted?
1411 void SAL_CALL
OCommonEmbeddedObject::saveCompleted( sal_Bool bUseNew
)
1413 ::osl::MutexGuard
aGuard( m_aMutex
);
1415 throw lang::DisposedException(); // TODO
1417 if ( m_nObjectState
== -1 )
1419 // the object is still not loaded
1420 throw embed::WrongStateException( "Can't store object without persistence!",
1421 static_cast< ::cppu::OWeakObject
* >(this) );
1424 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1425 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1426 // OSL_ENSURE( !m_bIsLinkURL, "This method implementation must not be used for links!" );
1430 m_aEntryName
= m_aNewEntryName
;
1431 m_aNewEntryName
.clear();
1435 // it is allowed to call saveCompleted( false ) for nonstored objects
1436 if ( !m_bWaitSaveCompleted
&& !bUseNew
)
1439 SAL_WARN_IF( !m_bWaitSaveCompleted
, "embeddedobj.common", "Unexpected saveCompleted() call!" );
1440 if ( !m_bWaitSaveCompleted
)
1441 throw io::IOException(); // TODO: illegal call
1443 OSL_ENSURE( m_xNewObjectStorage
.is() && m_xNewParentStorage
.is() , "Internal object information is broken!" );
1444 if ( !m_xNewObjectStorage
.is() || !m_xNewParentStorage
.is() )
1445 throw uno::RuntimeException(); // TODO: broken internal information
1449 SwitchOwnPersistence( m_xNewParentStorage
, m_xNewObjectStorage
, m_aNewEntryName
);
1450 m_aDocMediaDescriptor
= m_aNewDocMediaDescriptor
;
1452 uno::Reference
< util::XModifiable
> xModif( m_xDocHolder
->GetComponent(), uno::UNO_QUERY
);
1454 xModif
->setModified( false );
1456 PostEvent_Impl( "OnSaveAsDone");
1461 m_xNewObjectStorage
->dispose();
1463 catch ( const uno::Exception
& )
1468 m_xNewObjectStorage
.clear();
1469 m_xNewParentStorage
.clear();
1470 m_aNewEntryName
.clear();
1471 m_aNewDocMediaDescriptor
.realloc( 0 );
1472 m_bWaitSaveCompleted
= false;
1476 // TODO: notify listeners
1478 if ( m_nUpdateMode
== embed::EmbedUpdateModes::ALWAYS_UPDATE
)
1480 // TODO: update visual representation
1486 sal_Bool SAL_CALL
OCommonEmbeddedObject::hasEntry()
1488 ::osl::MutexGuard
aGuard( m_aMutex
);
1490 throw lang::DisposedException(); // TODO
1492 if ( m_bWaitSaveCompleted
)
1493 throw embed::WrongStateException(
1494 "The object waits for saveCompleted() call!",
1495 static_cast< ::cppu::OWeakObject
* >(this) );
1497 if ( m_xObjectStorage
.is() )
1504 OUString SAL_CALL
OCommonEmbeddedObject::getEntryName()
1506 ::osl::MutexGuard
aGuard( m_aMutex
);
1508 throw lang::DisposedException(); // TODO
1510 if ( m_nObjectState
== -1 )
1512 // the object is still not loaded
1513 throw embed::WrongStateException( "The object persistence is not initialized!",
1514 static_cast< ::cppu::OWeakObject
* >(this) );
1517 if ( m_bWaitSaveCompleted
)
1518 throw embed::WrongStateException(
1519 "The object waits for saveCompleted() call!",
1520 static_cast< ::cppu::OWeakObject
* >(this) );
1522 return m_aEntryName
;
1526 void SAL_CALL
OCommonEmbeddedObject::storeOwn()
1528 // during switching from Activated to Running and from Running to Loaded states the object will
1529 // ask container to store the object, the container has to make decision
1532 ::osl::ResettableMutexGuard
aGuard( m_aMutex
);
1534 throw lang::DisposedException(); // TODO
1536 if ( m_nObjectState
== -1 )
1538 // the object is still not loaded
1539 throw embed::WrongStateException( "Can't store object without persistence!",
1540 static_cast< ::cppu::OWeakObject
* >(this) );
1543 if ( m_bWaitSaveCompleted
)
1544 throw embed::WrongStateException(
1545 "The object waits for saveCompleted() call!",
1546 static_cast< ::cppu::OWeakObject
* >(this) );
1549 throw io::IOException(); // TODO: access denied
1551 // nothing to do, if the object is in loaded state
1552 if ( m_nObjectState
== embed::EmbedStates::LOADED
)
1555 PostEvent_Impl( "OnSave" );
1557 SAL_WARN_IF( !m_xDocHolder
->GetComponent().is(), "embeddedobj.common", "If an object is activated or in running state it must have a document!" );
1558 if ( !m_xDocHolder
->GetComponent().is() )
1559 throw uno::RuntimeException();
1563 // TODO: just store the document to its location
1564 uno::Reference
< frame::XStorable
> xStorable( m_xDocHolder
->GetComponent(), uno::UNO_QUERY_THROW
);
1566 // free the main mutex for the storing time
1575 OSL_ENSURE( m_xParentStorage
.is() && m_xObjectStorage
.is(), "The object has no valid persistence!" );
1577 if ( !m_xObjectStorage
.is() )
1578 throw io::IOException(); //TODO: access denied
1580 sal_Int32 nStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1582 nStorageFormat
= ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage
);
1584 catch ( const beans::IllegalTypeException
& )
1586 // the container just has an unknown type, use current file format
1588 catch ( const uno::Exception
& )
1590 SAL_WARN( "embeddedobj.common", "Can not retrieve storage media type!" );
1592 if (nStorageFormat
== SOFFICE_FILEFORMAT_60
)
1594 SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1595 nStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1596 // setting MediaType is done later anyway, no need to do it here
1600 uno::Sequence
<beans::PropertyValue
> aEmpty
;
1601 uno::Sequence
<beans::PropertyValue
> aMediaArgs
{ comphelper::makePropertyValue(
1602 "DocumentBaseURL", GetBaseURL_Impl()) };
1603 StoreDocToStorage_Impl( m_xObjectStorage
, aMediaArgs
, aEmpty
, nStorageFormat
, m_aEntryName
, true );
1607 uno::Reference
< util::XModifiable
> xModif( m_xDocHolder
->GetComponent(), uno::UNO_QUERY
);
1609 xModif
->setModified( false );
1611 PostEvent_Impl( "OnSaveDone" );
1615 sal_Bool SAL_CALL
OCommonEmbeddedObject::isReadonly()
1617 ::osl::MutexGuard
aGuard( m_aMutex
);
1619 throw lang::DisposedException(); // TODO
1621 if ( m_nObjectState
== -1 )
1623 // the object is still not loaded
1624 throw embed::WrongStateException( "The object persistence is not initialized!",
1625 static_cast< ::cppu::OWeakObject
* >(this) );
1628 if ( m_bWaitSaveCompleted
)
1629 throw embed::WrongStateException(
1630 "The object waits for saveCompleted() call!",
1631 static_cast< ::cppu::OWeakObject
* >(this) );
1637 void SAL_CALL
OCommonEmbeddedObject::reload(
1638 const uno::Sequence
< beans::PropertyValue
>& lArguments
,
1639 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
1641 // TODO: use lObjArgs
1642 // for now this method is used only to switch readonly state
1644 ::osl::MutexGuard
aGuard( m_aMutex
);
1646 throw lang::DisposedException(); // TODO
1648 if ( m_nObjectState
== -1 )
1650 // the object is still not loaded
1651 throw embed::WrongStateException( "The object persistence is not initialized!",
1652 static_cast< ::cppu::OWeakObject
* >(this) );
1655 if ( m_nObjectState
!= embed::EmbedStates::LOADED
)
1657 // the object is still not loaded
1658 throw embed::WrongStateException(
1659 "The object must be in loaded state to be reloaded!",
1660 static_cast< ::cppu::OWeakObject
* >(this) );
1663 if ( m_bWaitSaveCompleted
)
1664 throw embed::WrongStateException(
1665 "The object waits for saveCompleted() call!",
1666 static_cast< ::cppu::OWeakObject
* >(this) );
1670 // reload of the link
1671 OUString aOldLinkFilter
= m_aLinkFilterName
;
1673 OUString aNewLinkFilter
;
1674 for ( beans::PropertyValue
const & prop
: lArguments
)
1676 if ( prop
.Name
== "URL" )
1679 prop
.Value
>>= m_aLinkURL
;
1680 m_aLinkFilterName
.clear();
1682 else if ( prop
.Name
== "FilterName" )
1684 prop
.Value
>>= aNewLinkFilter
;
1685 m_aLinkFilterName
.clear();
1689 ::comphelper::MimeConfigurationHelper
aHelper( m_xContext
);
1690 if ( m_aLinkFilterName
.isEmpty() )
1692 if ( !aNewLinkFilter
.isEmpty() )
1693 m_aLinkFilterName
= aNewLinkFilter
;
1696 uno::Sequence
< beans::PropertyValue
> aArgs
{ comphelper::makePropertyValue(
1697 "URL", m_aLinkURL
) };
1698 m_aLinkFilterName
= aHelper
.UpdateMediaDescriptorWithFilterName( aArgs
, false );
1702 if ( aOldLinkFilter
!= m_aLinkFilterName
)
1704 uno::Sequence
< beans::NamedValue
> aObject
= aHelper
.GetObjectPropsByFilter( m_aLinkFilterName
);
1706 // TODO/LATER: probably the document holder could be cleaned explicitly as in the destructor
1707 m_xDocHolder
.clear();
1709 LinkInit_Impl( aObject
, lArguments
, lObjArgs
);
1713 m_aDocMediaDescriptor
= GetValuableArgs_Impl( lArguments
, true );
1715 // TODO: use lObjArgs for StoreVisualReplacement
1716 for ( beans::PropertyValue
const & prop
: lObjArgs
)
1717 if ( prop
.Name
== "OutplaceDispatchInterceptor" )
1719 uno::Reference
< frame::XDispatchProviderInterceptor
> xDispatchInterceptor
;
1720 if ( prop
.Value
>>= xDispatchInterceptor
)
1721 m_xDocHolder
->SetOutplaceDispatchInterceptor( xDispatchInterceptor
);
1727 // when document allows reloading through API the object can be reloaded not only in loaded state
1729 bool bOldReadOnlyValue
= m_bReadOnly
;
1731 m_bReadOnly
= false;
1732 for ( beans::PropertyValue
const & prop
: lArguments
)
1733 if ( prop
.Name
== "ReadOnly" )
1734 prop
.Value
>>= m_bReadOnly
;
1736 if ( bOldReadOnlyValue
== m_bReadOnly
|| m_bIsLinkURL
)
1739 // close own storage
1741 if ( m_xObjectStorage
.is() )
1742 m_xObjectStorage
->dispose();
1744 catch ( const uno::Exception
& )
1748 sal_Int32 nStorageMode
= m_bReadOnly
? embed::ElementModes::READ
: embed::ElementModes::READWRITE
;
1749 m_xObjectStorage
= m_xParentStorage
->openStorageElement( m_aEntryName
, nStorageMode
);
1752 sal_Bool SAL_CALL
OCommonEmbeddedObject::isStored()
1754 if (!m_xObjectStorage
.is())
1757 return m_xObjectStorage
->getElementNames().hasElements();
1761 void SAL_CALL
OCommonEmbeddedObject::breakLink( const uno::Reference
< embed::XStorage
>& xStorage
,
1762 const OUString
& sEntName
)
1764 ::osl::ResettableMutexGuard
aGuard( m_aMutex
);
1766 throw lang::DisposedException(); // TODO
1768 if (!m_bIsLinkURL
|| m_nObjectState
== -1)
1770 // it must be a linked initialized object
1771 throw embed::WrongStateException(
1772 "The object is not a valid linked object!",
1773 static_cast< ::cppu::OWeakObject
* >(this) );
1775 // the current implementation of OOo links does not implement this method since it does not implement
1776 // all the set of interfaces required for OOo embedded object ( XEmbedPersist is not supported ).
1778 if ( !xStorage
.is() )
1779 throw lang::IllegalArgumentException( "No parent storage is provided!",
1780 static_cast< ::cppu::OWeakObject
* >(this),
1783 if ( sEntName
.isEmpty() )
1784 throw lang::IllegalArgumentException( "Empty element name is provided!",
1785 static_cast< ::cppu::OWeakObject
* >(this),
1788 if ( m_bWaitSaveCompleted
)
1789 throw embed::WrongStateException(
1790 "The object waits for saveCompleted() call!",
1791 static_cast< ::cppu::OWeakObject
* >(this) );
1793 uno::Reference
< container::XNameAccess
> xNameAccess( xStorage
, uno::UNO_QUERY_THROW
);
1795 m_bReadOnly
= false;
1797 if ( m_xParentStorage
!= xStorage
|| m_aEntryName
!= sEntName
)
1798 SwitchOwnPersistence( xStorage
, sEntName
);
1800 // for linked object it means that it becomes embedded object
1801 // the document must switch it's persistence also
1803 // TODO/LATER: handle the case when temp doc can not be created
1804 // the document is a new embedded object so it must be marked as modified
1805 uno::Reference
< util::XCloseable
> xDocument
= CreateTempDocFromLink_Impl();
1808 if(m_xDocHolder
.is() && m_xDocHolder
->GetComponent().is())
1810 // tdf#141528 m_xDocHolder->GetComponent() may be not set, so add it
1811 // to the try path to not get thrown out of the local context to the next
1812 // higher try...catch on the stack. To make breakLink work it is
1813 // *necessary* to execute the code below that resets the linked state,
1814 // esp. the *.clear stuff and resetting m_bIsLink.
1815 uno::Reference
< util::XModifiable
> xModif( m_xDocHolder
->GetComponent(), uno::UNO_QUERY_THROW
);
1817 // all other locations in this file check for xModif.is(), so do it here, too
1819 xModif
->setModified( true );
1822 catch( const uno::Exception
& )
1825 m_xDocHolder
->SetComponent( xDocument
, m_bReadOnly
);
1826 SAL_WARN_IF( !m_xDocHolder
->GetComponent().is(), "embeddedobj.common", "If document can't be created, an exception must be thrown!" );
1828 if ( m_nObjectState
== embed::EmbedStates::LOADED
)
1830 // the state is changed and can not be switched to loaded state back without saving
1831 m_nObjectState
= embed::EmbedStates::RUNNING
;
1832 StateChangeNotification_Impl( false, embed::EmbedStates::LOADED
, m_nObjectState
, aGuard
);
1834 else if ( m_nObjectState
== embed::EmbedStates::ACTIVE
)
1835 m_xDocHolder
->Show();
1837 // tdf#141529 reset all stuff involved in linked state, including
1838 // the OLE content copied to the temp file
1839 m_bIsLinkURL
= false;
1840 m_aLinkTempFile
.clear();
1841 m_aLinkFilterName
.clear();
1846 sal_Bool SAL_CALL
OCommonEmbeddedObject::isLink()
1848 ::osl::MutexGuard
aGuard( m_aMutex
);
1850 throw lang::DisposedException(); // TODO
1852 return m_bIsLinkURL
;
1856 OUString SAL_CALL
OCommonEmbeddedObject::getLinkURL()
1858 ::osl::MutexGuard
aGuard( m_aMutex
);
1860 throw lang::DisposedException(); // TODO
1862 if ( !m_bIsLinkURL
)
1863 throw embed::WrongStateException(
1864 "The object is not a link object!",
1865 static_cast< ::cppu::OWeakObject
* >(this) );
1870 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */