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/EmbedVerbs.hpp>
25 #include <com/sun/star/embed/EntryInitModes.hpp>
26 #include <com/sun/star/embed/StorageWrappedTargetException.hpp>
27 #include <com/sun/star/embed/WrongStateException.hpp>
28 #include <com/sun/star/embed/XStorage.hpp>
29 #include <com/sun/star/embed/XOptimizedStorage.hpp>
30 #include <com/sun/star/embed/ElementModes.hpp>
31 #include <com/sun/star/embed/EmbedUpdateModes.hpp>
32 #include <com/sun/star/embed/StorageFactory.hpp>
33 #include <com/sun/star/io/IOException.hpp>
34 #include <com/sun/star/io/TempFile.hpp>
35 #include <com/sun/star/frame/XModel.hpp>
36 #include <com/sun/star/frame/XStorable.hpp>
37 #include <com/sun/star/frame/XLoadable.hpp>
38 #include <com/sun/star/frame/XModule.hpp>
39 #include <com/sun/star/lang/NoSupportException.hpp>
40 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
41 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
42 #include <com/sun/star/lang/DisposedException.hpp>
43 #include <com/sun/star/util/XModifiable.hpp>
45 #include <com/sun/star/container/XNameAccess.hpp>
46 #include <com/sun/star/container/XChild.hpp>
47 #include <com/sun/star/util/XCloseable.hpp>
48 #include <com/sun/star/beans/XPropertySet.hpp>
49 #include <com/sun/star/beans/IllegalTypeException.hpp>
50 #include <com/sun/star/chart2/XChartDocument.hpp>
52 #include <comphelper/fileformat.h>
53 #include <comphelper/storagehelper.hxx>
54 #include <comphelper/mimeconfighelper.hxx>
55 #include <comphelper/namedvaluecollection.hxx>
57 #include <tools/diagnose_ex.h>
58 #include <sal/log.hxx>
59 #include <unotools/configmgr.hxx>
60 #include "persistence.hxx"
62 using namespace ::com::sun::star
;
65 uno::Sequence
< beans::PropertyValue
> GetValuableArgs_Impl( const uno::Sequence
< beans::PropertyValue
>& aMedDescr
,
66 bool bCanUseDocumentBaseURL
)
68 uno::Sequence
< beans::PropertyValue
> aResult
;
69 sal_Int32 nResLen
= 0;
71 for ( sal_Int32 nInd
= 0; nInd
< aMedDescr
.getLength(); nInd
++ )
73 if ( aMedDescr
[nInd
].Name
== "ComponentData" || aMedDescr
[nInd
].Name
== "DocumentTitle"
74 || aMedDescr
[nInd
].Name
== "InteractionHandler" || aMedDescr
[nInd
].Name
== "JumpMark"
75 // || aMedDescr[nInd].Name == "Password" // makes no sense for embedded objects
76 || aMedDescr
[nInd
].Name
== "Preview" || aMedDescr
[nInd
].Name
== "ReadOnly"
77 || aMedDescr
[nInd
].Name
== "StartPresentation" || aMedDescr
[nInd
].Name
== "RepairPackage"
78 || aMedDescr
[nInd
].Name
== "StatusIndicator" || aMedDescr
[nInd
].Name
== "ViewData"
79 || aMedDescr
[nInd
].Name
== "ViewId" || aMedDescr
[nInd
].Name
== "MacroExecutionMode"
80 || aMedDescr
[nInd
].Name
== "UpdateDocMode"
81 || (aMedDescr
[nInd
].Name
== "DocumentBaseURL" && bCanUseDocumentBaseURL
) )
83 aResult
.realloc( ++nResLen
);
84 aResult
[nResLen
-1] = aMedDescr
[nInd
];
92 static uno::Sequence
< beans::PropertyValue
> addAsTemplate( const uno::Sequence
< beans::PropertyValue
>& aOrig
)
94 bool bAsTemplateSet
= false;
95 sal_Int32 nLength
= aOrig
.getLength();
96 uno::Sequence
< beans::PropertyValue
> aResult( nLength
);
98 for ( sal_Int32 nInd
= 0; nInd
< nLength
; nInd
++ )
100 aResult
[nInd
].Name
= aOrig
[nInd
].Name
;
101 if ( aResult
[nInd
].Name
== "AsTemplate" )
103 aResult
[nInd
].Value
<<= true;
104 bAsTemplateSet
= true;
107 aResult
[nInd
].Value
= aOrig
[nInd
].Value
;
110 if ( !bAsTemplateSet
)
112 aResult
.realloc( nLength
+ 1 );
113 aResult
[nLength
].Name
= "AsTemplate";
114 aResult
[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( 2 );
134 aArgs
[0] <<= xTempStream
;
135 aArgs
[1] <<= embed::ElementModes::READWRITE
;
136 uno::Reference
< embed::XStorage
> xTempStorage( xStorageFactory
->createInstanceWithArguments( aArgs
),
137 uno::UNO_QUERY_THROW
);
141 xStorage
->copyToStorage( xTempStorage
);
142 } catch( const uno::Exception
& )
144 css::uno::Any anyEx
= cppu::getCaughtException();
145 throw embed::StorageWrappedTargetException(
146 "Can't copy storage!",
147 uno::Reference
< uno::XInterface
>(),
152 uno::Reference
< lang::XComponent
> xComponent( xTempStorage
, uno::UNO_QUERY
);
153 SAL_WARN_IF( !xComponent
.is(), "embeddedobj.common", "Wrong storage implementation!" );
154 if ( xComponent
.is() )
155 xComponent
->dispose();
157 catch ( const uno::Exception
& )
162 uno::Reference
< io::XOutputStream
> xTempOut
= xTempStream
->getOutputStream();
164 xTempOut
->closeOutput();
166 catch ( const uno::Exception
& )
170 xResult
= xTempStream
->getInputStream();
177 static void TransferMediaType( const uno::Reference
< embed::XStorage
>& i_rSource
, const uno::Reference
< embed::XStorage
>& i_rTarget
)
181 const uno::Reference
< beans::XPropertySet
> xSourceProps( i_rSource
, uno::UNO_QUERY_THROW
);
182 const uno::Reference
< beans::XPropertySet
> xTargetProps( i_rTarget
, uno::UNO_QUERY_THROW
);
183 const OUString
sMediaTypePropName( "MediaType" );
184 xTargetProps
->setPropertyValue( sMediaTypePropName
, xSourceProps
->getPropertyValue( sMediaTypePropName
) );
186 catch( const uno::Exception
& )
188 DBG_UNHANDLED_EXCEPTION("embeddedobj.common");
193 static uno::Reference
< util::XCloseable
> CreateDocument( const uno::Reference
< uno::XComponentContext
>& _rxContext
,
194 const OUString
& _rDocumentServiceName
, bool _bEmbeddedScriptSupport
, const bool i_bDocumentRecoverySupport
)
196 ::comphelper::NamedValueCollection aArguments
;
197 aArguments
.put( "EmbeddedObject", true );
198 aArguments
.put( "EmbeddedScriptSupport", _bEmbeddedScriptSupport
);
199 aArguments
.put( "DocumentRecoverySupport", 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
)
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
& )
245 void OCommonEmbeddedObject::SwitchOwnPersistence( const uno::Reference
< embed::XStorage
>& xNewParentStorage
,
246 const uno::Reference
< embed::XStorage
>& xNewObjectStorage
,
247 const OUString
& aNewName
)
249 if ( xNewParentStorage
== m_xParentStorage
&& aNewName
== m_aEntryName
)
251 SAL_WARN_IF( xNewObjectStorage
!= m_xObjectStorage
, "embeddedobj.common", "The storage must be the same!" );
255 uno::Reference
< lang::XComponent
> xComponent( m_xObjectStorage
, uno::UNO_QUERY
);
256 OSL_ENSURE( !m_xObjectStorage
.is() || xComponent
.is(), "Wrong storage implementation!" );
258 m_xObjectStorage
= xNewObjectStorage
;
259 m_xParentStorage
= xNewParentStorage
;
260 m_aEntryName
= aNewName
;
262 // the linked document should not be switched
265 uno::Reference
< document::XStorageBasedDocument
> xDoc( m_xDocHolder
->GetComponent(), uno::UNO_QUERY
);
267 SwitchDocToStorage_Impl( xDoc
, m_xObjectStorage
);
271 if ( xComponent
.is() )
272 xComponent
->dispose();
274 catch ( const uno::Exception
& )
280 void OCommonEmbeddedObject::SwitchOwnPersistence( const uno::Reference
< embed::XStorage
>& xNewParentStorage
,
281 const OUString
& aNewName
)
283 if ( xNewParentStorage
== m_xParentStorage
&& aNewName
== m_aEntryName
)
286 sal_Int32 nStorageMode
= m_bReadOnly
? embed::ElementModes::READ
: embed::ElementModes::READWRITE
;
288 uno::Reference
< embed::XStorage
> xNewOwnStorage
= xNewParentStorage
->openStorageElement( aNewName
, nStorageMode
);
289 SAL_WARN_IF( !xNewOwnStorage
.is(), "embeddedobj.common", "The method can not return empty reference!" );
291 SwitchOwnPersistence( xNewParentStorage
, xNewOwnStorage
, aNewName
);
295 void OCommonEmbeddedObject::EmbedAndReparentDoc_Impl( const uno::Reference
< util::XCloseable
>& i_rxDocument
) const
297 SetDocToEmbedded( uno::Reference
< frame::XModel
>( i_rxDocument
, uno::UNO_QUERY
), m_aModuleName
);
301 uno::Reference
< container::XChild
> xChild( i_rxDocument
, uno::UNO_QUERY
);
303 xChild
->setParent( m_xParent
);
305 catch( const lang::NoSupportException
& )
307 SAL_WARN( "embeddedobj.common", "OCommonEmbeddedObject::EmbedAndReparentDoc: cannot set parent at document!" );
312 uno::Reference
< util::XCloseable
> OCommonEmbeddedObject::InitNewDocument_Impl()
314 uno::Reference
< util::XCloseable
> xDocument( CreateDocument( m_xContext
, GetDocumentServiceName(),
315 m_bEmbeddedScriptSupport
, m_bDocumentRecoverySupport
) );
317 uno::Reference
< frame::XModel
> xModel( xDocument
, uno::UNO_QUERY
);
318 uno::Reference
< frame::XLoadable
> xLoadable( xModel
, uno::UNO_QUERY_THROW
);
322 // set the document mode to embedded as the first action on document!!!
323 EmbedAndReparentDoc_Impl( xDocument
);
325 // if we have a storage to recover the document from, do not use initNew, but instead load from that storage
326 bool bInitNew
= true;
327 if ( m_xRecoveryStorage
.is() )
329 uno::Reference
< document::XStorageBasedDocument
> xDoc( xLoadable
, uno::UNO_QUERY
);
330 SAL_WARN_IF( !xDoc
.is(), "embeddedobj.common", "OCommonEmbeddedObject::InitNewDocument_Impl: cannot recover from a storage when the document is not storage based!" );
333 ::comphelper::NamedValueCollection aLoadArgs
;
334 FillDefaultLoadArgs_Impl( m_xRecoveryStorage
, aLoadArgs
);
336 xDoc
->loadFromStorage( m_xRecoveryStorage
, aLoadArgs
.getPropertyValues() );
337 SwitchDocToStorage_Impl( xDoc
, m_xObjectStorage
);
344 // init document as a new
345 xLoadable
->initNew();
347 xModel
->attachResource( xModel
->getURL(), m_aDocMediaDescriptor
);
349 catch( const uno::Exception
& )
351 uno::Reference
< util::XCloseable
> xCloseable( xDocument
, uno::UNO_QUERY
);
352 if ( xCloseable
.is() )
356 xCloseable
->close( true );
358 catch( const uno::Exception
& )
370 uno::Reference
< util::XCloseable
> OCommonEmbeddedObject::LoadLink_Impl()
372 uno::Reference
< util::XCloseable
> xDocument( CreateDocument( m_xContext
, GetDocumentServiceName(),
373 m_bEmbeddedScriptSupport
, m_bDocumentRecoverySupport
) );
375 uno::Reference
< frame::XLoadable
> xLoadable( xDocument
, uno::UNO_QUERY_THROW
);
378 uno::Sequence
< beans::PropertyValue
> aArgs( nLen
);
379 aArgs
[0].Name
= "URL";
380 aArgs
[0].Value
<<= m_aLinkURL
;
381 aArgs
[1].Name
= "FilterName";
382 aArgs
[1].Value
<<= m_aLinkFilterName
;
383 if ( m_bLinkHasPassword
)
385 aArgs
.realloc( ++nLen
);
386 aArgs
[nLen
-1].Name
= "Password";
387 aArgs
[nLen
-1].Value
<<= m_aLinkPassword
;
390 aArgs
.realloc( m_aDocMediaDescriptor
.getLength() + nLen
);
391 for ( sal_Int32 nInd
= 0; nInd
< m_aDocMediaDescriptor
.getLength(); nInd
++ )
393 aArgs
[nInd
+nLen
].Name
= m_aDocMediaDescriptor
[nInd
].Name
;
394 aArgs
[nInd
+nLen
].Value
= m_aDocMediaDescriptor
[nInd
].Value
;
399 // the document is not really an embedded one, it is a link
400 EmbedAndReparentDoc_Impl( xDocument
);
403 xLoadable
->load( aArgs
);
405 if ( !m_bLinkHasPassword
)
407 // check if there is a password to cache
408 uno::Reference
< frame::XModel
> xModel( xLoadable
, uno::UNO_QUERY_THROW
);
409 uno::Sequence
< beans::PropertyValue
> aProps
= xModel
->getArgs();
410 for ( sal_Int32 nInd
= 0; nInd
< aProps
.getLength(); nInd
++ )
411 if ( aProps
[nInd
].Name
== "Password" && ( aProps
[nInd
].Value
>>= m_aLinkPassword
) )
413 m_bLinkHasPassword
= true;
418 catch( const uno::Exception
& )
420 uno::Reference
< util::XCloseable
> xCloseable( xDocument
, uno::UNO_QUERY
);
421 if ( xCloseable
.is() )
425 xCloseable
->close( true );
427 catch( const uno::Exception
& )
440 OUString
OCommonEmbeddedObject::GetFilterName( sal_Int32 nVersion
) const
442 OUString aFilterName
= GetPresetFilterName();
443 if ( aFilterName
.isEmpty() )
445 OUString sDocumentServiceName
= GetDocumentServiceName();
446 if (utl::ConfigManager::IsFuzzing() && nVersion
== SOFFICE_FILEFORMAT_CURRENT
&&
447 sDocumentServiceName
== "com.sun.star.chart2.ChartDocument")
449 return OUString("chart8");
452 ::comphelper::MimeConfigurationHelper
aHelper( m_xContext
);
453 aFilterName
= aHelper
.GetDefaultFilterFromServiceName(sDocumentServiceName
, nVersion
);
455 // If no filter is found, fall back to the FileFormatVersion=6200 filter, Base only has that.
456 if (aFilterName
.isEmpty() && nVersion
== SOFFICE_FILEFORMAT_CURRENT
)
457 aFilterName
= aHelper
.GetDefaultFilterFromServiceName(GetDocumentServiceName(), SOFFICE_FILEFORMAT_60
);
458 } catch( const uno::Exception
& )
466 void OCommonEmbeddedObject::FillDefaultLoadArgs_Impl( const uno::Reference
< embed::XStorage
>& i_rxStorage
,
467 ::comphelper::NamedValueCollection
& o_rLoadArgs
) const
469 o_rLoadArgs
.put( "DocumentBaseURL", GetBaseURL_Impl() );
470 o_rLoadArgs
.put( "HierarchicalDocumentName", m_aEntryName
);
471 o_rLoadArgs
.put( "ReadOnly", m_bReadOnly
);
473 OUString aFilterName
= GetFilterName( ::comphelper::OStorageHelper::GetXStorageFormat( i_rxStorage
) );
474 SAL_WARN_IF( aFilterName
.isEmpty(), "embeddedobj.common", "OCommonEmbeddedObject::FillDefaultLoadArgs_Impl: Wrong document service name!" );
475 if ( aFilterName
.isEmpty() )
476 throw io::IOException(); // TODO: error message/code
478 o_rLoadArgs
.put( "FilterName", aFilterName
);
482 uno::Reference
< util::XCloseable
> OCommonEmbeddedObject::LoadDocumentFromStorage_Impl()
484 ENSURE_OR_THROW( m_xObjectStorage
.is(), "no object storage" );
486 const uno::Reference
< embed::XStorage
> xSourceStorage( m_xRecoveryStorage
.is() ? m_xRecoveryStorage
: m_xObjectStorage
);
488 uno::Reference
< util::XCloseable
> xDocument( CreateDocument( m_xContext
, GetDocumentServiceName(),
489 m_bEmbeddedScriptSupport
, m_bDocumentRecoverySupport
) );
491 //#i103460# ODF: take the size given from the parent frame as default
492 uno::Reference
< chart2::XChartDocument
> xChart( xDocument
, uno::UNO_QUERY
);
495 uno::Reference
< embed::XVisualObject
> xChartVisualObject( xChart
, uno::UNO_QUERY
);
496 if( xChartVisualObject
.is() )
497 xChartVisualObject
->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT
, m_aDefaultSizeForChart_In_100TH_MM
);
500 uno::Reference
< frame::XLoadable
> xLoadable( xDocument
, uno::UNO_QUERY
);
501 uno::Reference
< document::XStorageBasedDocument
> xDoc( xDocument
, uno::UNO_QUERY
);
502 if ( !xDoc
.is() && !xLoadable
.is() )
503 throw uno::RuntimeException();
505 ::comphelper::NamedValueCollection aLoadArgs
;
506 FillDefaultLoadArgs_Impl( xSourceStorage
, aLoadArgs
);
508 uno::Reference
< io::XInputStream
> xTempInpStream
;
511 xTempInpStream
= createTempInpStreamFromStor( xSourceStorage
, m_xContext
);
512 if ( !xTempInpStream
.is() )
513 throw uno::RuntimeException();
515 OUString aTempFileURL
;
518 // no need to let the file stay after the stream is removed since the embedded document
519 // can not be stored directly
520 uno::Reference
< beans::XPropertySet
> xTempStreamProps( xTempInpStream
, uno::UNO_QUERY_THROW
);
521 xTempStreamProps
->getPropertyValue("Uri") >>= aTempFileURL
;
523 catch( const uno::Exception
& )
527 SAL_WARN_IF( aTempFileURL
.isEmpty(), "embeddedobj.common", "Couldn't retrieve temporary file URL!" );
529 aLoadArgs
.put( "URL", aTempFileURL
);
530 aLoadArgs
.put( "InputStream", xTempInpStream
);
534 aLoadArgs
.merge( m_aDocMediaDescriptor
, true );
538 // set the document mode to embedded as the first step!!!
539 EmbedAndReparentDoc_Impl( xDocument
);
543 xDoc
->loadFromStorage( xSourceStorage
, aLoadArgs
.getPropertyValues() );
544 if ( xSourceStorage
!= m_xObjectStorage
)
545 SwitchDocToStorage_Impl( xDoc
, m_xObjectStorage
);
548 xLoadable
->load( aLoadArgs
.getPropertyValues() );
550 catch( const uno::Exception
& )
552 uno::Reference
< util::XCloseable
> xCloseable( xDocument
, uno::UNO_QUERY
);
553 if ( xCloseable
.is() )
557 xCloseable
->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() )
628 // check whether the component is modified,
629 // if not there is no need for storing
630 uno::Reference
< util::XModifiable
> xModifiable( m_xDocHolder
->GetComponent(), uno::UNO_QUERY
);
631 if ( xModifiable
.is() && !xModifiable
->isModified() )
634 catch( const uno::Exception
& )
638 m_xClientSite
->saveObject();
640 catch( const uno::Exception
& )
642 SAL_WARN( "embeddedobj.common", "The object was not stored!" );
648 OUString
OCommonEmbeddedObject::GetBaseURL_Impl() const
653 if ( m_xClientSite
.is() )
657 uno::Reference
< frame::XModel
> xParentModel( m_xClientSite
->getComponent(), uno::UNO_QUERY_THROW
);
658 uno::Sequence
< beans::PropertyValue
> aModelProps
= xParentModel
->getArgs();
659 for ( nInd
= 0; nInd
< aModelProps
.getLength(); nInd
++ )
660 if ( aModelProps
[nInd
].Name
== "DocumentBaseURL" )
662 aModelProps
[nInd
].Value
>>= aBaseURL
;
668 catch( const uno::Exception
& )
672 if ( aBaseURL
.isEmpty() )
674 for ( nInd
= 0; nInd
< m_aDocMediaDescriptor
.getLength(); nInd
++ )
675 if ( m_aDocMediaDescriptor
[nInd
].Name
== "DocumentBaseURL" )
677 m_aDocMediaDescriptor
[nInd
].Value
>>= aBaseURL
;
682 if ( aBaseURL
.isEmpty() )
683 aBaseURL
= m_aDefaultParentBaseURL
;
689 OUString
OCommonEmbeddedObject::GetBaseURLFrom_Impl(
690 const uno::Sequence
< beans::PropertyValue
>& lArguments
,
691 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
696 for ( nInd
= 0; nInd
< lArguments
.getLength(); nInd
++ )
697 if ( lArguments
[nInd
].Name
== "DocumentBaseURL" )
699 lArguments
[nInd
].Value
>>= aBaseURL
;
703 if ( aBaseURL
.isEmpty() )
705 for ( nInd
= 0; nInd
< lObjArgs
.getLength(); nInd
++ )
706 if ( lObjArgs
[nInd
].Name
== "DefaultParentBaseURL" )
708 lObjArgs
[nInd
].Value
>>= aBaseURL
;
717 void OCommonEmbeddedObject::SwitchDocToStorage_Impl( const uno::Reference
< document::XStorageBasedDocument
>& xDoc
, const uno::Reference
< embed::XStorage
>& xStorage
)
719 xDoc
->switchToStorage( xStorage
);
721 uno::Reference
< util::XModifiable
> xModif( xDoc
, uno::UNO_QUERY
);
723 xModif
->setModified( false );
725 if ( m_xRecoveryStorage
.is() )
726 m_xRecoveryStorage
.clear();
731 OUString
getStringPropertyValue( const uno::Sequence
<beans::PropertyValue
>& rProps
, const OUString
& rName
)
735 for (sal_Int32 i
= 0; i
< rProps
.getLength(); ++i
)
737 if (rProps
[i
].Name
== rName
)
739 rProps
[i
].Value
>>= aStr
;
749 void OCommonEmbeddedObject::StoreDocToStorage_Impl(
750 const uno::Reference
<embed::XStorage
>& xStorage
,
751 const uno::Sequence
<beans::PropertyValue
>& rMediaArgs
,
752 const uno::Sequence
<beans::PropertyValue
>& rObjArgs
,
753 sal_Int32 nStorageFormat
,
754 const OUString
& aHierarchName
,
755 bool bAttachToTheStorage
)
757 SAL_WARN_IF( !xStorage
.is(), "embeddedobj.common", "No storage is provided for storing!" );
759 if ( !xStorage
.is() )
760 throw uno::RuntimeException(); // TODO:
762 uno::Reference
< document::XStorageBasedDocument
> xDoc
;
764 osl::MutexGuard
aGuard( m_aMutex
);
765 if ( m_xDocHolder
.is() )
766 xDoc
.set( m_xDocHolder
->GetComponent(), uno::UNO_QUERY
);
769 OUString aBaseURL
= GetBaseURLFrom_Impl(rMediaArgs
, rObjArgs
);
773 OUString aFilterName
= GetFilterName( nStorageFormat
);
775 // No filter found? Try the older format, e.g. Base has only that.
776 if (aFilterName
.isEmpty() && nStorageFormat
== SOFFICE_FILEFORMAT_CURRENT
)
777 aFilterName
= GetFilterName( SOFFICE_FILEFORMAT_60
);
779 SAL_WARN_IF( aFilterName
.isEmpty(), "embeddedobj.common", "Wrong document service name!" );
780 if ( aFilterName
.isEmpty() )
781 throw io::IOException(); // TODO:
783 uno::Sequence
<beans::PropertyValue
> aArgs(5);
784 aArgs
[0].Name
= "FilterName";
785 aArgs
[0].Value
<<= aFilterName
;
786 aArgs
[1].Name
= "HierarchicalDocumentName";
787 aArgs
[1].Value
<<= aHierarchName
;
788 aArgs
[2].Name
= "DocumentBaseURL";
789 aArgs
[2].Value
<<= aBaseURL
;
790 aArgs
[3].Name
= "SourceShellID";
791 aArgs
[3].Value
<<= getStringPropertyValue(rObjArgs
, "SourceShellID");
792 aArgs
[4].Name
= "DestinationShellID";
793 aArgs
[4].Value
<<= getStringPropertyValue(rObjArgs
, "DestinationShellID");
795 xDoc
->storeToStorage( xStorage
, aArgs
);
796 if ( bAttachToTheStorage
)
797 SwitchDocToStorage_Impl( xDoc
, xStorage
);
801 // store document to temporary stream based on temporary file
802 uno::Reference
< io::XInputStream
> xTempIn
= StoreDocumentToTempStream_Impl( nStorageFormat
, aBaseURL
, aHierarchName
);
804 SAL_WARN_IF( !xTempIn
.is(), "embeddedobj.common", "The stream reference can not be empty!" );
806 // open storage based on document temporary file for reading
807 uno::Reference
< lang::XSingleServiceFactory
> xStorageFactory
= embed::StorageFactory::create(m_xContext
);
809 uno::Sequence
< uno::Any
> aArgs(1);
810 aArgs
[0] <<= 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 uno::Reference
< util::XCloseable
> xCloseable( xDocument
, uno::UNO_QUERY
);
838 if ( xCloseable
.is() )
842 xCloseable
->close( true );
844 catch( const uno::Exception
& )
856 uno::Reference
< util::XCloseable
> OCommonEmbeddedObject::CreateTempDocFromLink_Impl()
858 uno::Reference
< util::XCloseable
> xResult
;
860 SAL_WARN_IF( !m_bIsLink
, "embeddedobj.common", "The object is not a linked one!" );
862 uno::Sequence
< beans::PropertyValue
> aTempMediaDescr
;
864 sal_Int32 nStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
866 nStorageFormat
= ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage
);
868 catch ( const beans::IllegalTypeException
& )
870 // the container just has an unknown type, use current file format
872 catch ( const uno::Exception
& )
874 SAL_WARN( "embeddedobj.common", "Can not retrieve storage media type!" );
877 if ( m_xDocHolder
->GetComponent().is() )
879 aTempMediaDescr
.realloc( 4 );
881 // TODO/LATER: may be private:stream should be used as target URL
882 OUString aTempFileURL
;
883 uno::Reference
< io::XInputStream
> xTempStream
= StoreDocumentToTempStream_Impl( SOFFICE_FILEFORMAT_CURRENT
,
888 // no need to let the file stay after the stream is removed since the embedded document
889 // can not be stored directly
890 uno::Reference
< beans::XPropertySet
> xTempStreamProps( xTempStream
, uno::UNO_QUERY_THROW
);
891 xTempStreamProps
->getPropertyValue("Uri") >>= aTempFileURL
;
893 catch( const uno::Exception
& )
897 SAL_WARN_IF( aTempFileURL
.isEmpty(), "embeddedobj.common", "Couldn't retrieve temporary file URL!" );
899 aTempMediaDescr
[0].Name
= "URL";
900 aTempMediaDescr
[0].Value
<<= aTempFileURL
;
901 aTempMediaDescr
[1].Name
= "InputStream";
902 aTempMediaDescr
[1].Value
<<= xTempStream
;
903 aTempMediaDescr
[2].Name
= "FilterName";
904 aTempMediaDescr
[2].Value
<<= GetFilterName( nStorageFormat
);
905 aTempMediaDescr
[3].Name
= "AsTemplate";
906 aTempMediaDescr
[3].Value
<<= true;
910 aTempMediaDescr
.realloc( 2 );
911 aTempMediaDescr
[0].Name
= "URL";
912 aTempMediaDescr
[0].Value
<<= m_aLinkURL
;
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_bIsLink, "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 ( sal_Int32 nInd
= 0; nInd
< lArguments
.getLength(); nInd
++ )
1002 if ( lArguments
[nInd
].Name
== "ReadOnly" )
1003 lArguments
[nInd
].Value
>>= m_bReadOnly
;
1005 // TODO: use lObjArgs for StoreVisualReplacement
1006 for ( sal_Int32 nObjInd
= 0; nObjInd
< lObjArgs
.getLength(); nObjInd
++ )
1007 if ( lObjArgs
[nObjInd
].Name
== "OutplaceDispatchInterceptor" )
1009 uno::Reference
< frame::XDispatchProviderInterceptor
> xDispatchInterceptor
;
1010 if ( lObjArgs
[nObjInd
].Value
>>= xDispatchInterceptor
)
1011 m_xDocHolder
->SetOutplaceDispatchInterceptor( xDispatchInterceptor
);
1013 else if ( lObjArgs
[nObjInd
].Name
== "DefaultParentBaseURL" )
1015 lObjArgs
[nObjInd
].Value
>>= m_aDefaultParentBaseURL
;
1017 else if ( lObjArgs
[nObjInd
].Name
== "Parent" )
1019 lObjArgs
[nObjInd
].Value
>>= m_xParent
;
1021 else if ( lObjArgs
[nObjInd
].Name
== "IndividualMiscStatus" )
1023 sal_Int64 nMiscStatus
=0;
1024 lObjArgs
[nObjInd
].Value
>>= nMiscStatus
;
1025 m_nMiscStatus
|= nMiscStatus
;
1027 else if ( lObjArgs
[nObjInd
].Name
== "CloneFrom" )
1029 uno::Reference
< embed::XEmbeddedObject
> xObj
;
1030 lObjArgs
[nObjInd
].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 ( lObjArgs
[nObjInd
].Name
== "OutplaceFrameProperties" )
1040 uno::Sequence
< uno::Any
> aOutFrameProps
;
1041 uno::Sequence
< beans::NamedValue
> aOutFramePropsTyped
;
1042 if ( lObjArgs
[nObjInd
].Value
>>= aOutFrameProps
)
1044 m_xDocHolder
->SetOutplaceFrameProperties( aOutFrameProps
);
1046 else if ( lObjArgs
[nObjInd
].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 ( lObjArgs
[nObjInd
].Name
== "ModuleName" )
1064 lObjArgs
[nObjInd
].Value
>>= m_aModuleName
;
1066 else if ( lObjArgs
[nObjInd
].Name
== "EmbeddedScriptSupport" )
1068 OSL_VERIFY( lObjArgs
[nObjInd
].Value
>>= m_bEmbeddedScriptSupport
);
1070 else if ( lObjArgs
[nObjInd
].Name
== "DocumentRecoverySupport" )
1072 OSL_VERIFY( lObjArgs
[nObjInd
].Value
>>= m_bDocumentRecoverySupport
);
1074 else if ( lObjArgs
[nObjInd
].Name
== "RecoveryStorage" )
1076 OSL_VERIFY( lObjArgs
[nObjInd
].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_bIsLink, "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 ( sal_Int32 nInd
= 0; nInd
< lObjArgs
.getLength(); nInd
++ )
1206 // StoreVisualReplacement and VisualReplacement args have no sense here
1207 if ( lObjArgs
[nInd
].Name
== "CanTryOptimization" )
1208 lObjArgs
[nInd
].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
)
1247 uno::Reference
< embed::XStorage
> xSubStorage
=
1248 xStorage
->openStorageElement( sEntName
, embed::ElementModes::READWRITE
);
1250 if ( !xSubStorage
.is() )
1251 throw uno::RuntimeException(); //TODO
1254 // TODO/LATER: support hierarchical name for embedded objects in embedded objects
1255 StoreDocToStorage_Impl(
1256 xSubStorage
, lArguments
, lObjArgs
, nTargetStorageFormat
, sEntName
, false );
1259 if ( bSwitchBackToLoaded
)
1260 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_bIsLink, "This method implementation must not be used for links!" );
1295 m_aNewEntryName
= sEntName
;
1299 OSL_ENSURE( m_xParentStorage
.is() && m_xObjectStorage
.is(), "The object has no valid persistence!" );
1301 sal_Int32 nTargetStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1302 sal_Int32 nOriginalStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1304 nTargetStorageFormat
= ::comphelper::OStorageHelper::GetXStorageFormat( xStorage
);
1306 catch ( const beans::IllegalTypeException
& )
1308 // the container just has an unknown type, use current file format
1310 catch ( const uno::Exception
& )
1312 SAL_WARN( "embeddedobj.common", "Can not retrieve target storage media type!" );
1314 if (nTargetStorageFormat
== SOFFICE_FILEFORMAT_60
)
1316 SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1317 nTargetStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1318 // setting MediaType is done later anyway, no need to do it here
1323 nOriginalStorageFormat
= ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage
);
1325 catch ( const beans::IllegalTypeException
& )
1327 // the container just has an unknown type, use current file format
1329 catch ( const uno::Exception
& )
1331 SAL_WARN( "embeddedobj.common", "Can not retrieve own storage media type!" );
1334 PostEvent_Impl( "OnSaveAs" );
1336 bool bTryOptimization
= false;
1337 for ( sal_Int32 nInd
= 0; nInd
< lObjArgs
.getLength(); nInd
++ )
1339 // StoreVisualReplacement and VisualReplacement args have no sense here
1340 if ( lObjArgs
[nInd
].Name
== "CanTryOptimization" )
1341 lObjArgs
[nInd
].Value
>>= bTryOptimization
;
1344 bool bSwitchBackToLoaded
= false;
1346 // Storing to different format can be done only in running state.
1347 if ( m_nObjectState
== embed::EmbedStates::LOADED
)
1349 // TODO/LATER: copying is not legal for documents with relative links.
1350 if ( nTargetStorageFormat
== nOriginalStorageFormat
)
1352 bool bOptimizationWorks
= false;
1353 if ( bTryOptimization
)
1357 // try to use optimized copying
1358 uno::Reference
< embed::XOptimizedStorage
> xSource( m_xParentStorage
, uno::UNO_QUERY_THROW
);
1359 uno::Reference
< embed::XOptimizedStorage
> xTarget( xStorage
, uno::UNO_QUERY_THROW
);
1360 xSource
->copyElementDirectlyTo( m_aEntryName
, xTarget
, sEntName
);
1361 bOptimizationWorks
= true;
1363 catch( const uno::Exception
& )
1368 if ( !bOptimizationWorks
)
1369 m_xParentStorage
->copyElementTo( m_aEntryName
, xStorage
, sEntName
);
1373 changeState( embed::EmbedStates::RUNNING
);
1374 bSwitchBackToLoaded
= true;
1378 uno::Reference
< embed::XStorage
> xSubStorage
=
1379 xStorage
->openStorageElement( sEntName
, embed::ElementModes::READWRITE
);
1381 if ( !xSubStorage
.is() )
1382 throw uno::RuntimeException(); //TODO
1384 if ( m_nObjectState
!= embed::EmbedStates::LOADED
)
1387 // TODO/LATER: support hierarchical name for embedded objects in embedded objects
1388 StoreDocToStorage_Impl(
1389 xSubStorage
, lArguments
, lObjArgs
, nTargetStorageFormat
, sEntName
, false );
1392 if ( bSwitchBackToLoaded
)
1393 changeState( embed::EmbedStates::LOADED
);
1396 m_bWaitSaveCompleted
= true;
1397 m_xNewObjectStorage
= xSubStorage
;
1398 m_xNewParentStorage
= xStorage
;
1399 m_aNewEntryName
= sEntName
;
1400 m_aNewDocMediaDescriptor
= GetValuableArgs_Impl( lArguments
, true );
1402 // TODO: register listeners for storages above, in case thay are disposed
1403 // an exception will be thrown on saveCompleted( true )
1405 // TODO: should the listener notification be done here or in saveCompleted?
1409 void SAL_CALL
OCommonEmbeddedObject::saveCompleted( sal_Bool bUseNew
)
1411 ::osl::MutexGuard
aGuard( m_aMutex
);
1413 throw lang::DisposedException(); // TODO
1415 if ( m_nObjectState
== -1 )
1417 // the object is still not loaded
1418 throw embed::WrongStateException( "Can't store object without persistence!",
1419 static_cast< ::cppu::OWeakObject
* >(this) );
1422 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1423 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1424 // OSL_ENSURE( !m_bIsLink, "This method implementation must not be used for links!" );
1428 m_aEntryName
= m_aNewEntryName
;
1429 m_aNewEntryName
.clear();
1433 // it is allowed to call saveCompleted( false ) for nonstored objects
1434 if ( !m_bWaitSaveCompleted
&& !bUseNew
)
1437 SAL_WARN_IF( !m_bWaitSaveCompleted
, "embeddedobj.common", "Unexpected saveCompleted() call!" );
1438 if ( !m_bWaitSaveCompleted
)
1439 throw io::IOException(); // TODO: illegal call
1441 OSL_ENSURE( m_xNewObjectStorage
.is() && m_xNewParentStorage
.is() , "Internal object information is broken!" );
1442 if ( !m_xNewObjectStorage
.is() || !m_xNewParentStorage
.is() )
1443 throw uno::RuntimeException(); // TODO: broken internal information
1447 SwitchOwnPersistence( m_xNewParentStorage
, m_xNewObjectStorage
, m_aNewEntryName
);
1448 m_aDocMediaDescriptor
= m_aNewDocMediaDescriptor
;
1450 uno::Reference
< util::XModifiable
> xModif( m_xDocHolder
->GetComponent(), uno::UNO_QUERY
);
1452 xModif
->setModified( false );
1454 PostEvent_Impl( "OnSaveAsDone");
1459 uno::Reference
< lang::XComponent
> xComponent( m_xNewObjectStorage
, uno::UNO_QUERY
);
1460 SAL_WARN_IF( !xComponent
.is(), "embeddedobj.common", "Wrong storage implementation!" );
1461 if ( xComponent
.is() )
1462 xComponent
->dispose();
1464 catch ( const uno::Exception
& )
1469 m_xNewObjectStorage
.clear();
1470 m_xNewParentStorage
.clear();
1471 m_aNewEntryName
.clear();
1472 m_aNewDocMediaDescriptor
.realloc( 0 );
1473 m_bWaitSaveCompleted
= false;
1477 // TODO: notify listeners
1479 if ( m_nUpdateMode
== embed::EmbedUpdateModes::ALWAYS_UPDATE
)
1481 // TODO: update visual representation
1487 sal_Bool SAL_CALL
OCommonEmbeddedObject::hasEntry()
1489 ::osl::MutexGuard
aGuard( m_aMutex
);
1491 throw lang::DisposedException(); // TODO
1493 if ( m_bWaitSaveCompleted
)
1494 throw embed::WrongStateException(
1495 "The object waits for saveCompleted() call!",
1496 static_cast< ::cppu::OWeakObject
* >(this) );
1498 if ( m_xObjectStorage
.is() )
1505 OUString SAL_CALL
OCommonEmbeddedObject::getEntryName()
1507 ::osl::MutexGuard
aGuard( m_aMutex
);
1509 throw lang::DisposedException(); // TODO
1511 if ( m_nObjectState
== -1 )
1513 // the object is still not loaded
1514 throw embed::WrongStateException( "The object persistence is not initialized!",
1515 static_cast< ::cppu::OWeakObject
* >(this) );
1518 if ( m_bWaitSaveCompleted
)
1519 throw embed::WrongStateException(
1520 "The object waits for saveCompleted() call!",
1521 static_cast< ::cppu::OWeakObject
* >(this) );
1523 return m_aEntryName
;
1527 void SAL_CALL
OCommonEmbeddedObject::storeOwn()
1529 // during switching from Activated to Running and from Running to Loaded states the object will
1530 // ask container to store the object, the container has to make decision
1533 ::osl::ResettableMutexGuard
aGuard( m_aMutex
);
1535 throw lang::DisposedException(); // TODO
1537 if ( m_nObjectState
== -1 )
1539 // the object is still not loaded
1540 throw embed::WrongStateException( "Can't store object without persistence!",
1541 static_cast< ::cppu::OWeakObject
* >(this) );
1544 if ( m_bWaitSaveCompleted
)
1545 throw embed::WrongStateException(
1546 "The object waits for saveCompleted() call!",
1547 static_cast< ::cppu::OWeakObject
* >(this) );
1550 throw io::IOException(); // TODO: access denied
1552 // nothing to do, if the object is in loaded state
1553 if ( m_nObjectState
== embed::EmbedStates::LOADED
)
1556 PostEvent_Impl( "OnSave" );
1558 SAL_WARN_IF( !m_xDocHolder
->GetComponent().is(), "embeddedobj.common", "If an object is activated or in running state it must have a document!" );
1559 if ( !m_xDocHolder
->GetComponent().is() )
1560 throw uno::RuntimeException();
1564 // TODO: just store the document to its location
1565 uno::Reference
< frame::XStorable
> xStorable( m_xDocHolder
->GetComponent(), uno::UNO_QUERY_THROW
);
1567 // free the main mutex for the storing time
1576 OSL_ENSURE( m_xParentStorage
.is() && m_xObjectStorage
.is(), "The object has no valid persistence!" );
1578 if ( !m_xObjectStorage
.is() )
1579 throw io::IOException(); //TODO: access denied
1581 sal_Int32 nStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1583 nStorageFormat
= ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage
);
1585 catch ( const beans::IllegalTypeException
& )
1587 // the container just has an unknown type, use current file format
1589 catch ( const uno::Exception
& )
1591 SAL_WARN( "embeddedobj.common", "Can not retrieve storage media type!" );
1593 if (nStorageFormat
== SOFFICE_FILEFORMAT_60
)
1595 SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1596 nStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1597 // setting MediaType is done later anyway, no need to do it here
1601 uno::Sequence
<beans::PropertyValue
> aEmpty
;
1602 uno::Sequence
<beans::PropertyValue
> aMediaArgs(1);
1603 aMediaArgs
[0].Name
= "DocumentBaseURL";
1604 aMediaArgs
[0].Value
<<= GetBaseURL_Impl();
1605 StoreDocToStorage_Impl( m_xObjectStorage
, aMediaArgs
, aEmpty
, nStorageFormat
, m_aEntryName
, true );
1609 uno::Reference
< util::XModifiable
> xModif( m_xDocHolder
->GetComponent(), uno::UNO_QUERY
);
1611 xModif
->setModified( false );
1613 PostEvent_Impl( "OnSaveDone" );
1617 sal_Bool SAL_CALL
OCommonEmbeddedObject::isReadonly()
1619 ::osl::MutexGuard
aGuard( m_aMutex
);
1621 throw lang::DisposedException(); // TODO
1623 if ( m_nObjectState
== -1 )
1625 // the object is still not loaded
1626 throw embed::WrongStateException( "The object persistence is not initialized!",
1627 static_cast< ::cppu::OWeakObject
* >(this) );
1630 if ( m_bWaitSaveCompleted
)
1631 throw embed::WrongStateException(
1632 "The object waits for saveCompleted() call!",
1633 static_cast< ::cppu::OWeakObject
* >(this) );
1639 void SAL_CALL
OCommonEmbeddedObject::reload(
1640 const uno::Sequence
< beans::PropertyValue
>& lArguments
,
1641 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
1643 // TODO: use lObjArgs
1644 // for now this method is used only to switch readonly state
1646 ::osl::MutexGuard
aGuard( m_aMutex
);
1648 throw lang::DisposedException(); // TODO
1650 if ( m_nObjectState
== -1 )
1652 // the object is still not loaded
1653 throw embed::WrongStateException( "The object persistence is not initialized!",
1654 static_cast< ::cppu::OWeakObject
* >(this) );
1657 if ( m_nObjectState
!= embed::EmbedStates::LOADED
)
1659 // the object is still not loaded
1660 throw embed::WrongStateException(
1661 "The object must be in loaded state to be reloaded!",
1662 static_cast< ::cppu::OWeakObject
* >(this) );
1665 if ( m_bWaitSaveCompleted
)
1666 throw embed::WrongStateException(
1667 "The object waits for saveCompleted() call!",
1668 static_cast< ::cppu::OWeakObject
* >(this) );
1672 // reload of the link
1673 OUString aOldLinkFilter
= m_aLinkFilterName
;
1675 OUString aNewLinkFilter
;
1676 for ( sal_Int32 nInd
= 0; nInd
< lArguments
.getLength(); nInd
++ )
1678 if ( lArguments
[nInd
].Name
== "URL" )
1681 lArguments
[nInd
].Value
>>= m_aLinkURL
;
1682 m_aLinkFilterName
.clear();
1684 else if ( lArguments
[nInd
].Name
== "FilterName" )
1686 lArguments
[nInd
].Value
>>= aNewLinkFilter
;
1687 m_aLinkFilterName
.clear();
1691 ::comphelper::MimeConfigurationHelper
aHelper( m_xContext
);
1692 if ( m_aLinkFilterName
.isEmpty() )
1694 if ( !aNewLinkFilter
.isEmpty() )
1695 m_aLinkFilterName
= aNewLinkFilter
;
1698 uno::Sequence
< beans::PropertyValue
> aArgs( 1 );
1699 aArgs
[0].Name
= "URL";
1700 aArgs
[0].Value
<<= m_aLinkURL
;
1701 m_aLinkFilterName
= aHelper
.UpdateMediaDescriptorWithFilterName( aArgs
, false );
1705 if ( aOldLinkFilter
!= m_aLinkFilterName
)
1707 uno::Sequence
< beans::NamedValue
> aObject
= aHelper
.GetObjectPropsByFilter( m_aLinkFilterName
);
1709 // TODO/LATER: probably the document holder could be cleaned explicitly as in the destructor
1710 m_xDocHolder
.clear();
1712 LinkInit_Impl( aObject
, lArguments
, lObjArgs
);
1716 m_aDocMediaDescriptor
= GetValuableArgs_Impl( lArguments
, true );
1718 // TODO: use lObjArgs for StoreVisualReplacement
1719 for ( sal_Int32 nObjInd
= 0; nObjInd
< lObjArgs
.getLength(); nObjInd
++ )
1720 if ( lObjArgs
[nObjInd
].Name
== "OutplaceDispatchInterceptor" )
1722 uno::Reference
< frame::XDispatchProviderInterceptor
> xDispatchInterceptor
;
1723 if ( lObjArgs
[nObjInd
].Value
>>= xDispatchInterceptor
)
1724 m_xDocHolder
->SetOutplaceDispatchInterceptor( xDispatchInterceptor
);
1730 // when document allows reloading through API the object can be reloaded not only in loaded state
1732 bool bOldReadOnlyValue
= m_bReadOnly
;
1734 m_bReadOnly
= false;
1735 for ( sal_Int32 nInd
= 0; nInd
< lArguments
.getLength(); nInd
++ )
1736 if ( lArguments
[nInd
].Name
== "ReadOnly" )
1737 lArguments
[nInd
].Value
>>= m_bReadOnly
;
1739 if ( bOldReadOnlyValue
!= m_bReadOnly
&& !m_bIsLink
)
1741 // close own storage
1743 uno::Reference
< lang::XComponent
> xComponent( m_xObjectStorage
, uno::UNO_QUERY
);
1744 OSL_ENSURE( !m_xObjectStorage
.is() || xComponent
.is(), "Wrong storage implementation!" );
1745 if ( xComponent
.is() )
1746 xComponent
->dispose();
1748 catch ( const uno::Exception
& )
1752 sal_Int32 nStorageMode
= m_bReadOnly
? embed::ElementModes::READ
: embed::ElementModes::READWRITE
;
1753 m_xObjectStorage
= m_xParentStorage
->openStorageElement( m_aEntryName
, nStorageMode
);
1757 sal_Bool SAL_CALL
OCommonEmbeddedObject::isStored()
1759 uno::Reference
<container::XNameAccess
> xNA(m_xObjectStorage
, uno::UNO_QUERY
);
1763 return xNA
->getElementNames().getLength() > 0;
1767 void SAL_CALL
OCommonEmbeddedObject::breakLink( const uno::Reference
< embed::XStorage
>& xStorage
,
1768 const OUString
& sEntName
)
1770 ::osl::ResettableMutexGuard
aGuard( m_aMutex
);
1772 throw lang::DisposedException(); // TODO
1776 // it must be a linked initialized object
1777 throw embed::WrongStateException(
1778 "The object is not a valid linked object!",
1779 static_cast< ::cppu::OWeakObject
* >(this) );
1781 // the current implementation of OOo links does not implement this method since it does not implement
1782 // all the set of interfaces required for OOo embedded object ( XEmbedPersist is not supported ).
1784 if ( !xStorage
.is() )
1785 throw lang::IllegalArgumentException( "No parent storage is provided!",
1786 static_cast< ::cppu::OWeakObject
* >(this),
1789 if ( sEntName
.isEmpty() )
1790 throw lang::IllegalArgumentException( "Empty element name is provided!",
1791 static_cast< ::cppu::OWeakObject
* >(this),
1794 if ( !m_bIsLink
|| m_nObjectState
== -1 )
1796 // it must be a linked initialized object
1797 throw embed::WrongStateException(
1798 "The object is not a valid linked object!",
1799 static_cast< ::cppu::OWeakObject
* >(this) );
1802 if ( m_bWaitSaveCompleted
)
1803 throw embed::WrongStateException(
1804 "The object waits for saveCompleted() call!",
1805 static_cast< ::cppu::OWeakObject
* >(this) );
1807 uno::Reference
< container::XNameAccess
> xNameAccess( xStorage
, uno::UNO_QUERY_THROW
);
1809 m_bReadOnly
= false;
1811 if ( m_xParentStorage
!= xStorage
|| m_aEntryName
!= sEntName
)
1812 SwitchOwnPersistence( xStorage
, sEntName
);
1814 // for linked object it means that it becomes embedded object
1815 // the document must switch it's persistence also
1817 // TODO/LATER: handle the case when temp doc can not be created
1818 // the document is a new embedded object so it must be marked as modified
1819 uno::Reference
< util::XCloseable
> xDocument
= CreateTempDocFromLink_Impl();
1820 uno::Reference
< util::XModifiable
> xModif( m_xDocHolder
->GetComponent(), uno::UNO_QUERY_THROW
);
1823 xModif
->setModified( true );
1825 catch( const uno::Exception
& )
1828 m_xDocHolder
->SetComponent( xDocument
, m_bReadOnly
);
1829 SAL_WARN_IF( !m_xDocHolder
->GetComponent().is(), "embeddedobj.common", "If document can't be created, an exception must be thrown!" );
1831 if ( m_nObjectState
== embed::EmbedStates::LOADED
)
1833 // the state is changed and can not be switched to loaded state back without saving
1834 m_nObjectState
= embed::EmbedStates::RUNNING
;
1835 StateChangeNotification_Impl( false, embed::EmbedStates::LOADED
, m_nObjectState
, aGuard
);
1837 else if ( m_nObjectState
== embed::EmbedStates::ACTIVE
)
1838 m_xDocHolder
->Show();
1841 m_aLinkFilterName
.clear();
1846 sal_Bool SAL_CALL
OCommonEmbeddedObject::isLink()
1848 ::osl::MutexGuard
aGuard( m_aMutex
);
1850 throw lang::DisposedException(); // TODO
1856 OUString SAL_CALL
OCommonEmbeddedObject::getLinkURL()
1858 ::osl::MutexGuard
aGuard( m_aMutex
);
1860 throw lang::DisposedException(); // TODO
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: */