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>
51 #include <com/sun/star/io/XTruncate.hpp>
53 #include <comphelper/fileformat.h>
54 #include <comphelper/storagehelper.hxx>
55 #include <comphelper/mimeconfighelper.hxx>
56 #include <comphelper/namedvaluecollection.hxx>
58 #include <tools/diagnose_ex.h>
59 #include <sal/log.hxx>
60 #include <unotools/configmgr.hxx>
61 #include "persistence.hxx"
63 using namespace ::com::sun::star
;
66 uno::Sequence
< beans::PropertyValue
> GetValuableArgs_Impl( const uno::Sequence
< beans::PropertyValue
>& aMedDescr
,
67 bool bCanUseDocumentBaseURL
)
69 uno::Sequence
< beans::PropertyValue
> aResult
;
70 sal_Int32 nResLen
= 0;
72 for ( beans::PropertyValue
const & prop
: aMedDescr
)
74 if ( prop
.Name
== "ComponentData" || prop
.Name
== "DocumentTitle"
75 || prop
.Name
== "InteractionHandler" || prop
.Name
== "JumpMark"
76 // || prop.Name == "Password" // makes no sense for embedded objects
77 || prop
.Name
== "Preview" || prop
.Name
== "ReadOnly"
78 || prop
.Name
== "StartPresentation" || prop
.Name
== "RepairPackage"
79 || prop
.Name
== "StatusIndicator" || prop
.Name
== "ViewData"
80 || prop
.Name
== "ViewId" || prop
.Name
== "MacroExecutionMode"
81 || prop
.Name
== "UpdateDocMode"
82 || (prop
.Name
== "DocumentBaseURL" && bCanUseDocumentBaseURL
) )
84 aResult
.realloc( ++nResLen
);
85 aResult
[nResLen
-1] = prop
;
93 static uno::Sequence
< beans::PropertyValue
> addAsTemplate( const uno::Sequence
< beans::PropertyValue
>& aOrig
)
95 bool bAsTemplateSet
= false;
96 sal_Int32 nLength
= aOrig
.getLength();
97 uno::Sequence
< beans::PropertyValue
> aResult( nLength
);
99 for ( sal_Int32 nInd
= 0; nInd
< nLength
; nInd
++ )
101 aResult
[nInd
].Name
= aOrig
[nInd
].Name
;
102 if ( aResult
[nInd
].Name
== "AsTemplate" )
104 aResult
[nInd
].Value
<<= true;
105 bAsTemplateSet
= true;
108 aResult
[nInd
].Value
= aOrig
[nInd
].Value
;
111 if ( !bAsTemplateSet
)
113 aResult
.realloc( nLength
+ 1 );
114 aResult
[nLength
].Name
= "AsTemplate";
115 aResult
[nLength
].Value
<<= true;
122 static uno::Reference
< io::XInputStream
> createTempInpStreamFromStor(
123 const uno::Reference
< embed::XStorage
>& xStorage
,
124 const uno::Reference
< uno::XComponentContext
>& xContext
)
126 SAL_WARN_IF( !xStorage
.is(), "embeddedobj.common", "The storage can not be empty!" );
128 uno::Reference
< io::XInputStream
> xResult
;
130 uno::Reference
< io::XStream
> xTempStream( io::TempFile::create(xContext
), uno::UNO_QUERY_THROW
);
132 uno::Reference
< lang::XSingleServiceFactory
> xStorageFactory( embed::StorageFactory::create(xContext
) );
134 uno::Sequence
< uno::Any
> aArgs( 2 );
135 aArgs
[0] <<= xTempStream
;
136 aArgs
[1] <<= embed::ElementModes::READWRITE
;
137 uno::Reference
< embed::XStorage
> xTempStorage( xStorageFactory
->createInstanceWithArguments( aArgs
),
138 uno::UNO_QUERY_THROW
);
142 xStorage
->copyToStorage( xTempStorage
);
143 } catch( const uno::Exception
& )
145 css::uno::Any anyEx
= cppu::getCaughtException();
146 throw embed::StorageWrappedTargetException(
147 "Can't copy storage!",
148 uno::Reference
< uno::XInterface
>(),
153 if ( xTempStorage
.is() )
154 xTempStorage
->dispose();
156 catch ( const uno::Exception
& )
161 uno::Reference
< io::XOutputStream
> xTempOut
= xTempStream
->getOutputStream();
163 xTempOut
->closeOutput();
165 catch ( const uno::Exception
& )
169 xResult
= xTempStream
->getInputStream();
176 static void TransferMediaType( const uno::Reference
< embed::XStorage
>& i_rSource
, const uno::Reference
< embed::XStorage
>& i_rTarget
)
180 const uno::Reference
< beans::XPropertySet
> xSourceProps( i_rSource
, uno::UNO_QUERY_THROW
);
181 const uno::Reference
< beans::XPropertySet
> xTargetProps( i_rTarget
, uno::UNO_QUERY_THROW
);
182 const OUString
sMediaTypePropName( "MediaType" );
183 xTargetProps
->setPropertyValue( sMediaTypePropName
, xSourceProps
->getPropertyValue( sMediaTypePropName
) );
185 catch( const uno::Exception
& )
187 DBG_UNHANDLED_EXCEPTION("embeddedobj.common");
192 static uno::Reference
< util::XCloseable
> CreateDocument( const uno::Reference
< uno::XComponentContext
>& _rxContext
,
193 const OUString
& _rDocumentServiceName
, bool _bEmbeddedScriptSupport
, const bool i_bDocumentRecoverySupport
)
195 ::comphelper::NamedValueCollection aArguments
;
196 aArguments
.put( "EmbeddedObject", true );
197 aArguments
.put( "EmbeddedScriptSupport", _bEmbeddedScriptSupport
);
198 aArguments
.put( "DocumentRecoverySupport", i_bDocumentRecoverySupport
);
200 uno::Reference
< uno::XInterface
> xDocument
;
203 xDocument
= _rxContext
->getServiceManager()->createInstanceWithArgumentsAndContext(
204 _rDocumentServiceName
, aArguments
.getWrappedPropertyValues(), _rxContext
);
206 catch( const uno::Exception
& )
208 // if an embedded object implementation does not support XInitialization,
209 // the default factory from cppuhelper will throw an
210 // IllegalArgumentException when we try to create the instance with arguments.
211 // Okay, so we fall back to creating the instance without any arguments.
212 OSL_FAIL("Consider implementing interface XInitialization to avoid duplicate construction");
213 xDocument
= _rxContext
->getServiceManager()->createInstanceWithContext( _rDocumentServiceName
, _rxContext
);
216 SAL_WARN_IF(!xDocument
.is(), "embeddedobj.common", "Service " << _rDocumentServiceName
<< " is not available?");
217 return uno::Reference
< util::XCloseable
>( xDocument
, uno::UNO_QUERY
);
221 static void SetDocToEmbedded( const uno::Reference
< frame::XModel
>& rDocument
, const OUString
& aModuleName
)
226 uno::Sequence
< beans::PropertyValue
> aSeq( 1 );
227 aSeq
[0].Name
= "SetEmbedded";
228 aSeq
[0].Value
<<= true;
229 rDocument
->attachResource( OUString(), aSeq
);
231 if ( !aModuleName
.isEmpty() )
235 uno::Reference
< frame::XModule
> xModule( rDocument
, uno::UNO_QUERY_THROW
);
236 xModule
->setIdentifier( aModuleName
);
238 catch( const uno::Exception
& )
244 void OCommonEmbeddedObject::SwitchOwnPersistence( const uno::Reference
< embed::XStorage
>& xNewParentStorage
,
245 const uno::Reference
< embed::XStorage
>& xNewObjectStorage
,
246 const OUString
& aNewName
)
248 if ( xNewParentStorage
== m_xParentStorage
&& aNewName
== m_aEntryName
)
250 SAL_WARN_IF( xNewObjectStorage
!= m_xObjectStorage
, "embeddedobj.common", "The storage must be the same!" );
254 auto xOldObjectStorage
= m_xObjectStorage
;
255 m_xObjectStorage
= xNewObjectStorage
;
256 m_xParentStorage
= xNewParentStorage
;
257 m_aEntryName
= aNewName
;
259 // the linked document should not be switched
262 uno::Reference
< document::XStorageBasedDocument
> xDoc( m_xDocHolder
->GetComponent(), uno::UNO_QUERY
);
264 SwitchDocToStorage_Impl( xDoc
, m_xObjectStorage
);
268 if ( xOldObjectStorage
.is() )
269 xOldObjectStorage
->dispose();
271 catch ( const uno::Exception
& )
277 void OCommonEmbeddedObject::SwitchOwnPersistence( const uno::Reference
< embed::XStorage
>& xNewParentStorage
,
278 const OUString
& aNewName
)
280 if ( xNewParentStorage
== m_xParentStorage
&& aNewName
== m_aEntryName
)
283 sal_Int32 nStorageMode
= m_bReadOnly
? embed::ElementModes::READ
: embed::ElementModes::READWRITE
;
285 uno::Reference
< embed::XStorage
> xNewOwnStorage
= xNewParentStorage
->openStorageElement( aNewName
, nStorageMode
);
286 SAL_WARN_IF( !xNewOwnStorage
.is(), "embeddedobj.common", "The method can not return empty reference!" );
288 SwitchOwnPersistence( xNewParentStorage
, xNewOwnStorage
, aNewName
);
292 void OCommonEmbeddedObject::EmbedAndReparentDoc_Impl( const uno::Reference
< util::XCloseable
>& i_rxDocument
) const
294 SetDocToEmbedded( uno::Reference
< frame::XModel
>( i_rxDocument
, uno::UNO_QUERY
), m_aModuleName
);
298 uno::Reference
< container::XChild
> xChild( i_rxDocument
, uno::UNO_QUERY
);
300 xChild
->setParent( m_xParent
);
302 catch( const lang::NoSupportException
& )
304 SAL_WARN( "embeddedobj.common", "OCommonEmbeddedObject::EmbedAndReparentDoc: cannot set parent at document!" );
309 uno::Reference
< util::XCloseable
> OCommonEmbeddedObject::InitNewDocument_Impl()
311 uno::Reference
< util::XCloseable
> xDocument( CreateDocument( m_xContext
, GetDocumentServiceName(),
312 m_bEmbeddedScriptSupport
, m_bDocumentRecoverySupport
) );
314 uno::Reference
< frame::XModel
> xModel( xDocument
, uno::UNO_QUERY
);
315 uno::Reference
< frame::XLoadable
> xLoadable( xModel
, uno::UNO_QUERY_THROW
);
319 // set the document mode to embedded as the first action on document!!!
320 EmbedAndReparentDoc_Impl( xDocument
);
322 // if we have a storage to recover the document from, do not use initNew, but instead load from that storage
323 bool bInitNew
= true;
324 if ( m_xRecoveryStorage
.is() )
326 uno::Reference
< document::XStorageBasedDocument
> xDoc( xLoadable
, uno::UNO_QUERY
);
327 SAL_WARN_IF( !xDoc
.is(), "embeddedobj.common", "OCommonEmbeddedObject::InitNewDocument_Impl: cannot recover from a storage when the document is not storage based!" );
330 ::comphelper::NamedValueCollection aLoadArgs
;
331 FillDefaultLoadArgs_Impl( m_xRecoveryStorage
, aLoadArgs
);
333 xDoc
->loadFromStorage( m_xRecoveryStorage
, aLoadArgs
.getPropertyValues() );
334 SwitchDocToStorage_Impl( xDoc
, m_xObjectStorage
);
341 // init document as a new
342 xLoadable
->initNew();
344 xModel
->attachResource( xModel
->getURL(), m_aDocMediaDescriptor
);
346 catch( const uno::Exception
& )
348 if ( xDocument
.is() )
352 xDocument
->close( true );
354 catch( const uno::Exception
& )
366 uno::Reference
< util::XCloseable
> OCommonEmbeddedObject::LoadLink_Impl()
368 uno::Reference
< util::XCloseable
> xDocument( CreateDocument( m_xContext
, GetDocumentServiceName(),
369 m_bEmbeddedScriptSupport
, m_bDocumentRecoverySupport
) );
371 uno::Reference
< frame::XLoadable
> xLoadable( xDocument
, uno::UNO_QUERY_THROW
);
374 uno::Sequence
< beans::PropertyValue
> aArgs( nLen
);
376 aArgs
[0].Name
= "URL";
377 if(m_aLinkTempFile
.is())
378 aArgs
[0].Value
<<= m_aLinkTempFile
->getUri();
380 aArgs
[0].Value
<<= m_aLinkURL
;
382 aArgs
[1].Name
= "FilterName";
383 aArgs
[1].Value
<<= m_aLinkFilterName
;
385 if ( m_bLinkHasPassword
)
387 aArgs
.realloc( ++nLen
);
388 aArgs
[nLen
-1].Name
= "Password";
389 aArgs
[nLen
-1].Value
<<= m_aLinkPassword
;
392 aArgs
.realloc( m_aDocMediaDescriptor
.getLength() + nLen
);
393 for ( sal_Int32 nInd
= 0; nInd
< m_aDocMediaDescriptor
.getLength(); nInd
++ )
395 aArgs
[nInd
+nLen
].Name
= m_aDocMediaDescriptor
[nInd
].Name
;
396 aArgs
[nInd
+nLen
].Value
= m_aDocMediaDescriptor
[nInd
].Value
;
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 xDoc
->loadFromStorage( xSourceStorage
, aLoadArgs
.getPropertyValues() );
545 if ( xSourceStorage
!= m_xObjectStorage
)
546 SwitchDocToStorage_Impl( xDoc
, m_xObjectStorage
);
549 xLoadable
->load( aLoadArgs
.getPropertyValues() );
551 catch( const uno::Exception
& )
553 if ( xDocument
.is() )
557 xDocument
->close( true );
559 catch( const uno::Exception
& )
561 DBG_UNHANDLED_EXCEPTION("embeddedobj.common");
572 uno::Reference
< io::XInputStream
> OCommonEmbeddedObject::StoreDocumentToTempStream_Impl(
573 sal_Int32 nStorageFormat
,
574 const OUString
& aBaseURL
,
575 const OUString
& aHierarchName
)
577 uno::Reference
< io::XOutputStream
> xTempOut(
578 io::TempFile::create(m_xContext
),
579 uno::UNO_QUERY_THROW
);
580 uno::Reference
< io::XInputStream
> aResult( xTempOut
, uno::UNO_QUERY_THROW
);
582 uno::Reference
< frame::XStorable
> xStorable
;
584 osl::MutexGuard
aGuard( m_aMutex
);
585 if ( m_xDocHolder
.is() )
586 xStorable
.set( m_xDocHolder
->GetComponent(), uno::UNO_QUERY
);
589 if( !xStorable
.is() )
590 throw uno::RuntimeException(); // TODO:
592 OUString aFilterName
= GetFilterName( nStorageFormat
);
594 SAL_WARN_IF( aFilterName
.isEmpty(), "embeddedobj.common", "Wrong document service name!" );
595 if ( aFilterName
.isEmpty() )
596 throw io::IOException(); // TODO:
598 uno::Sequence
< beans::PropertyValue
> aArgs( 4 );
599 aArgs
[0].Name
= "FilterName";
600 aArgs
[0].Value
<<= aFilterName
;
601 aArgs
[1].Name
= "OutputStream";
602 aArgs
[1].Value
<<= xTempOut
;
603 aArgs
[2].Name
= "DocumentBaseURL";
604 aArgs
[2].Value
<<= aBaseURL
;
605 aArgs
[3].Name
= "HierarchicalDocumentName";
606 aArgs
[3].Value
<<= aHierarchName
;
608 xStorable
->storeToURL( "private:stream", aArgs
);
611 xTempOut
->closeOutput();
613 catch( const uno::Exception
& )
615 SAL_WARN( "embeddedobj.common", "Looks like stream was closed already" );
622 void OCommonEmbeddedObject::SaveObject_Impl()
624 if ( !m_xClientSite
.is() )
629 // check whether the component is modified,
630 // if not there is no need for storing
631 uno::Reference
< util::XModifiable
> xModifiable( m_xDocHolder
->GetComponent(), uno::UNO_QUERY
);
632 if ( xModifiable
.is() && !xModifiable
->isModified() )
635 catch( const uno::Exception
& )
639 m_xClientSite
->saveObject();
641 catch( const uno::Exception
& )
643 SAL_WARN( "embeddedobj.common", "The object was not stored!" );
648 OUString
OCommonEmbeddedObject::GetBaseURL_Impl() const
652 if ( m_xClientSite
.is() )
656 uno::Reference
< frame::XModel
> xParentModel( m_xClientSite
->getComponent(), uno::UNO_QUERY_THROW
);
657 const uno::Sequence
< beans::PropertyValue
> aModelProps
= xParentModel
->getArgs();
658 for ( beans::PropertyValue
const & prop
: aModelProps
)
659 if ( prop
.Name
== "DocumentBaseURL" )
661 prop
.Value
>>= aBaseURL
;
665 catch( const uno::Exception
& )
669 if ( aBaseURL
.isEmpty() )
671 for ( beans::PropertyValue
const & prop
: m_aDocMediaDescriptor
)
672 if ( prop
.Name
== "DocumentBaseURL" )
674 prop
.Value
>>= aBaseURL
;
679 if ( aBaseURL
.isEmpty() )
680 aBaseURL
= m_aDefaultParentBaseURL
;
686 OUString
OCommonEmbeddedObject::GetBaseURLFrom_Impl(
687 const uno::Sequence
< beans::PropertyValue
>& lArguments
,
688 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
692 for ( beans::PropertyValue
const & prop
: lArguments
)
693 if ( prop
.Name
== "DocumentBaseURL" )
695 prop
.Value
>>= aBaseURL
;
699 if ( aBaseURL
.isEmpty() )
701 for ( beans::PropertyValue
const & prop
: lObjArgs
)
702 if ( prop
.Name
== "DefaultParentBaseURL" )
704 prop
.Value
>>= aBaseURL
;
713 void OCommonEmbeddedObject::SwitchDocToStorage_Impl( const uno::Reference
< document::XStorageBasedDocument
>& xDoc
, const uno::Reference
< embed::XStorage
>& xStorage
)
715 xDoc
->switchToStorage( xStorage
);
717 uno::Reference
< util::XModifiable
> xModif( xDoc
, uno::UNO_QUERY
);
719 xModif
->setModified( false );
721 if ( m_xRecoveryStorage
.is() )
722 m_xRecoveryStorage
.clear();
727 OUString
getStringPropertyValue( const uno::Sequence
<beans::PropertyValue
>& rProps
, const OUString
& rName
)
731 for (beans::PropertyValue
const & prop
: rProps
)
733 if (prop
.Name
== rName
)
745 void OCommonEmbeddedObject::StoreDocToStorage_Impl(
746 const uno::Reference
<embed::XStorage
>& xStorage
,
747 const uno::Sequence
<beans::PropertyValue
>& rMediaArgs
,
748 const uno::Sequence
<beans::PropertyValue
>& rObjArgs
,
749 sal_Int32 nStorageFormat
,
750 const OUString
& aHierarchName
,
751 bool bAttachToTheStorage
)
753 SAL_WARN_IF( !xStorage
.is(), "embeddedobj.common", "No storage is provided for storing!" );
755 if ( !xStorage
.is() )
756 throw uno::RuntimeException(); // TODO:
758 uno::Reference
< document::XStorageBasedDocument
> xDoc
;
760 osl::MutexGuard
aGuard( m_aMutex
);
761 if ( m_xDocHolder
.is() )
762 xDoc
.set( m_xDocHolder
->GetComponent(), uno::UNO_QUERY
);
765 OUString aBaseURL
= GetBaseURLFrom_Impl(rMediaArgs
, rObjArgs
);
769 OUString aFilterName
= GetFilterName( nStorageFormat
);
771 // No filter found? Try the older format, e.g. Base has only that.
772 if (aFilterName
.isEmpty() && nStorageFormat
== SOFFICE_FILEFORMAT_CURRENT
)
773 aFilterName
= GetFilterName( SOFFICE_FILEFORMAT_60
);
775 SAL_WARN_IF( aFilterName
.isEmpty(), "embeddedobj.common", "Wrong document service name!" );
776 if ( aFilterName
.isEmpty() )
777 throw io::IOException(); // TODO:
779 uno::Sequence
<beans::PropertyValue
> aArgs(5);
780 aArgs
[0].Name
= "FilterName";
781 aArgs
[0].Value
<<= aFilterName
;
782 aArgs
[1].Name
= "HierarchicalDocumentName";
783 aArgs
[1].Value
<<= aHierarchName
;
784 aArgs
[2].Name
= "DocumentBaseURL";
785 aArgs
[2].Value
<<= aBaseURL
;
786 aArgs
[3].Name
= "SourceShellID";
787 aArgs
[3].Value
<<= getStringPropertyValue(rObjArgs
, "SourceShellID");
788 aArgs
[4].Name
= "DestinationShellID";
789 aArgs
[4].Value
<<= getStringPropertyValue(rObjArgs
, "DestinationShellID");
791 xDoc
->storeToStorage( xStorage
, aArgs
);
792 if ( bAttachToTheStorage
)
793 SwitchDocToStorage_Impl( xDoc
, xStorage
);
797 // store document to temporary stream based on temporary file
798 uno::Reference
< io::XInputStream
> xTempIn
= StoreDocumentToTempStream_Impl( nStorageFormat
, aBaseURL
, aHierarchName
);
800 SAL_WARN_IF( !xTempIn
.is(), "embeddedobj.common", "The stream reference can not be empty!" );
802 // open storage based on document temporary file for reading
803 uno::Reference
< lang::XSingleServiceFactory
> xStorageFactory
= embed::StorageFactory::create(m_xContext
);
805 uno::Sequence
< uno::Any
> aArgs(1);
806 aArgs
[0] <<= xTempIn
;
807 uno::Reference
< embed::XStorage
> xTempStorage( xStorageFactory
->createInstanceWithArguments( aArgs
),
808 uno::UNO_QUERY_THROW
);
810 // object storage must be committed automatically
811 xTempStorage
->copyToStorage( xStorage
);
816 uno::Reference
< util::XCloseable
> OCommonEmbeddedObject::CreateDocFromMediaDescr_Impl(
817 const uno::Sequence
< beans::PropertyValue
>& aMedDescr
)
819 uno::Reference
< util::XCloseable
> xDocument( CreateDocument( m_xContext
, GetDocumentServiceName(),
820 m_bEmbeddedScriptSupport
, m_bDocumentRecoverySupport
) );
822 uno::Reference
< frame::XLoadable
> xLoadable( xDocument
, uno::UNO_QUERY_THROW
);
826 // set the document mode to embedded as the first action on the document!!!
827 EmbedAndReparentDoc_Impl( xDocument
);
829 xLoadable
->load( addAsTemplate( aMedDescr
) );
831 catch( const uno::Exception
& )
833 if ( xDocument
.is() )
837 xDocument
->close( true );
839 catch( const uno::Exception
& )
851 uno::Reference
< util::XCloseable
> OCommonEmbeddedObject::CreateTempDocFromLink_Impl()
853 uno::Reference
< util::XCloseable
> xResult
;
855 SAL_WARN_IF( !m_bIsLinkURL
, "embeddedobj.common", "The object is not a linked one!" );
857 uno::Sequence
< beans::PropertyValue
> aTempMediaDescr
;
859 sal_Int32 nStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
861 nStorageFormat
= ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage
);
863 catch ( const beans::IllegalTypeException
& )
865 // the container just has an unknown type, use current file format
867 catch ( const uno::Exception
& )
869 SAL_WARN( "embeddedobj.common", "Can not retrieve storage media type!" );
872 if ( m_xDocHolder
->GetComponent().is() )
874 aTempMediaDescr
.realloc( 4 );
876 // TODO/LATER: may be private:stream should be used as target URL
877 OUString aTempFileURL
;
878 uno::Reference
< io::XInputStream
> xTempStream
= StoreDocumentToTempStream_Impl( SOFFICE_FILEFORMAT_CURRENT
,
883 // no need to let the file stay after the stream is removed since the embedded document
884 // can not be stored directly
885 uno::Reference
< beans::XPropertySet
> xTempStreamProps( xTempStream
, uno::UNO_QUERY_THROW
);
886 xTempStreamProps
->getPropertyValue("Uri") >>= aTempFileURL
;
888 catch( const uno::Exception
& )
892 SAL_WARN_IF( aTempFileURL
.isEmpty(), "embeddedobj.common", "Couldn't retrieve temporary file URL!" );
894 aTempMediaDescr
[0].Name
= "URL";
895 aTempMediaDescr
[0].Value
<<= aTempFileURL
;
896 aTempMediaDescr
[1].Name
= "InputStream";
897 aTempMediaDescr
[1].Value
<<= xTempStream
;
898 aTempMediaDescr
[2].Name
= "FilterName";
899 aTempMediaDescr
[2].Value
<<= GetFilterName( nStorageFormat
);
900 aTempMediaDescr
[3].Name
= "AsTemplate";
901 aTempMediaDescr
[3].Value
<<= true;
905 aTempMediaDescr
.realloc( 2 );
906 aTempMediaDescr
[0].Name
= "URL";
908 // tdf#141529 use URL of the linked TempFile if it exists
909 aTempMediaDescr
[0].Value
<<= m_aLinkTempFile
.is()
910 ? m_aLinkTempFile
->getUri()
913 aTempMediaDescr
[1].Name
= "FilterName";
914 aTempMediaDescr
[1].Value
<<= m_aLinkFilterName
;
917 xResult
= CreateDocFromMediaDescr_Impl( aTempMediaDescr
);
923 void SAL_CALL
OCommonEmbeddedObject::setPersistentEntry(
924 const uno::Reference
< embed::XStorage
>& xStorage
,
925 const OUString
& sEntName
,
926 sal_Int32 nEntryConnectionMode
,
927 const uno::Sequence
< beans::PropertyValue
>& lArguments
,
928 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
930 // the type of the object must be already set
931 // a kind of typedetection should be done in the factory
933 ::osl::MutexGuard
aGuard( m_aMutex
);
935 throw lang::DisposedException(); // TODO
937 if ( !xStorage
.is() )
938 throw lang::IllegalArgumentException( "No parent storage is provided!",
939 static_cast< ::cppu::OWeakObject
* >(this),
942 if ( sEntName
.isEmpty() )
943 throw lang::IllegalArgumentException( "Empty element name is provided!",
944 static_cast< ::cppu::OWeakObject
* >(this),
947 // May be LOADED should be forbidden here ???
948 if ( ( m_nObjectState
!= -1 || nEntryConnectionMode
== embed::EntryInitModes::NO_INIT
)
949 && ( m_nObjectState
== -1 || nEntryConnectionMode
!= embed::EntryInitModes::NO_INIT
) )
951 // if the object is not loaded
952 // it can not get persistent representation without initialization
954 // if the object is loaded
955 // it can switch persistent representation only without initialization
957 throw embed::WrongStateException(
958 "Can't change persistent representation of activated object!",
959 static_cast< ::cppu::OWeakObject
* >(this) );
962 if ( m_bWaitSaveCompleted
)
964 if ( nEntryConnectionMode
!= embed::EntryInitModes::NO_INIT
)
965 throw embed::WrongStateException(
966 "The object waits for saveCompleted() call!",
967 static_cast< ::cppu::OWeakObject
* >(this) );
968 // saveCompleted is expected, handle it accordingly
969 if ( m_xNewParentStorage
== xStorage
&& m_aNewEntryName
== sEntName
)
971 saveCompleted( true );
975 // if a completely different entry is provided, switch first back to the old persistence in saveCompleted
976 // and then switch to the target persistence
977 bool bSwitchFurther
= ( m_xParentStorage
!= xStorage
|| m_aEntryName
!= sEntName
);
978 saveCompleted( false );
979 if ( !bSwitchFurther
)
983 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
984 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
985 // OSL_ENSURE( !m_bIsLinkURL, "This method implementation must not be used for links!" );
988 m_aEntryName
= sEntName
;
992 uno::Reference
< container::XNameAccess
> xNameAccess( xStorage
, uno::UNO_QUERY_THROW
);
994 // detect entry existence
995 bool bElExists
= xNameAccess
->hasByName( sEntName
);
997 m_aDocMediaDescriptor
= GetValuableArgs_Impl( lArguments
,
998 nEntryConnectionMode
!= embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT
);
1000 m_bReadOnly
= false;
1001 for ( beans::PropertyValue
const & prop
: lArguments
)
1002 if ( prop
.Name
== "ReadOnly" )
1003 prop
.Value
>>= m_bReadOnly
;
1005 // TODO: use lObjArgs for StoreVisualReplacement
1006 for ( beans::PropertyValue
const & prop
: lObjArgs
)
1007 if ( prop
.Name
== "OutplaceDispatchInterceptor" )
1009 uno::Reference
< frame::XDispatchProviderInterceptor
> xDispatchInterceptor
;
1010 if ( prop
.Value
>>= xDispatchInterceptor
)
1011 m_xDocHolder
->SetOutplaceDispatchInterceptor( xDispatchInterceptor
);
1013 else if ( prop
.Name
== "DefaultParentBaseURL" )
1015 prop
.Value
>>= m_aDefaultParentBaseURL
;
1017 else if ( prop
.Name
== "Parent" )
1019 prop
.Value
>>= m_xParent
;
1021 else if ( prop
.Name
== "IndividualMiscStatus" )
1023 sal_Int64 nMiscStatus
=0;
1024 prop
.Value
>>= nMiscStatus
;
1025 m_nMiscStatus
|= nMiscStatus
;
1027 else if ( prop
.Name
== "CloneFrom" )
1029 uno::Reference
< embed::XEmbeddedObject
> xObj
;
1030 prop
.Value
>>= xObj
;
1033 m_bHasClonedSize
= true;
1034 m_aClonedSize
= xObj
->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT
);
1035 m_nClonedMapUnit
= xObj
->getMapUnit( embed::Aspects::MSOLE_CONTENT
);
1038 else if ( prop
.Name
== "OutplaceFrameProperties" )
1040 uno::Sequence
< uno::Any
> aOutFrameProps
;
1041 uno::Sequence
< beans::NamedValue
> aOutFramePropsTyped
;
1042 if ( prop
.Value
>>= aOutFrameProps
)
1044 m_xDocHolder
->SetOutplaceFrameProperties( aOutFrameProps
);
1046 else if ( prop
.Value
>>= aOutFramePropsTyped
)
1048 aOutFrameProps
.realloc( aOutFramePropsTyped
.getLength() );
1049 uno::Any
* pProp
= aOutFrameProps
.getArray();
1050 for ( const beans::NamedValue
* pTypedProp
= aOutFramePropsTyped
.getConstArray();
1051 pTypedProp
!= aOutFramePropsTyped
.getConstArray() + aOutFramePropsTyped
.getLength();
1052 ++pTypedProp
, ++pProp
1055 *pProp
<<= *pTypedProp
;
1057 m_xDocHolder
->SetOutplaceFrameProperties( aOutFrameProps
);
1060 SAL_WARN( "embeddedobj.common", "OCommonEmbeddedObject::setPersistentEntry: illegal type for argument 'OutplaceFrameProperties'!" );
1062 else if ( prop
.Name
== "ModuleName" )
1064 prop
.Value
>>= m_aModuleName
;
1066 else if ( prop
.Name
== "EmbeddedScriptSupport" )
1068 OSL_VERIFY( prop
.Value
>>= m_bEmbeddedScriptSupport
);
1070 else if ( prop
.Name
== "DocumentRecoverySupport" )
1072 OSL_VERIFY( prop
.Value
>>= m_bDocumentRecoverySupport
);
1074 else if ( prop
.Name
== "RecoveryStorage" )
1076 OSL_VERIFY( prop
.Value
>>= m_xRecoveryStorage
);
1080 sal_Int32 nStorageMode
= m_bReadOnly
? embed::ElementModes::READ
: embed::ElementModes::READWRITE
;
1082 SwitchOwnPersistence( xStorage
, sEntName
);
1084 if ( nEntryConnectionMode
== embed::EntryInitModes::DEFAULT_INIT
)
1088 // the initialization from existing storage allows to leave object in loaded state
1089 m_nObjectState
= embed::EmbedStates::LOADED
;
1093 m_xDocHolder
->SetComponent( InitNewDocument_Impl(), m_bReadOnly
);
1094 if ( !m_xDocHolder
->GetComponent().is() )
1095 throw io::IOException(); // TODO: can not create document
1097 m_nObjectState
= embed::EmbedStates::RUNNING
;
1102 if ( ( nStorageMode
& embed::ElementModes::READWRITE
) != embed::ElementModes::READWRITE
)
1103 throw io::IOException();
1105 if ( nEntryConnectionMode
== embed::EntryInitModes::NO_INIT
)
1107 // the document just already changed its storage to store to
1108 // the links to OOo documents for now ignore this call
1109 // TODO: OOo links will have persistence so it will be switched here
1111 else if ( nEntryConnectionMode
== embed::EntryInitModes::TRUNCATE_INIT
)
1113 if ( m_xRecoveryStorage
.is() )
1114 TransferMediaType( m_xRecoveryStorage
, m_xObjectStorage
);
1117 m_xDocHolder
->SetComponent( InitNewDocument_Impl(), m_bReadOnly
);
1119 if ( !m_xDocHolder
->GetComponent().is() )
1120 throw io::IOException(); // TODO: can not create document
1122 m_nObjectState
= embed::EmbedStates::RUNNING
;
1124 else if ( nEntryConnectionMode
== embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT
)
1126 m_xDocHolder
->SetComponent( CreateDocFromMediaDescr_Impl( lArguments
), m_bReadOnly
);
1127 m_nObjectState
= embed::EmbedStates::RUNNING
;
1129 //else if ( nEntryConnectionMode == embed::EntryInitModes::TRANSFERABLE_INIT )
1134 throw lang::IllegalArgumentException( "Wrong connection mode is provided!",
1135 static_cast< ::cppu::OWeakObject
* >(this),
1141 void SAL_CALL
OCommonEmbeddedObject::storeToEntry( const uno::Reference
< embed::XStorage
>& xStorage
,
1142 const OUString
& sEntName
,
1143 const uno::Sequence
< beans::PropertyValue
>& lArguments
,
1144 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
1146 ::osl::ResettableMutexGuard
aGuard( m_aMutex
);
1148 throw lang::DisposedException(); // TODO
1150 if ( m_nObjectState
== -1 )
1152 // the object is still not loaded
1153 throw embed::WrongStateException( "Can't store object without persistence!",
1154 static_cast< ::cppu::OWeakObject
* >(this) );
1157 if ( m_bWaitSaveCompleted
)
1158 throw embed::WrongStateException(
1159 "The object waits for saveCompleted() call!",
1160 static_cast< ::cppu::OWeakObject
* >(this) );
1162 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1163 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1164 // OSL_ENSURE( !m_bIsLinkURL, "This method implementation must not be used for links!" );
1168 OSL_ENSURE( m_xParentStorage
.is() && m_xObjectStorage
.is(), "The object has no valid persistence!" );
1170 sal_Int32 nTargetStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1171 sal_Int32 nOriginalStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1173 nTargetStorageFormat
= ::comphelper::OStorageHelper::GetXStorageFormat( xStorage
);
1175 catch ( const beans::IllegalTypeException
& )
1177 // the container just has an unknown type, use current file format
1179 catch ( const uno::Exception
& )
1181 SAL_WARN( "embeddedobj.common", "Can not retrieve target storage media type!" );
1183 if (nTargetStorageFormat
== SOFFICE_FILEFORMAT_60
)
1185 SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1186 nTargetStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1187 // setting MediaType is done later anyway, no need to do it here
1192 nOriginalStorageFormat
= ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage
);
1194 catch ( const beans::IllegalTypeException
& )
1196 // the container just has an unknown type, use current file format
1198 catch ( const uno::Exception
& )
1200 SAL_WARN( "embeddedobj.common", "Can not retrieve own storage media type!" );
1203 bool bTryOptimization
= false;
1204 for ( beans::PropertyValue
const & prop
: lObjArgs
)
1206 // StoreVisualReplacement and VisualReplacement args have no sense here
1207 if ( prop
.Name
== "CanTryOptimization" )
1208 prop
.Value
>>= bTryOptimization
;
1211 bool bSwitchBackToLoaded
= false;
1213 // Storing to different format can be done only in running state.
1214 if ( m_nObjectState
== embed::EmbedStates::LOADED
)
1216 // TODO/LATER: copying is not legal for documents with relative links.
1217 if ( nTargetStorageFormat
== nOriginalStorageFormat
)
1219 bool bOptimizationWorks
= false;
1220 if ( bTryOptimization
)
1224 // try to use optimized copying
1225 uno::Reference
< embed::XOptimizedStorage
> xSource( m_xParentStorage
, uno::UNO_QUERY_THROW
);
1226 uno::Reference
< embed::XOptimizedStorage
> xTarget( xStorage
, uno::UNO_QUERY_THROW
);
1227 xSource
->copyElementDirectlyTo( m_aEntryName
, xTarget
, sEntName
);
1228 bOptimizationWorks
= true;
1230 catch( const uno::Exception
& )
1235 if ( !bOptimizationWorks
)
1236 m_xParentStorage
->copyElementTo( m_aEntryName
, xStorage
, sEntName
);
1240 changeState( embed::EmbedStates::RUNNING
);
1241 bSwitchBackToLoaded
= true;
1245 if ( m_nObjectState
== embed::EmbedStates::LOADED
)
1248 uno::Reference
< embed::XStorage
> xSubStorage
=
1249 xStorage
->openStorageElement( sEntName
, embed::ElementModes::READWRITE
);
1251 if ( !xSubStorage
.is() )
1252 throw uno::RuntimeException(); //TODO
1255 // TODO/LATER: support hierarchical name for embedded objects in embedded objects
1256 StoreDocToStorage_Impl(
1257 xSubStorage
, lArguments
, lObjArgs
, nTargetStorageFormat
, sEntName
, false );
1260 if ( bSwitchBackToLoaded
)
1261 changeState( embed::EmbedStates::LOADED
);
1263 // TODO: should the listener notification be done?
1267 void SAL_CALL
OCommonEmbeddedObject::storeAsEntry( const uno::Reference
< embed::XStorage
>& xStorage
,
1268 const OUString
& sEntName
,
1269 const uno::Sequence
< beans::PropertyValue
>& lArguments
,
1270 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
1272 // TODO: use lObjArgs
1274 ::osl::ResettableMutexGuard
aGuard( m_aMutex
);
1276 throw lang::DisposedException(); // TODO
1278 if ( m_nObjectState
== -1 )
1280 // the object is still not loaded
1281 throw embed::WrongStateException( "Can't store object without persistence!",
1282 static_cast< ::cppu::OWeakObject
* >(this) );
1285 if ( m_bWaitSaveCompleted
)
1286 throw embed::WrongStateException(
1287 "The object waits for saveCompleted() call!",
1288 static_cast< ::cppu::OWeakObject
* >(this) );
1290 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1291 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1292 // OSL_ENSURE( !m_bIsLinkURL, "This method implementation must not be used for links!" );
1295 m_aNewEntryName
= sEntName
;
1297 if(m_aLinkTempFile
.is() && m_bLinkTempFileChanged
)
1299 // tdf#141529 if we have a changed copy of the original OLE data we now
1300 // need to write it back 'over' the original OLE data
1301 uno::Reference
< ucb::XSimpleFileAccess2
> xFileAccess(ucb::SimpleFileAccess::create( m_xContext
));
1302 uno::Reference
< io::XInputStream
> xTempIn
= m_aLinkTempFile
->getInputStream();
1304 // This is *needed* since OTempFileService calls OTempFileService::readBytes which
1305 // ensures the SvStream mpStream gets/is opened, *but* also sets the mnCachedPos from
1306 // OTempFileService which still points to the end-of-file (from write-cc'ing).
1307 uno::Reference
< io::XSeekable
> xSeek( xTempIn
, uno::UNO_QUERY_THROW
);
1310 xFileAccess
->writeFile(m_aLinkURL
, xTempIn
);
1312 // Do *not* close input, that would remove the temporary file too early
1313 // xTempIn->closeInput();
1315 // reset flag m_bLinkTempFileChanged
1316 m_bLinkTempFileChanged
= false;
1322 OSL_ENSURE( m_xParentStorage
.is() && m_xObjectStorage
.is(), "The object has no valid persistence!" );
1324 sal_Int32 nTargetStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1325 sal_Int32 nOriginalStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1327 nTargetStorageFormat
= ::comphelper::OStorageHelper::GetXStorageFormat( xStorage
);
1329 catch ( const beans::IllegalTypeException
& )
1331 // the container just has an unknown type, use current file format
1333 catch ( const uno::Exception
& )
1335 SAL_WARN( "embeddedobj.common", "Can not retrieve target storage media type!" );
1337 if (nTargetStorageFormat
== SOFFICE_FILEFORMAT_60
)
1339 SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1340 nTargetStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1341 // setting MediaType is done later anyway, no need to do it here
1346 nOriginalStorageFormat
= ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage
);
1348 catch ( const beans::IllegalTypeException
& )
1350 // the container just has an unknown type, use current file format
1352 catch ( const uno::Exception
& )
1354 SAL_WARN( "embeddedobj.common", "Can not retrieve own storage media type!" );
1357 PostEvent_Impl( "OnSaveAs" );
1359 bool bTryOptimization
= false;
1360 for ( beans::PropertyValue
const & prop
: lObjArgs
)
1362 // StoreVisualReplacement and VisualReplacement args have no sense here
1363 if ( prop
.Name
== "CanTryOptimization" )
1364 prop
.Value
>>= bTryOptimization
;
1367 bool bSwitchBackToLoaded
= false;
1369 // Storing to different format can be done only in running state.
1370 if ( m_nObjectState
== embed::EmbedStates::LOADED
)
1372 // TODO/LATER: copying is not legal for documents with relative links.
1373 if ( nTargetStorageFormat
== nOriginalStorageFormat
)
1375 bool bOptimizationWorks
= false;
1376 if ( bTryOptimization
)
1380 // try to use optimized copying
1381 uno::Reference
< embed::XOptimizedStorage
> xSource( m_xParentStorage
, uno::UNO_QUERY_THROW
);
1382 uno::Reference
< embed::XOptimizedStorage
> xTarget( xStorage
, uno::UNO_QUERY_THROW
);
1383 xSource
->copyElementDirectlyTo( m_aEntryName
, xTarget
, sEntName
);
1384 bOptimizationWorks
= true;
1386 catch( const uno::Exception
& )
1391 if ( !bOptimizationWorks
)
1392 m_xParentStorage
->copyElementTo( m_aEntryName
, xStorage
, sEntName
);
1396 changeState( embed::EmbedStates::RUNNING
);
1397 bSwitchBackToLoaded
= true;
1401 uno::Reference
< embed::XStorage
> xSubStorage
=
1402 xStorage
->openStorageElement( sEntName
, embed::ElementModes::READWRITE
);
1404 if ( !xSubStorage
.is() )
1405 throw uno::RuntimeException(); //TODO
1407 if ( m_nObjectState
!= embed::EmbedStates::LOADED
)
1410 // TODO/LATER: support hierarchical name for embedded objects in embedded objects
1411 StoreDocToStorage_Impl(
1412 xSubStorage
, lArguments
, lObjArgs
, nTargetStorageFormat
, sEntName
, false );
1415 if ( bSwitchBackToLoaded
)
1416 changeState( embed::EmbedStates::LOADED
);
1419 m_bWaitSaveCompleted
= true;
1420 m_xNewObjectStorage
= xSubStorage
;
1421 m_xNewParentStorage
= xStorage
;
1422 m_aNewEntryName
= sEntName
;
1423 m_aNewDocMediaDescriptor
= GetValuableArgs_Impl( lArguments
, true );
1425 // TODO: register listeners for storages above, in case they are disposed
1426 // an exception will be thrown on saveCompleted( true )
1428 // TODO: should the listener notification be done here or in saveCompleted?
1432 void SAL_CALL
OCommonEmbeddedObject::saveCompleted( sal_Bool bUseNew
)
1434 ::osl::MutexGuard
aGuard( m_aMutex
);
1436 throw lang::DisposedException(); // TODO
1438 if ( m_nObjectState
== -1 )
1440 // the object is still not loaded
1441 throw embed::WrongStateException( "Can't store object without persistence!",
1442 static_cast< ::cppu::OWeakObject
* >(this) );
1445 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1446 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1447 // OSL_ENSURE( !m_bIsLinkURL, "This method implementation must not be used for links!" );
1451 m_aEntryName
= m_aNewEntryName
;
1452 m_aNewEntryName
.clear();
1456 // it is allowed to call saveCompleted( false ) for nonstored objects
1457 if ( !m_bWaitSaveCompleted
&& !bUseNew
)
1460 SAL_WARN_IF( !m_bWaitSaveCompleted
, "embeddedobj.common", "Unexpected saveCompleted() call!" );
1461 if ( !m_bWaitSaveCompleted
)
1462 throw io::IOException(); // TODO: illegal call
1464 OSL_ENSURE( m_xNewObjectStorage
.is() && m_xNewParentStorage
.is() , "Internal object information is broken!" );
1465 if ( !m_xNewObjectStorage
.is() || !m_xNewParentStorage
.is() )
1466 throw uno::RuntimeException(); // TODO: broken internal information
1470 SwitchOwnPersistence( m_xNewParentStorage
, m_xNewObjectStorage
, m_aNewEntryName
);
1471 m_aDocMediaDescriptor
= m_aNewDocMediaDescriptor
;
1473 uno::Reference
< util::XModifiable
> xModif( m_xDocHolder
->GetComponent(), uno::UNO_QUERY
);
1475 xModif
->setModified( false );
1477 PostEvent_Impl( "OnSaveAsDone");
1482 m_xNewObjectStorage
->dispose();
1484 catch ( const uno::Exception
& )
1489 m_xNewObjectStorage
.clear();
1490 m_xNewParentStorage
.clear();
1491 m_aNewEntryName
.clear();
1492 m_aNewDocMediaDescriptor
.realloc( 0 );
1493 m_bWaitSaveCompleted
= false;
1497 // TODO: notify listeners
1499 if ( m_nUpdateMode
== embed::EmbedUpdateModes::ALWAYS_UPDATE
)
1501 // TODO: update visual representation
1507 sal_Bool SAL_CALL
OCommonEmbeddedObject::hasEntry()
1509 ::osl::MutexGuard
aGuard( m_aMutex
);
1511 throw lang::DisposedException(); // TODO
1513 if ( m_bWaitSaveCompleted
)
1514 throw embed::WrongStateException(
1515 "The object waits for saveCompleted() call!",
1516 static_cast< ::cppu::OWeakObject
* >(this) );
1518 if ( m_xObjectStorage
.is() )
1525 OUString SAL_CALL
OCommonEmbeddedObject::getEntryName()
1527 ::osl::MutexGuard
aGuard( m_aMutex
);
1529 throw lang::DisposedException(); // TODO
1531 if ( m_nObjectState
== -1 )
1533 // the object is still not loaded
1534 throw embed::WrongStateException( "The object persistence is not initialized!",
1535 static_cast< ::cppu::OWeakObject
* >(this) );
1538 if ( m_bWaitSaveCompleted
)
1539 throw embed::WrongStateException(
1540 "The object waits for saveCompleted() call!",
1541 static_cast< ::cppu::OWeakObject
* >(this) );
1543 return m_aEntryName
;
1547 void SAL_CALL
OCommonEmbeddedObject::storeOwn()
1549 // during switching from Activated to Running and from Running to Loaded states the object will
1550 // ask container to store the object, the container has to make decision
1553 ::osl::ResettableMutexGuard
aGuard( m_aMutex
);
1555 throw lang::DisposedException(); // TODO
1557 if ( m_nObjectState
== -1 )
1559 // the object is still not loaded
1560 throw embed::WrongStateException( "Can't store object without persistence!",
1561 static_cast< ::cppu::OWeakObject
* >(this) );
1564 if ( m_bWaitSaveCompleted
)
1565 throw embed::WrongStateException(
1566 "The object waits for saveCompleted() call!",
1567 static_cast< ::cppu::OWeakObject
* >(this) );
1570 throw io::IOException(); // TODO: access denied
1572 // nothing to do, if the object is in loaded state
1573 if ( m_nObjectState
== embed::EmbedStates::LOADED
)
1576 PostEvent_Impl( "OnSave" );
1578 SAL_WARN_IF( !m_xDocHolder
->GetComponent().is(), "embeddedobj.common", "If an object is activated or in running state it must have a document!" );
1579 if ( !m_xDocHolder
->GetComponent().is() )
1580 throw uno::RuntimeException();
1584 // TODO: just store the document to its location
1585 uno::Reference
< frame::XStorable
> xStorable( m_xDocHolder
->GetComponent(), uno::UNO_QUERY_THROW
);
1587 // free the main mutex for the storing time
1596 OSL_ENSURE( m_xParentStorage
.is() && m_xObjectStorage
.is(), "The object has no valid persistence!" );
1598 if ( !m_xObjectStorage
.is() )
1599 throw io::IOException(); //TODO: access denied
1601 sal_Int32 nStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1603 nStorageFormat
= ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage
);
1605 catch ( const beans::IllegalTypeException
& )
1607 // the container just has an unknown type, use current file format
1609 catch ( const uno::Exception
& )
1611 SAL_WARN( "embeddedobj.common", "Can not retrieve storage media type!" );
1613 if (nStorageFormat
== SOFFICE_FILEFORMAT_60
)
1615 SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1616 nStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1617 // setting MediaType is done later anyway, no need to do it here
1621 uno::Sequence
<beans::PropertyValue
> aEmpty
;
1622 uno::Sequence
<beans::PropertyValue
> aMediaArgs(1);
1623 aMediaArgs
[0].Name
= "DocumentBaseURL";
1624 aMediaArgs
[0].Value
<<= GetBaseURL_Impl();
1625 StoreDocToStorage_Impl( m_xObjectStorage
, aMediaArgs
, aEmpty
, nStorageFormat
, m_aEntryName
, true );
1629 uno::Reference
< util::XModifiable
> xModif( m_xDocHolder
->GetComponent(), uno::UNO_QUERY
);
1631 xModif
->setModified( false );
1633 PostEvent_Impl( "OnSaveDone" );
1637 sal_Bool SAL_CALL
OCommonEmbeddedObject::isReadonly()
1639 ::osl::MutexGuard
aGuard( m_aMutex
);
1641 throw lang::DisposedException(); // TODO
1643 if ( m_nObjectState
== -1 )
1645 // the object is still not loaded
1646 throw embed::WrongStateException( "The object persistence is not initialized!",
1647 static_cast< ::cppu::OWeakObject
* >(this) );
1650 if ( m_bWaitSaveCompleted
)
1651 throw embed::WrongStateException(
1652 "The object waits for saveCompleted() call!",
1653 static_cast< ::cppu::OWeakObject
* >(this) );
1659 void SAL_CALL
OCommonEmbeddedObject::reload(
1660 const uno::Sequence
< beans::PropertyValue
>& lArguments
,
1661 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
1663 // TODO: use lObjArgs
1664 // for now this method is used only to switch readonly state
1666 ::osl::MutexGuard
aGuard( m_aMutex
);
1668 throw lang::DisposedException(); // TODO
1670 if ( m_nObjectState
== -1 )
1672 // the object is still not loaded
1673 throw embed::WrongStateException( "The object persistence is not initialized!",
1674 static_cast< ::cppu::OWeakObject
* >(this) );
1677 if ( m_nObjectState
!= embed::EmbedStates::LOADED
)
1679 // the object is still not loaded
1680 throw embed::WrongStateException(
1681 "The object must be in loaded state to be reloaded!",
1682 static_cast< ::cppu::OWeakObject
* >(this) );
1685 if ( m_bWaitSaveCompleted
)
1686 throw embed::WrongStateException(
1687 "The object waits for saveCompleted() call!",
1688 static_cast< ::cppu::OWeakObject
* >(this) );
1692 // reload of the link
1693 OUString aOldLinkFilter
= m_aLinkFilterName
;
1695 OUString aNewLinkFilter
;
1696 for ( beans::PropertyValue
const & prop
: lArguments
)
1698 if ( prop
.Name
== "URL" )
1701 prop
.Value
>>= m_aLinkURL
;
1702 m_aLinkFilterName
.clear();
1704 else if ( prop
.Name
== "FilterName" )
1706 prop
.Value
>>= aNewLinkFilter
;
1707 m_aLinkFilterName
.clear();
1711 ::comphelper::MimeConfigurationHelper
aHelper( m_xContext
);
1712 if ( m_aLinkFilterName
.isEmpty() )
1714 if ( !aNewLinkFilter
.isEmpty() )
1715 m_aLinkFilterName
= aNewLinkFilter
;
1718 uno::Sequence
< beans::PropertyValue
> aArgs( 1 );
1719 aArgs
[0].Name
= "URL";
1720 aArgs
[0].Value
<<= m_aLinkURL
;
1721 m_aLinkFilterName
= aHelper
.UpdateMediaDescriptorWithFilterName( aArgs
, false );
1725 if ( aOldLinkFilter
!= m_aLinkFilterName
)
1727 uno::Sequence
< beans::NamedValue
> aObject
= aHelper
.GetObjectPropsByFilter( m_aLinkFilterName
);
1729 // TODO/LATER: probably the document holder could be cleaned explicitly as in the destructor
1730 m_xDocHolder
.clear();
1732 LinkInit_Impl( aObject
, lArguments
, lObjArgs
);
1736 m_aDocMediaDescriptor
= GetValuableArgs_Impl( lArguments
, true );
1738 // TODO: use lObjArgs for StoreVisualReplacement
1739 for ( beans::PropertyValue
const & prop
: lObjArgs
)
1740 if ( prop
.Name
== "OutplaceDispatchInterceptor" )
1742 uno::Reference
< frame::XDispatchProviderInterceptor
> xDispatchInterceptor
;
1743 if ( prop
.Value
>>= xDispatchInterceptor
)
1744 m_xDocHolder
->SetOutplaceDispatchInterceptor( xDispatchInterceptor
);
1750 // when document allows reloading through API the object can be reloaded not only in loaded state
1752 bool bOldReadOnlyValue
= m_bReadOnly
;
1754 m_bReadOnly
= false;
1755 for ( beans::PropertyValue
const & prop
: lArguments
)
1756 if ( prop
.Name
== "ReadOnly" )
1757 prop
.Value
>>= m_bReadOnly
;
1759 if ( bOldReadOnlyValue
== m_bReadOnly
|| m_bIsLinkURL
)
1762 // close own storage
1764 if ( m_xObjectStorage
.is() )
1765 m_xObjectStorage
->dispose();
1767 catch ( const uno::Exception
& )
1771 sal_Int32 nStorageMode
= m_bReadOnly
? embed::ElementModes::READ
: embed::ElementModes::READWRITE
;
1772 m_xObjectStorage
= m_xParentStorage
->openStorageElement( m_aEntryName
, nStorageMode
);
1775 sal_Bool SAL_CALL
OCommonEmbeddedObject::isStored()
1777 if (!m_xObjectStorage
.is())
1780 return m_xObjectStorage
->getElementNames().hasElements();
1784 void SAL_CALL
OCommonEmbeddedObject::breakLink( const uno::Reference
< embed::XStorage
>& xStorage
,
1785 const OUString
& sEntName
)
1787 ::osl::ResettableMutexGuard
aGuard( m_aMutex
);
1789 throw lang::DisposedException(); // TODO
1791 if (!m_bIsLinkURL
|| m_nObjectState
== -1)
1793 // it must be a linked initialized object
1794 throw embed::WrongStateException(
1795 "The object is not a valid linked object!",
1796 static_cast< ::cppu::OWeakObject
* >(this) );
1798 // the current implementation of OOo links does not implement this method since it does not implement
1799 // all the set of interfaces required for OOo embedded object ( XEmbedPersist is not supported ).
1801 if ( !xStorage
.is() )
1802 throw lang::IllegalArgumentException( "No parent storage is provided!",
1803 static_cast< ::cppu::OWeakObject
* >(this),
1806 if ( sEntName
.isEmpty() )
1807 throw lang::IllegalArgumentException( "Empty element name is provided!",
1808 static_cast< ::cppu::OWeakObject
* >(this),
1811 if ( m_bWaitSaveCompleted
)
1812 throw embed::WrongStateException(
1813 "The object waits for saveCompleted() call!",
1814 static_cast< ::cppu::OWeakObject
* >(this) );
1816 uno::Reference
< container::XNameAccess
> xNameAccess( xStorage
, uno::UNO_QUERY_THROW
);
1818 m_bReadOnly
= false;
1820 if ( m_xParentStorage
!= xStorage
|| m_aEntryName
!= sEntName
)
1821 SwitchOwnPersistence( xStorage
, sEntName
);
1823 // for linked object it means that it becomes embedded object
1824 // the document must switch it's persistence also
1826 // TODO/LATER: handle the case when temp doc can not be created
1827 // the document is a new embedded object so it must be marked as modified
1828 uno::Reference
< util::XCloseable
> xDocument
= CreateTempDocFromLink_Impl();
1831 if(m_xDocHolder
.is() && m_xDocHolder
->GetComponent().is())
1833 // tdf#141528 m_xDocHolder->GetComponent() may be not set, so add it
1834 // to the try path to not get thrown out of the local context to the next
1835 // highter try...catch on the stack. To make breakLink work it is
1836 // *necessary* to execute the code below that resets the linked state,
1837 // esp. the *.clear stuff and resetting m_bIsLink.
1838 uno::Reference
< util::XModifiable
> xModif( m_xDocHolder
->GetComponent(), uno::UNO_QUERY_THROW
);
1840 // all other locations in this file check for xModif.is(), so do it here, too
1842 xModif
->setModified( true );
1845 catch( const uno::Exception
& )
1848 m_xDocHolder
->SetComponent( xDocument
, m_bReadOnly
);
1849 SAL_WARN_IF( !m_xDocHolder
->GetComponent().is(), "embeddedobj.common", "If document can't be created, an exception must be thrown!" );
1851 if ( m_nObjectState
== embed::EmbedStates::LOADED
)
1853 // the state is changed and can not be switched to loaded state back without saving
1854 m_nObjectState
= embed::EmbedStates::RUNNING
;
1855 StateChangeNotification_Impl( false, embed::EmbedStates::LOADED
, m_nObjectState
, aGuard
);
1857 else if ( m_nObjectState
== embed::EmbedStates::ACTIVE
)
1858 m_xDocHolder
->Show();
1860 // tdf#141529 reset all stuff involved in linked state, including
1861 // the OLE content copied to the temp file
1862 m_bIsLinkURL
= false;
1863 m_aLinkTempFile
.clear();
1864 m_aLinkFilterName
.clear();
1869 sal_Bool SAL_CALL
OCommonEmbeddedObject::isLink()
1871 ::osl::MutexGuard
aGuard( m_aMutex
);
1873 throw lang::DisposedException(); // TODO
1875 return m_bIsLinkURL
;
1879 OUString SAL_CALL
OCommonEmbeddedObject::getLinkURL()
1881 ::osl::MutexGuard
aGuard( m_aMutex
);
1883 throw lang::DisposedException(); // TODO
1885 if ( !m_bIsLinkURL
)
1886 throw embed::WrongStateException(
1887 "The object is not a link object!",
1888 static_cast< ::cppu::OWeakObject
* >(this) );
1893 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */