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/XStorage.hpp>
27 #include <com/sun/star/embed/XOptimizedStorage.hpp>
28 #include <com/sun/star/embed/ElementModes.hpp>
29 #include <com/sun/star/embed/EmbedUpdateModes.hpp>
30 #include <com/sun/star/embed/StorageFactory.hpp>
31 #include <com/sun/star/io/TempFile.hpp>
32 #include <com/sun/star/frame/XModel.hpp>
33 #include <com/sun/star/frame/XStorable.hpp>
34 #include <com/sun/star/frame/XLoadable.hpp>
35 #include <com/sun/star/frame/XComponentLoader.hpp>
36 #include <com/sun/star/frame/XModule.hpp>
37 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
38 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
39 #include <com/sun/star/lang/DisposedException.hpp>
40 #include <com/sun/star/util/XModifiable.hpp>
42 #include <com/sun/star/container/XNameAccess.hpp>
43 #include <com/sun/star/container/XChild.hpp>
44 #include <com/sun/star/util/XCloseable.hpp>
45 #include <com/sun/star/beans/XPropertySet.hpp>
46 #include <com/sun/star/beans/IllegalTypeException.hpp>
47 #include <com/sun/star/chart2/XChartDocument.hpp>
49 #include <comphelper/fileformat.h>
50 #include <comphelper/processfactory.hxx>
51 #include <comphelper/storagehelper.hxx>
52 #include <comphelper/mimeconfighelper.hxx>
53 #include <comphelper/namedvaluecollection.hxx>
55 #include <tools/diagnose_ex.h>
56 #include "persistence.hxx"
58 using namespace ::com::sun::star
;
61 uno::Sequence
< beans::PropertyValue
> GetValuableArgs_Impl( const uno::Sequence
< beans::PropertyValue
>& aMedDescr
,
62 bool bCanUseDocumentBaseURL
)
64 uno::Sequence
< beans::PropertyValue
> aResult
;
65 sal_Int32 nResLen
= 0;
67 for ( sal_Int32 nInd
= 0; nInd
< aMedDescr
.getLength(); nInd
++ )
69 if ( aMedDescr
[nInd
].Name
== "ComponentData" || aMedDescr
[nInd
].Name
== "DocumentTitle"
70 || aMedDescr
[nInd
].Name
== "InteractionHandler" || aMedDescr
[nInd
].Name
== "JumpMark"
71 // || aMedDescr[nInd].Name == "Password" // makes no sense for embedded objects
72 || aMedDescr
[nInd
].Name
== "Preview" || aMedDescr
[nInd
].Name
== "ReadOnly"
73 || aMedDescr
[nInd
].Name
== "StartPresentation" || aMedDescr
[nInd
].Name
== "RepairPackage"
74 || aMedDescr
[nInd
].Name
== "StatusIndicator" || aMedDescr
[nInd
].Name
== "ViewData"
75 || aMedDescr
[nInd
].Name
== "ViewId" || aMedDescr
[nInd
].Name
== "MacroExecutionMode"
76 || aMedDescr
[nInd
].Name
== "UpdateDocMode"
77 || (aMedDescr
[nInd
].Name
== "DocumentBaseURL" && bCanUseDocumentBaseURL
) )
79 aResult
.realloc( ++nResLen
);
80 aResult
[nResLen
-1] = aMedDescr
[nInd
];
88 uno::Sequence
< beans::PropertyValue
> addAsTemplate( const uno::Sequence
< beans::PropertyValue
>& aOrig
)
90 bool bAsTemplateSet
= false;
91 sal_Int32 nLength
= aOrig
.getLength();
92 uno::Sequence
< beans::PropertyValue
> aResult( nLength
);
94 for ( sal_Int32 nInd
= 0; nInd
< nLength
; nInd
++ )
96 aResult
[nInd
].Name
= aOrig
[nInd
].Name
;
97 if ( aResult
[nInd
].Name
== "AsTemplate" )
99 aResult
[nInd
].Value
<<= true;
100 bAsTemplateSet
= true;
103 aResult
[nInd
].Value
= aOrig
[nInd
].Value
;
106 if ( !bAsTemplateSet
)
108 aResult
.realloc( nLength
+ 1 );
109 aResult
[nLength
].Name
= "AsTemplate";
110 aResult
[nLength
].Value
<<= true;
117 uno::Reference
< io::XInputStream
> createTempInpStreamFromStor(
118 const uno::Reference
< embed::XStorage
>& xStorage
,
119 const uno::Reference
< uno::XComponentContext
>& xContext
)
121 SAL_WARN_IF( !xStorage
.is(), "embeddedobj.common", "The storage can not be empty!" );
123 uno::Reference
< io::XInputStream
> xResult
;
125 uno::Reference
< io::XStream
> xTempStream( io::TempFile::create(xContext
), uno::UNO_QUERY_THROW
);
127 uno::Reference
< lang::XSingleServiceFactory
> xStorageFactory( embed::StorageFactory::create(xContext
) );
129 uno::Sequence
< uno::Any
> aArgs( 2 );
130 aArgs
[0] <<= xTempStream
;
131 aArgs
[1] <<= embed::ElementModes::READWRITE
;
132 uno::Reference
< embed::XStorage
> xTempStorage( xStorageFactory
->createInstanceWithArguments( aArgs
),
134 if ( !xTempStorage
.is() )
135 throw uno::RuntimeException(); // TODO:
139 xStorage
->copyToStorage( xTempStorage
);
140 } catch( const uno::Exception
& e
)
142 throw embed::StorageWrappedTargetException(
143 "Can't copy storage!",
144 uno::Reference
< uno::XInterface
>(),
149 uno::Reference
< lang::XComponent
> xComponent( xTempStorage
, uno::UNO_QUERY
);
150 SAL_WARN_IF( !xComponent
.is(), "embeddedobj.common", "Wrong storage implementation!" );
151 if ( xComponent
.is() )
152 xComponent
->dispose();
154 catch ( const uno::Exception
& )
159 uno::Reference
< io::XOutputStream
> xTempOut
= xTempStream
->getOutputStream();
161 xTempOut
->closeOutput();
163 catch ( const uno::Exception
& )
167 xResult
= xTempStream
->getInputStream();
174 static void TransferMediaType( const uno::Reference
< embed::XStorage
>& i_rSource
, const uno::Reference
< embed::XStorage
>& i_rTarget
)
178 const uno::Reference
< beans::XPropertySet
> xSourceProps( i_rSource
, uno::UNO_QUERY_THROW
);
179 const uno::Reference
< beans::XPropertySet
> xTargetProps( i_rTarget
, uno::UNO_QUERY_THROW
);
180 const OUString
sMediaTypePropName( "MediaType" );
181 xTargetProps
->setPropertyValue( sMediaTypePropName
, xSourceProps
->getPropertyValue( sMediaTypePropName
) );
183 catch( const uno::Exception
& )
185 DBG_UNHANDLED_EXCEPTION();
190 static uno::Reference
< util::XCloseable
> CreateDocument( const uno::Reference
< uno::XComponentContext
>& _rxContext
,
191 const OUString
& _rDocumentServiceName
, bool _bEmbeddedScriptSupport
, const bool i_bDocumentRecoverySupport
)
193 ::comphelper::NamedValueCollection aArguments
;
194 aArguments
.put( "EmbeddedObject", true );
195 aArguments
.put( "EmbeddedScriptSupport", _bEmbeddedScriptSupport
);
196 aArguments
.put( "DocumentRecoverySupport", i_bDocumentRecoverySupport
);
198 uno::Reference
< uno::XInterface
> xDocument
;
201 xDocument
= _rxContext
->getServiceManager()->createInstanceWithArgumentsAndContext(
202 _rDocumentServiceName
, aArguments
.getWrappedPropertyValues(), _rxContext
);
204 catch( const uno::Exception
& )
206 // if an embedded object implementation does not support XInitialization,
207 // the default factory from cppuhelper will throw an
208 // IllegalArgumentException when we try to create the instance with arguments.
209 // Okay, so we fall back to creating the instance without any arguments.
210 OSL_FAIL("Consider implementing interface XInitialization to avoid duplicate construction");
211 xDocument
= _rxContext
->getServiceManager()->createInstanceWithContext( _rDocumentServiceName
, _rxContext
);
214 SAL_WARN_IF(!xDocument
.is(), "embeddedobj.common", "Service " << _rDocumentServiceName
<< " is not available?");
215 return uno::Reference
< util::XCloseable
>( xDocument
, uno::UNO_QUERY
);
219 static void SetDocToEmbedded( const uno::Reference
< frame::XModel
>& rDocument
, const OUString
& aModuleName
)
223 uno::Sequence
< beans::PropertyValue
> aSeq( 1 );
224 aSeq
[0].Name
= "SetEmbedded";
225 aSeq
[0].Value
<<= true;
226 rDocument
->attachResource( OUString(), aSeq
);
228 if ( !aModuleName
.isEmpty() )
232 uno::Reference
< frame::XModule
> xModule( rDocument
, uno::UNO_QUERY_THROW
);
233 xModule
->setIdentifier( aModuleName
);
235 catch( const uno::Exception
& )
242 void OCommonEmbeddedObject::SwitchOwnPersistence( const uno::Reference
< embed::XStorage
>& xNewParentStorage
,
243 const uno::Reference
< embed::XStorage
>& xNewObjectStorage
,
244 const OUString
& aNewName
)
246 if ( xNewParentStorage
== m_xParentStorage
&& aNewName
.equals( m_aEntryName
) )
248 SAL_WARN_IF( xNewObjectStorage
!= m_xObjectStorage
, "embeddedobj.common", "The storage must be the same!" );
252 uno::Reference
< lang::XComponent
> xComponent( m_xObjectStorage
, uno::UNO_QUERY
);
253 OSL_ENSURE( !m_xObjectStorage
.is() || xComponent
.is(), "Wrong storage implementation!" );
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_pDocHolder
->GetComponent(), uno::UNO_QUERY
);
264 SwitchDocToStorage_Impl( xDoc
, m_xObjectStorage
);
268 if ( xComponent
.is() )
269 xComponent
->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
.equals( 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
);
316 if ( !xLoadable
.is() )
317 throw uno::RuntimeException();
321 // set the document mode to embedded as the first action on document!!!
322 EmbedAndReparentDoc_Impl( xDocument
);
324 // if we have a storage to recover the document from, do not use initNew, but instead load from that storage
325 bool bInitNew
= true;
326 if ( m_xRecoveryStorage
.is() )
328 uno::Reference
< document::XStorageBasedDocument
> xDoc( xLoadable
, uno::UNO_QUERY
);
329 SAL_WARN_IF( !xDoc
.is(), "embeddedobj.common", "OCommonEmbeddedObject::InitNewDocument_Impl: cannot recover from a storage when the document is not storage based!" );
332 ::comphelper::NamedValueCollection aLoadArgs
;
333 FillDefaultLoadArgs_Impl( m_xRecoveryStorage
, aLoadArgs
);
335 xDoc
->loadFromStorage( m_xRecoveryStorage
, aLoadArgs
.getPropertyValues() );
336 SwitchDocToStorage_Impl( xDoc
, m_xObjectStorage
);
343 // init document as a new
344 xLoadable
->initNew();
346 xModel
->attachResource( xModel
->getURL(), m_aDocMediaDescriptor
);
348 catch( const uno::Exception
& )
350 uno::Reference
< util::XCloseable
> xCloseable( xDocument
, uno::UNO_QUERY
);
351 if ( xCloseable
.is() )
355 xCloseable
->close( true );
357 catch( const uno::Exception
& )
369 uno::Reference
< util::XCloseable
> OCommonEmbeddedObject::LoadLink_Impl()
371 uno::Reference
< util::XCloseable
> xDocument( CreateDocument( m_xContext
, GetDocumentServiceName(),
372 m_bEmbeddedScriptSupport
, m_bDocumentRecoverySupport
) );
374 uno::Reference
< frame::XLoadable
> xLoadable( xDocument
, uno::UNO_QUERY
);
375 if ( !xLoadable
.is() )
376 throw uno::RuntimeException();
379 uno::Sequence
< beans::PropertyValue
> aArgs( nLen
);
380 aArgs
[0].Name
= "URL";
381 aArgs
[0].Value
<<= m_aLinkURL
;
382 aArgs
[1].Name
= "FilterName";
383 aArgs
[1].Value
<<= m_aLinkFilterName
;
384 if ( m_bLinkHasPassword
)
386 aArgs
.realloc( ++nLen
);
387 aArgs
[nLen
-1].Name
= "Password";
388 aArgs
[nLen
-1].Value
<<= m_aLinkPassword
;
391 aArgs
.realloc( m_aDocMediaDescriptor
.getLength() + nLen
);
392 for ( sal_Int32 nInd
= 0; nInd
< m_aDocMediaDescriptor
.getLength(); nInd
++ )
394 aArgs
[nInd
+nLen
].Name
= m_aDocMediaDescriptor
[nInd
].Name
;
395 aArgs
[nInd
+nLen
].Value
= m_aDocMediaDescriptor
[nInd
].Value
;
400 // the document is not really an embedded one, it is a link
401 EmbedAndReparentDoc_Impl( xDocument
);
404 xLoadable
->load( aArgs
);
406 if ( !m_bLinkHasPassword
)
408 // check if there is a password to cache
409 uno::Reference
< frame::XModel
> xModel( xLoadable
, uno::UNO_QUERY_THROW
);
410 uno::Sequence
< beans::PropertyValue
> aProps
= xModel
->getArgs();
411 for ( sal_Int32 nInd
= 0; nInd
< aProps
.getLength(); nInd
++ )
412 if ( aProps
[nInd
].Name
== "Password" && ( aProps
[nInd
].Value
>>= m_aLinkPassword
) )
414 m_bLinkHasPassword
= true;
419 catch( const uno::Exception
& )
421 uno::Reference
< util::XCloseable
> xCloseable( xDocument
, uno::UNO_QUERY
);
422 if ( xCloseable
.is() )
426 xCloseable
->close( true );
428 catch( const uno::Exception
& )
441 OUString
OCommonEmbeddedObject::GetFilterName( sal_Int32 nVersion
) const
443 OUString aFilterName
= GetPresetFilterName();
444 if ( aFilterName
.isEmpty() )
447 ::comphelper::MimeConfigurationHelper
aHelper( m_xContext
);
448 aFilterName
= aHelper
.GetDefaultFilterFromServiceName( GetDocumentServiceName(), nVersion
);
450 // If no filter is found, fall back to the FileFormatVersion=6200 filter, Base only has that.
451 if (aFilterName
.isEmpty() && nVersion
== SOFFICE_FILEFORMAT_CURRENT
)
452 aFilterName
= aHelper
.GetDefaultFilterFromServiceName(GetDocumentServiceName(), SOFFICE_FILEFORMAT_60
);
453 } catch( const uno::Exception
& )
461 void OCommonEmbeddedObject::FillDefaultLoadArgs_Impl( const uno::Reference
< embed::XStorage
>& i_rxStorage
,
462 ::comphelper::NamedValueCollection
& o_rLoadArgs
) const
464 o_rLoadArgs
.put( "DocumentBaseURL", GetBaseURL_Impl() );
465 o_rLoadArgs
.put( "HierarchicalDocumentName", m_aEntryName
);
466 o_rLoadArgs
.put( "ReadOnly", m_bReadOnly
);
468 OUString aFilterName
= GetFilterName( ::comphelper::OStorageHelper::GetXStorageFormat( i_rxStorage
) );
469 SAL_WARN_IF( aFilterName
.isEmpty(), "embeddedobj.common", "OCommonEmbeddedObject::FillDefaultLoadArgs_Impl: Wrong document service name!" );
470 if ( aFilterName
.isEmpty() )
471 throw io::IOException(); // TODO: error message/code
473 o_rLoadArgs
.put( "FilterName", aFilterName
);
477 uno::Reference
< util::XCloseable
> OCommonEmbeddedObject::LoadDocumentFromStorage_Impl()
479 ENSURE_OR_THROW( m_xObjectStorage
.is(), "no object storage" );
481 const uno::Reference
< embed::XStorage
> xSourceStorage( m_xRecoveryStorage
.is() ? m_xRecoveryStorage
: m_xObjectStorage
);
483 uno::Reference
< util::XCloseable
> xDocument( CreateDocument( m_xContext
, GetDocumentServiceName(),
484 m_bEmbeddedScriptSupport
, m_bDocumentRecoverySupport
) );
486 //#i103460# ODF: take the size given from the parent frame as default
487 uno::Reference
< chart2::XChartDocument
> xChart( xDocument
, uno::UNO_QUERY
);
490 uno::Reference
< embed::XVisualObject
> xChartVisualObject( xChart
, uno::UNO_QUERY
);
491 if( xChartVisualObject
.is() )
492 xChartVisualObject
->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT
, m_aDefaultSizeForChart_In_100TH_MM
);
495 uno::Reference
< frame::XLoadable
> xLoadable( xDocument
, uno::UNO_QUERY
);
496 uno::Reference
< document::XStorageBasedDocument
> xDoc( xDocument
, uno::UNO_QUERY
);
497 if ( !xDoc
.is() && !xLoadable
.is() ) ///BUG: This should be || instead of && ?
498 throw uno::RuntimeException();
500 ::comphelper::NamedValueCollection aLoadArgs
;
501 FillDefaultLoadArgs_Impl( xSourceStorage
, aLoadArgs
);
503 uno::Reference
< io::XInputStream
> xTempInpStream
;
506 xTempInpStream
= createTempInpStreamFromStor( xSourceStorage
, m_xContext
);
507 if ( !xTempInpStream
.is() )
508 throw uno::RuntimeException();
510 OUString aTempFileURL
;
513 // no need to let the file stay after the stream is removed since the embedded document
514 // can not be stored directly
515 uno::Reference
< beans::XPropertySet
> xTempStreamProps( xTempInpStream
, uno::UNO_QUERY_THROW
);
516 xTempStreamProps
->getPropertyValue("Uri") >>= aTempFileURL
;
518 catch( const uno::Exception
& )
522 SAL_WARN_IF( aTempFileURL
.isEmpty(), "embeddedobj.common", "Couldn't retrieve temporary file URL!" );
524 aLoadArgs
.put( "URL", aTempFileURL
);
525 aLoadArgs
.put( "InputStream", xTempInpStream
);
529 aLoadArgs
.merge( m_aDocMediaDescriptor
, true );
533 // set the document mode to embedded as the first step!!!
534 EmbedAndReparentDoc_Impl( xDocument
);
538 xDoc
->loadFromStorage( xSourceStorage
, aLoadArgs
.getPropertyValues() );
539 if ( xSourceStorage
!= m_xObjectStorage
)
540 SwitchDocToStorage_Impl( xDoc
, m_xObjectStorage
);
543 xLoadable
->load( aLoadArgs
.getPropertyValues() );
545 catch( const uno::Exception
& )
547 uno::Reference
< util::XCloseable
> xCloseable( xDocument
, uno::UNO_QUERY
);
548 if ( xCloseable
.is() )
552 xCloseable
->close( true );
554 catch( const uno::Exception
& )
556 DBG_UNHANDLED_EXCEPTION();
567 uno::Reference
< io::XInputStream
> OCommonEmbeddedObject::StoreDocumentToTempStream_Impl(
568 sal_Int32 nStorageFormat
,
569 const OUString
& aBaseURL
,
570 const OUString
& aHierarchName
)
572 uno::Reference
< io::XOutputStream
> xTempOut(
573 io::TempFile::create(m_xContext
),
574 uno::UNO_QUERY_THROW
);
575 uno::Reference
< io::XInputStream
> aResult( xTempOut
, uno::UNO_QUERY
);
578 throw uno::RuntimeException(); // TODO:
580 uno::Reference
< frame::XStorable
> xStorable
;
582 osl::MutexGuard
aGuard( m_aMutex
);
584 xStorable
.set( m_pDocHolder
->GetComponent(), uno::UNO_QUERY
);
587 if( !xStorable
.is() )
588 throw uno::RuntimeException(); // TODO:
590 OUString aFilterName
= GetFilterName( nStorageFormat
);
592 SAL_WARN_IF( aFilterName
.isEmpty(), "embeddedobj.common", "Wrong document service name!" );
593 if ( aFilterName
.isEmpty() )
594 throw io::IOException(); // TODO:
596 uno::Sequence
< beans::PropertyValue
> aArgs( 4 );
597 aArgs
[0].Name
= "FilterName";
598 aArgs
[0].Value
<<= aFilterName
;
599 aArgs
[1].Name
= "OutputStream";
600 aArgs
[1].Value
<<= xTempOut
;
601 aArgs
[2].Name
= "DocumentBaseURL";
602 aArgs
[2].Value
<<= aBaseURL
;
603 aArgs
[3].Name
= "HierarchicalDocumentName";
604 aArgs
[3].Value
<<= aHierarchName
;
606 xStorable
->storeToURL( "private:stream", aArgs
);
609 xTempOut
->closeOutput();
611 catch( const uno::Exception
& )
613 SAL_WARN( "embeddedobj.common", "Looks like stream was closed already" );
620 void OCommonEmbeddedObject::SaveObject_Impl()
622 if ( m_xClientSite
.is() )
626 // check whether the component is modified,
627 // if not there is no need for storing
628 uno::Reference
< util::XModifiable
> xModifiable( m_pDocHolder
->GetComponent(), uno::UNO_QUERY
);
629 if ( xModifiable
.is() && !xModifiable
->isModified() )
632 catch( const uno::Exception
& )
636 m_xClientSite
->saveObject();
638 catch( const uno::Exception
& )
640 SAL_WARN( "embeddedobj.common", "The object was not stored!" );
646 OUString
OCommonEmbeddedObject::GetBaseURL_Impl() const
651 if ( m_xClientSite
.is() )
655 uno::Reference
< frame::XModel
> xParentModel( m_xClientSite
->getComponent(), uno::UNO_QUERY_THROW
);
656 uno::Sequence
< beans::PropertyValue
> aModelProps
= xParentModel
->getArgs();
657 for ( nInd
= 0; nInd
< aModelProps
.getLength(); nInd
++ )
658 if ( aModelProps
[nInd
].Name
== "DocumentBaseURL" )
660 aModelProps
[nInd
].Value
>>= aBaseURL
;
666 catch( const uno::Exception
& )
670 if ( aBaseURL
.isEmpty() )
672 for ( nInd
= 0; nInd
< m_aDocMediaDescriptor
.getLength(); nInd
++ )
673 if ( m_aDocMediaDescriptor
[nInd
].Name
== "DocumentBaseURL" )
675 m_aDocMediaDescriptor
[nInd
].Value
>>= aBaseURL
;
680 if ( aBaseURL
.isEmpty() )
681 aBaseURL
= m_aDefaultParentBaseURL
;
687 OUString
OCommonEmbeddedObject::GetBaseURLFrom_Impl(
688 const uno::Sequence
< beans::PropertyValue
>& lArguments
,
689 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
694 for ( nInd
= 0; nInd
< lArguments
.getLength(); nInd
++ )
695 if ( lArguments
[nInd
].Name
== "DocumentBaseURL" )
697 lArguments
[nInd
].Value
>>= aBaseURL
;
701 if ( aBaseURL
.isEmpty() )
703 for ( nInd
= 0; nInd
< lObjArgs
.getLength(); nInd
++ )
704 if ( lObjArgs
[nInd
].Name
== "DefaultParentBaseURL" )
706 lObjArgs
[nInd
].Value
>>= aBaseURL
;
715 void OCommonEmbeddedObject::SwitchDocToStorage_Impl( const uno::Reference
< document::XStorageBasedDocument
>& xDoc
, const uno::Reference
< embed::XStorage
>& xStorage
)
717 xDoc
->switchToStorage( xStorage
);
719 uno::Reference
< util::XModifiable
> xModif( xDoc
, uno::UNO_QUERY
);
721 xModif
->setModified( false );
723 if ( m_xRecoveryStorage
.is() )
724 m_xRecoveryStorage
.clear();
729 OUString
getStringPropertyValue( const uno::Sequence
<beans::PropertyValue
>& rProps
, const OUString
& rName
)
733 for (sal_Int32 i
= 0; i
< rProps
.getLength(); ++i
)
735 if (rProps
[i
].Name
== rName
)
737 rProps
[i
].Value
>>= aStr
;
747 void OCommonEmbeddedObject::StoreDocToStorage_Impl(
748 const uno::Reference
<embed::XStorage
>& xStorage
,
749 const uno::Sequence
<beans::PropertyValue
>& rMediaArgs
,
750 const uno::Sequence
<beans::PropertyValue
>& rObjArgs
,
751 sal_Int32 nStorageFormat
,
752 const OUString
& aHierarchName
,
753 bool bAttachToTheStorage
)
755 SAL_WARN_IF( !xStorage
.is(), "embeddedobj.common", "No storage is provided for storing!" );
757 if ( !xStorage
.is() )
758 throw uno::RuntimeException(); // TODO:
760 uno::Reference
< document::XStorageBasedDocument
> xDoc
;
762 osl::MutexGuard
aGuard( m_aMutex
);
764 xDoc
.set( m_pDocHolder
->GetComponent(), uno::UNO_QUERY
);
767 OUString aBaseURL
= GetBaseURLFrom_Impl(rMediaArgs
, rObjArgs
);
771 OUString aFilterName
= GetFilterName( nStorageFormat
);
773 // No filter found? Try the older format, e.g. Base has only that.
774 if (aFilterName
.isEmpty() && nStorageFormat
== SOFFICE_FILEFORMAT_CURRENT
)
775 aFilterName
= GetFilterName( SOFFICE_FILEFORMAT_60
);
777 SAL_WARN_IF( aFilterName
.isEmpty(), "embeddedobj.common", "Wrong document service name!" );
778 if ( aFilterName
.isEmpty() )
779 throw io::IOException(); // TODO:
781 uno::Sequence
<beans::PropertyValue
> aArgs(5);
782 aArgs
[0].Name
= "FilterName";
783 aArgs
[0].Value
<<= aFilterName
;
784 aArgs
[1].Name
= "HierarchicalDocumentName";
785 aArgs
[1].Value
<<= aHierarchName
;
786 aArgs
[2].Name
= "DocumentBaseURL";
787 aArgs
[2].Value
<<= aBaseURL
;
788 aArgs
[3].Name
= "SourceShellID";
789 aArgs
[3].Value
<<= getStringPropertyValue(rObjArgs
, "SourceShellID");
790 aArgs
[4].Name
= "DestinationShellID";
791 aArgs
[4].Value
<<= getStringPropertyValue(rObjArgs
, "DestinationShellID");
793 xDoc
->storeToStorage( xStorage
, aArgs
);
794 if ( bAttachToTheStorage
)
795 SwitchDocToStorage_Impl( xDoc
, xStorage
);
799 // store document to temporary stream based on temporary file
800 uno::Reference
< io::XInputStream
> xTempIn
= StoreDocumentToTempStream_Impl( nStorageFormat
, aBaseURL
, aHierarchName
);
802 SAL_WARN_IF( !xTempIn
.is(), "embeddedobj.common", "The stream reference can not be empty!" );
804 // open storage based on document temporary file for reading
805 uno::Reference
< lang::XSingleServiceFactory
> xStorageFactory
= embed::StorageFactory::create(m_xContext
);
807 uno::Sequence
< uno::Any
> aArgs(1);
808 aArgs
[0] <<= xTempIn
;
809 uno::Reference
< embed::XStorage
> xTempStorage( xStorageFactory
->createInstanceWithArguments( aArgs
),
811 if ( !xTempStorage
.is() )
812 throw uno::RuntimeException(); // TODO:
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
);
827 if ( !xLoadable
.is() )
828 throw uno::RuntimeException();
832 // set the document mode to embedded as the first action on the document!!!
833 EmbedAndReparentDoc_Impl( xDocument
);
835 xLoadable
->load( addAsTemplate( aMedDescr
) );
837 catch( const uno::Exception
& )
839 uno::Reference
< util::XCloseable
> xCloseable( xDocument
, uno::UNO_QUERY
);
840 if ( xCloseable
.is() )
844 xCloseable
->close( true );
846 catch( const uno::Exception
& )
858 uno::Reference
< util::XCloseable
> OCommonEmbeddedObject::CreateTempDocFromLink_Impl()
860 uno::Reference
< util::XCloseable
> xResult
;
862 SAL_WARN_IF( !m_bIsLink
, "embeddedobj.common", "The object is not a linked one!" );
864 uno::Sequence
< beans::PropertyValue
> aTempMediaDescr
;
866 sal_Int32 nStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
868 nStorageFormat
= ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage
);
870 catch ( const beans::IllegalTypeException
& )
872 // the container just has an unknown type, use current file format
874 catch ( const uno::Exception
& )
876 SAL_WARN( "embeddedobj.common", "Can not retrieve storage media type!" );
879 if ( m_pDocHolder
->GetComponent().is() )
881 aTempMediaDescr
.realloc( 4 );
883 // TODO/LATER: may be private:stream should be used as target URL
884 OUString aTempFileURL
;
885 uno::Reference
< io::XInputStream
> xTempStream
= StoreDocumentToTempStream_Impl( SOFFICE_FILEFORMAT_CURRENT
,
890 // no need to let the file stay after the stream is removed since the embedded document
891 // can not be stored directly
892 uno::Reference
< beans::XPropertySet
> xTempStreamProps( xTempStream
, uno::UNO_QUERY_THROW
);
893 xTempStreamProps
->getPropertyValue("Uri") >>= aTempFileURL
;
895 catch( const uno::Exception
& )
899 SAL_WARN_IF( aTempFileURL
.isEmpty(), "embeddedobj.common", "Couldn't retrieve temporary file URL!" );
901 aTempMediaDescr
[0].Name
= "URL";
902 aTempMediaDescr
[0].Value
<<= aTempFileURL
;
903 aTempMediaDescr
[1].Name
= "InputStream";
904 aTempMediaDescr
[1].Value
<<= xTempStream
;
905 aTempMediaDescr
[2].Name
= "FilterName";
906 aTempMediaDescr
[2].Value
<<= GetFilterName( nStorageFormat
);
907 aTempMediaDescr
[3].Name
= "AsTemplate";
908 aTempMediaDescr
[3].Value
<<= true;
912 aTempMediaDescr
.realloc( 2 );
913 aTempMediaDescr
[0].Name
= "URL";
914 aTempMediaDescr
[0].Value
<<= m_aLinkURL
;
915 aTempMediaDescr
[1].Name
= "FilterName";
916 aTempMediaDescr
[1].Value
<<= m_aLinkFilterName
;
919 xResult
= CreateDocFromMediaDescr_Impl( aTempMediaDescr
);
925 void SAL_CALL
OCommonEmbeddedObject::setPersistentEntry(
926 const uno::Reference
< embed::XStorage
>& xStorage
,
927 const OUString
& sEntName
,
928 sal_Int32 nEntryConnectionMode
,
929 const uno::Sequence
< beans::PropertyValue
>& lArguments
,
930 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
931 throw ( lang::IllegalArgumentException
,
932 embed::WrongStateException
,
935 uno::RuntimeException
, std::exception
)
937 // the type of the object must be already set
938 // a kind of typedetection should be done in the factory
940 ::osl::MutexGuard
aGuard( m_aMutex
);
942 throw lang::DisposedException(); // TODO
944 if ( !xStorage
.is() )
945 throw lang::IllegalArgumentException( "No parent storage is provided!",
946 static_cast< ::cppu::OWeakObject
* >(this),
949 if ( sEntName
.isEmpty() )
950 throw lang::IllegalArgumentException( "Empty element name is provided!",
951 static_cast< ::cppu::OWeakObject
* >(this),
954 // May be LOADED should be forbidden here ???
955 if ( ( m_nObjectState
!= -1 || nEntryConnectionMode
== embed::EntryInitModes::NO_INIT
)
956 && ( m_nObjectState
== -1 || nEntryConnectionMode
!= embed::EntryInitModes::NO_INIT
) )
958 // if the object is not loaded
959 // it can not get persistent representation without initialization
961 // if the object is loaded
962 // it can switch persistent representation only without initialization
964 throw embed::WrongStateException(
965 "Can't change persistent representation of activated object!",
966 static_cast< ::cppu::OWeakObject
* >(this) );
969 if ( m_bWaitSaveCompleted
)
971 if ( nEntryConnectionMode
== embed::EntryInitModes::NO_INIT
)
973 // saveCompleted is expected, handle it accordingly
974 if ( m_xNewParentStorage
== xStorage
&& m_aNewEntryName
.equals( sEntName
) )
976 saveCompleted( true );
980 // if a completely different entry is provided, switch first back to the old persistence in saveCompleted
981 // and then switch to the target persistence
982 bool bSwitchFurther
= ( m_xParentStorage
!= xStorage
|| !m_aEntryName
.equals( sEntName
) );
983 saveCompleted( false );
984 if ( !bSwitchFurther
)
988 throw embed::WrongStateException(
989 "The object waits for saveCompleted() call!",
990 static_cast< ::cppu::OWeakObject
* >(this) );
993 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
994 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
995 // OSL_ENSURE( !m_bIsLink, "This method implementation must not be used for links!\n" );
998 m_aEntryName
= sEntName
;
1002 uno::Reference
< container::XNameAccess
> xNameAccess( xStorage
, uno::UNO_QUERY
);
1003 if ( !xNameAccess
.is() )
1004 throw uno::RuntimeException(); //TODO
1006 // detect entry existence
1007 bool bElExists
= xNameAccess
->hasByName( sEntName
);
1009 m_aDocMediaDescriptor
= GetValuableArgs_Impl( lArguments
,
1010 nEntryConnectionMode
!= embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT
);
1012 m_bReadOnly
= false;
1013 for ( sal_Int32 nInd
= 0; nInd
< lArguments
.getLength(); nInd
++ )
1014 if ( lArguments
[nInd
].Name
== "ReadOnly" )
1015 lArguments
[nInd
].Value
>>= m_bReadOnly
;
1017 // TODO: use lObjArgs for StoreVisualReplacement
1018 for ( sal_Int32 nObjInd
= 0; nObjInd
< lObjArgs
.getLength(); nObjInd
++ )
1019 if ( lObjArgs
[nObjInd
].Name
== "OutplaceDispatchInterceptor" )
1021 uno::Reference
< frame::XDispatchProviderInterceptor
> xDispatchInterceptor
;
1022 if ( lObjArgs
[nObjInd
].Value
>>= xDispatchInterceptor
)
1023 m_pDocHolder
->SetOutplaceDispatchInterceptor( xDispatchInterceptor
);
1025 else if ( lObjArgs
[nObjInd
].Name
== "DefaultParentBaseURL" )
1027 lObjArgs
[nObjInd
].Value
>>= m_aDefaultParentBaseURL
;
1029 else if ( lObjArgs
[nObjInd
].Name
== "Parent" )
1031 lObjArgs
[nObjInd
].Value
>>= m_xParent
;
1033 else if ( lObjArgs
[nObjInd
].Name
== "IndividualMiscStatus" )
1035 sal_Int64 nMiscStatus
=0;
1036 lObjArgs
[nObjInd
].Value
>>= nMiscStatus
;
1037 m_nMiscStatus
|= nMiscStatus
;
1039 else if ( lObjArgs
[nObjInd
].Name
== "CloneFrom" )
1041 uno::Reference
< embed::XEmbeddedObject
> xObj
;
1042 lObjArgs
[nObjInd
].Value
>>= xObj
;
1045 m_bHasClonedSize
= true;
1046 m_aClonedSize
= xObj
->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT
);
1047 m_nClonedMapUnit
= xObj
->getMapUnit( embed::Aspects::MSOLE_CONTENT
);
1050 else if ( lObjArgs
[nObjInd
].Name
== "OutplaceFrameProperties" )
1052 uno::Sequence
< uno::Any
> aOutFrameProps
;
1053 uno::Sequence
< beans::NamedValue
> aOutFramePropsTyped
;
1054 if ( lObjArgs
[nObjInd
].Value
>>= aOutFrameProps
)
1056 m_pDocHolder
->SetOutplaceFrameProperties( aOutFrameProps
);
1058 else if ( lObjArgs
[nObjInd
].Value
>>= aOutFramePropsTyped
)
1060 aOutFrameProps
.realloc( aOutFramePropsTyped
.getLength() );
1061 uno::Any
* pProp
= aOutFrameProps
.getArray();
1062 for ( const beans::NamedValue
* pTypedProp
= aOutFramePropsTyped
.getConstArray();
1063 pTypedProp
!= aOutFramePropsTyped
.getConstArray() + aOutFramePropsTyped
.getLength();
1064 ++pTypedProp
, ++pProp
1067 *pProp
<<= *pTypedProp
;
1069 m_pDocHolder
->SetOutplaceFrameProperties( aOutFrameProps
);
1072 SAL_WARN( "embeddedobj.common", "OCommonEmbeddedObject::setPersistentEntry: illegal type for argument 'OutplaceFrameProperties'!" );
1074 else if ( lObjArgs
[nObjInd
].Name
== "ModuleName" )
1076 lObjArgs
[nObjInd
].Value
>>= m_aModuleName
;
1078 else if ( lObjArgs
[nObjInd
].Name
== "EmbeddedScriptSupport" )
1080 OSL_VERIFY( lObjArgs
[nObjInd
].Value
>>= m_bEmbeddedScriptSupport
);
1082 else if ( lObjArgs
[nObjInd
].Name
== "DocumentRecoverySupport" )
1084 OSL_VERIFY( lObjArgs
[nObjInd
].Value
>>= m_bDocumentRecoverySupport
);
1086 else if ( lObjArgs
[nObjInd
].Name
== "RecoveryStorage" )
1088 OSL_VERIFY( lObjArgs
[nObjInd
].Value
>>= m_xRecoveryStorage
);
1092 sal_Int32 nStorageMode
= m_bReadOnly
? embed::ElementModes::READ
: embed::ElementModes::READWRITE
;
1094 SwitchOwnPersistence( xStorage
, sEntName
);
1096 if ( nEntryConnectionMode
== embed::EntryInitModes::DEFAULT_INIT
)
1100 // the initialization from existing storage allows to leave object in loaded state
1101 m_nObjectState
= embed::EmbedStates::LOADED
;
1105 m_pDocHolder
->SetComponent( InitNewDocument_Impl(), m_bReadOnly
);
1106 if ( !m_pDocHolder
->GetComponent().is() )
1107 throw io::IOException(); // TODO: can not create document
1109 m_nObjectState
= embed::EmbedStates::RUNNING
;
1114 if ( ( nStorageMode
& embed::ElementModes::READWRITE
) != embed::ElementModes::READWRITE
)
1115 throw io::IOException();
1117 if ( nEntryConnectionMode
== embed::EntryInitModes::NO_INIT
)
1119 // the document just already changed its storage to store to
1120 // the links to OOo documents for now ignore this call
1121 // TODO: OOo links will have persistence so it will be switched here
1123 else if ( nEntryConnectionMode
== embed::EntryInitModes::TRUNCATE_INIT
)
1125 if ( m_xRecoveryStorage
.is() )
1126 TransferMediaType( m_xRecoveryStorage
, m_xObjectStorage
);
1129 m_pDocHolder
->SetComponent( InitNewDocument_Impl(), m_bReadOnly
);
1131 if ( !m_pDocHolder
->GetComponent().is() )
1132 throw io::IOException(); // TODO: can not create document
1134 m_nObjectState
= embed::EmbedStates::RUNNING
;
1136 else if ( nEntryConnectionMode
== embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT
)
1138 m_pDocHolder
->SetComponent( CreateDocFromMediaDescr_Impl( lArguments
), m_bReadOnly
);
1139 m_nObjectState
= embed::EmbedStates::RUNNING
;
1141 //else if ( nEntryConnectionMode == embed::EntryInitModes::TRANSFERABLE_INIT )
1146 throw lang::IllegalArgumentException( "Wrong connection mode is provided!",
1147 static_cast< ::cppu::OWeakObject
* >(this),
1153 void SAL_CALL
OCommonEmbeddedObject::storeToEntry( const uno::Reference
< embed::XStorage
>& xStorage
,
1154 const OUString
& sEntName
,
1155 const uno::Sequence
< beans::PropertyValue
>& lArguments
,
1156 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
1157 throw ( lang::IllegalArgumentException
,
1158 embed::WrongStateException
,
1161 uno::RuntimeException
, std::exception
)
1163 ::osl::ResettableMutexGuard
aGuard( m_aMutex
);
1165 throw lang::DisposedException(); // TODO
1167 if ( m_nObjectState
== -1 )
1169 // the object is still not loaded
1170 throw embed::WrongStateException( "Can't store object without persistence!",
1171 static_cast< ::cppu::OWeakObject
* >(this) );
1174 if ( m_bWaitSaveCompleted
)
1175 throw embed::WrongStateException(
1176 "The object waits for saveCompleted() call!",
1177 static_cast< ::cppu::OWeakObject
* >(this) );
1179 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1180 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1181 // OSL_ENSURE( !m_bIsLink, "This method implementation must not be used for links!\n" );
1185 OSL_ENSURE( m_xParentStorage
.is() && m_xObjectStorage
.is(), "The object has no valid persistence!\n" );
1187 sal_Int32 nTargetStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1188 sal_Int32 nOriginalStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1190 nTargetStorageFormat
= ::comphelper::OStorageHelper::GetXStorageFormat( xStorage
);
1192 catch ( const beans::IllegalTypeException
& )
1194 // the container just has an unknown type, use current file format
1196 catch ( const uno::Exception
& )
1198 SAL_WARN( "embeddedobj.common", "Can not retrieve target storage media type!" );
1200 if (nTargetStorageFormat
== SOFFICE_FILEFORMAT_60
)
1202 SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1203 nTargetStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1204 // setting MediaType is done later anyway, no need to do it here
1209 nOriginalStorageFormat
= ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage
);
1211 catch ( const beans::IllegalTypeException
& )
1213 // the container just has an unknown type, use current file format
1215 catch ( const uno::Exception
& )
1217 SAL_WARN( "embeddedobj.common", "Can not retrieve own storage media type!" );
1220 bool bTryOptimization
= false;
1221 for ( sal_Int32 nInd
= 0; nInd
< lObjArgs
.getLength(); nInd
++ )
1223 // StoreVisualReplacement and VisualReplacement args have no sense here
1224 if ( lObjArgs
[nInd
].Name
== "CanTryOptimization" )
1225 lObjArgs
[nInd
].Value
>>= bTryOptimization
;
1228 bool bSwitchBackToLoaded
= false;
1230 // Storing to different format can be done only in running state.
1231 if ( m_nObjectState
== embed::EmbedStates::LOADED
)
1233 // TODO/LATER: copying is not legal for documents with relative links.
1234 if ( nTargetStorageFormat
== nOriginalStorageFormat
)
1236 bool bOptimizationWorks
= false;
1237 if ( bTryOptimization
)
1241 // try to use optimized copying
1242 uno::Reference
< embed::XOptimizedStorage
> xSource( m_xParentStorage
, uno::UNO_QUERY_THROW
);
1243 uno::Reference
< embed::XOptimizedStorage
> xTarget( xStorage
, uno::UNO_QUERY_THROW
);
1244 xSource
->copyElementDirectlyTo( m_aEntryName
, xTarget
, sEntName
);
1245 bOptimizationWorks
= true;
1247 catch( const uno::Exception
& )
1252 if ( !bOptimizationWorks
)
1253 m_xParentStorage
->copyElementTo( m_aEntryName
, xStorage
, sEntName
);
1257 changeState( embed::EmbedStates::RUNNING
);
1258 bSwitchBackToLoaded
= true;
1262 if ( m_nObjectState
!= embed::EmbedStates::LOADED
)
1264 uno::Reference
< embed::XStorage
> xSubStorage
=
1265 xStorage
->openStorageElement( sEntName
, embed::ElementModes::READWRITE
);
1267 if ( !xSubStorage
.is() )
1268 throw uno::RuntimeException(); //TODO
1271 // TODO/LATER: support hierarchical name for embedded objects in embedded objects
1272 StoreDocToStorage_Impl(
1273 xSubStorage
, lArguments
, lObjArgs
, nTargetStorageFormat
, sEntName
, false );
1276 if ( bSwitchBackToLoaded
)
1277 changeState( embed::EmbedStates::LOADED
);
1280 // TODO: should the listener notification be done?
1284 void SAL_CALL
OCommonEmbeddedObject::storeAsEntry( const uno::Reference
< embed::XStorage
>& xStorage
,
1285 const OUString
& sEntName
,
1286 const uno::Sequence
< beans::PropertyValue
>& lArguments
,
1287 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
1288 throw ( lang::IllegalArgumentException
,
1289 embed::WrongStateException
,
1292 uno::RuntimeException
, std::exception
)
1294 // TODO: use lObjArgs
1296 ::osl::ResettableMutexGuard
aGuard( m_aMutex
);
1298 throw lang::DisposedException(); // TODO
1300 if ( m_nObjectState
== -1 )
1302 // the object is still not loaded
1303 throw embed::WrongStateException( "Can't store object without persistence!",
1304 static_cast< ::cppu::OWeakObject
* >(this) );
1307 if ( m_bWaitSaveCompleted
)
1308 throw embed::WrongStateException(
1309 "The object waits for saveCompleted() call!",
1310 static_cast< ::cppu::OWeakObject
* >(this) );
1312 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1313 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1314 // OSL_ENSURE( !m_bIsLink, "This method implementation must not be used for links!\n" );
1317 m_aNewEntryName
= sEntName
;
1321 OSL_ENSURE( m_xParentStorage
.is() && m_xObjectStorage
.is(), "The object has no valid persistence!\n" );
1323 sal_Int32 nTargetStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1324 sal_Int32 nOriginalStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1326 nTargetStorageFormat
= ::comphelper::OStorageHelper::GetXStorageFormat( xStorage
);
1328 catch ( const beans::IllegalTypeException
& )
1330 // the container just has an unknown type, use current file format
1332 catch ( const uno::Exception
& )
1334 SAL_WARN( "embeddedobj.common", "Can not retrieve target storage media type!" );
1336 if (nTargetStorageFormat
== SOFFICE_FILEFORMAT_60
)
1338 SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1339 nTargetStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1340 // setting MediaType is done later anyway, no need to do it here
1345 nOriginalStorageFormat
= ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage
);
1347 catch ( const beans::IllegalTypeException
& )
1349 // the container just has an unknown type, use current file format
1351 catch ( const uno::Exception
& )
1353 SAL_WARN( "embeddedobj.common", "Can not retrieve own storage media type!" );
1356 PostEvent_Impl( "OnSaveAs" );
1358 bool bTryOptimization
= false;
1359 for ( sal_Int32 nInd
= 0; nInd
< lObjArgs
.getLength(); nInd
++ )
1361 // StoreVisualReplacement and VisualReplacement args have no sense here
1362 if ( lObjArgs
[nInd
].Name
== "CanTryOptimization" )
1363 lObjArgs
[nInd
].Value
>>= bTryOptimization
;
1366 bool bSwitchBackToLoaded
= false;
1368 // Storing to different format can be done only in running state.
1369 if ( m_nObjectState
== embed::EmbedStates::LOADED
)
1371 // TODO/LATER: copying is not legal for documents with relative links.
1372 if ( nTargetStorageFormat
== nOriginalStorageFormat
)
1374 bool bOptimizationWorks
= false;
1375 if ( bTryOptimization
)
1379 // try to use optimized copying
1380 uno::Reference
< embed::XOptimizedStorage
> xSource( m_xParentStorage
, uno::UNO_QUERY_THROW
);
1381 uno::Reference
< embed::XOptimizedStorage
> xTarget( xStorage
, uno::UNO_QUERY_THROW
);
1382 xSource
->copyElementDirectlyTo( m_aEntryName
, xTarget
, sEntName
);
1383 bOptimizationWorks
= true;
1385 catch( const uno::Exception
& )
1390 if ( !bOptimizationWorks
)
1391 m_xParentStorage
->copyElementTo( m_aEntryName
, xStorage
, sEntName
);
1395 changeState( embed::EmbedStates::RUNNING
);
1396 bSwitchBackToLoaded
= true;
1400 uno::Reference
< embed::XStorage
> xSubStorage
=
1401 xStorage
->openStorageElement( sEntName
, embed::ElementModes::READWRITE
);
1403 if ( !xSubStorage
.is() )
1404 throw uno::RuntimeException(); //TODO
1406 if ( m_nObjectState
!= embed::EmbedStates::LOADED
)
1409 // TODO/LATER: support hierarchical name for embedded objects in embedded objects
1410 StoreDocToStorage_Impl(
1411 xSubStorage
, lArguments
, lObjArgs
, nTargetStorageFormat
, sEntName
, false );
1414 if ( bSwitchBackToLoaded
)
1415 changeState( embed::EmbedStates::LOADED
);
1418 m_bWaitSaveCompleted
= true;
1419 m_xNewObjectStorage
= xSubStorage
;
1420 m_xNewParentStorage
= xStorage
;
1421 m_aNewEntryName
= sEntName
;
1422 m_aNewDocMediaDescriptor
= GetValuableArgs_Impl( lArguments
, true );
1424 // TODO: register listeners for storages above, in case thay are disposed
1425 // an exception will be thrown on saveCompleted( true )
1427 // TODO: should the listener notification be done here or in saveCompleted?
1431 void SAL_CALL
OCommonEmbeddedObject::saveCompleted( sal_Bool bUseNew
)
1432 throw ( embed::WrongStateException
,
1434 uno::RuntimeException
, std::exception
)
1436 ::osl::MutexGuard
aGuard( m_aMutex
);
1438 throw lang::DisposedException(); // TODO
1440 if ( m_nObjectState
== -1 )
1442 // the object is still not loaded
1443 throw embed::WrongStateException( "Can't store object without persistence!",
1444 static_cast< ::cppu::OWeakObject
* >(this) );
1447 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1448 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1449 // OSL_ENSURE( !m_bIsLink, "This method implementation must not be used for links!\n" );
1453 m_aEntryName
= m_aNewEntryName
;
1454 m_aNewEntryName
.clear();
1458 // it is allowed to call saveCompleted( false ) for nonstored objects
1459 if ( !m_bWaitSaveCompleted
&& !bUseNew
)
1462 SAL_WARN_IF( !m_bWaitSaveCompleted
, "embeddedobj.common", "Unexpected saveCompleted() call!" );
1463 if ( !m_bWaitSaveCompleted
)
1464 throw io::IOException(); // TODO: illegal call
1466 OSL_ENSURE( m_xNewObjectStorage
.is() && m_xNewParentStorage
.is() , "Internal object information is broken!\n" );
1467 if ( !m_xNewObjectStorage
.is() || !m_xNewParentStorage
.is() )
1468 throw uno::RuntimeException(); // TODO: broken internal information
1472 SwitchOwnPersistence( m_xNewParentStorage
, m_xNewObjectStorage
, m_aNewEntryName
);
1473 m_aDocMediaDescriptor
= m_aNewDocMediaDescriptor
;
1475 uno::Reference
< util::XModifiable
> xModif( m_pDocHolder
->GetComponent(), uno::UNO_QUERY
);
1477 xModif
->setModified( false );
1479 PostEvent_Impl( "OnSaveAsDone");
1484 uno::Reference
< lang::XComponent
> xComponent( m_xNewObjectStorage
, uno::UNO_QUERY
);
1485 SAL_WARN_IF( !xComponent
.is(), "embeddedobj.common", "Wrong storage implementation!" );
1486 if ( xComponent
.is() )
1487 xComponent
->dispose();
1489 catch ( const uno::Exception
& )
1494 m_xNewObjectStorage
.clear();
1495 m_xNewParentStorage
.clear();
1496 m_aNewEntryName
.clear();
1497 m_aNewDocMediaDescriptor
.realloc( 0 );
1498 m_bWaitSaveCompleted
= false;
1502 // TODO: notify listeners
1504 if ( m_nUpdateMode
== embed::EmbedUpdateModes::ALWAYS_UPDATE
)
1506 // TODO: update visual representation
1512 sal_Bool SAL_CALL
OCommonEmbeddedObject::hasEntry()
1513 throw ( embed::WrongStateException
,
1514 uno::RuntimeException
, std::exception
)
1516 ::osl::MutexGuard
aGuard( m_aMutex
);
1518 throw lang::DisposedException(); // TODO
1520 if ( m_bWaitSaveCompleted
)
1521 throw embed::WrongStateException(
1522 "The object waits for saveCompleted() call!",
1523 static_cast< ::cppu::OWeakObject
* >(this) );
1525 if ( m_xObjectStorage
.is() )
1532 OUString SAL_CALL
OCommonEmbeddedObject::getEntryName()
1533 throw ( embed::WrongStateException
,
1534 uno::RuntimeException
, std::exception
)
1536 ::osl::MutexGuard
aGuard( m_aMutex
);
1538 throw lang::DisposedException(); // TODO
1540 if ( m_nObjectState
== -1 )
1542 // the object is still not loaded
1543 throw embed::WrongStateException( "The object persistence is not initialized!",
1544 static_cast< ::cppu::OWeakObject
* >(this) );
1547 if ( m_bWaitSaveCompleted
)
1548 throw embed::WrongStateException(
1549 "The object waits for saveCompleted() call!",
1550 static_cast< ::cppu::OWeakObject
* >(this) );
1552 return m_aEntryName
;
1556 void SAL_CALL
OCommonEmbeddedObject::storeOwn()
1557 throw ( embed::WrongStateException
,
1560 uno::RuntimeException
, std::exception
)
1562 // during switching from Activated to Running and from Running to Loaded states the object will
1563 // ask container to store the object, the container has to make decision
1566 ::osl::ResettableMutexGuard
aGuard( m_aMutex
);
1568 throw lang::DisposedException(); // TODO
1570 if ( m_nObjectState
== -1 )
1572 // the object is still not loaded
1573 throw embed::WrongStateException( "Can't store object without persistence!",
1574 static_cast< ::cppu::OWeakObject
* >(this) );
1577 if ( m_bWaitSaveCompleted
)
1578 throw embed::WrongStateException(
1579 "The object waits for saveCompleted() call!",
1580 static_cast< ::cppu::OWeakObject
* >(this) );
1583 throw io::IOException(); // TODO: access denied
1585 // nothing to do, if the object is in loaded state
1586 if ( m_nObjectState
== embed::EmbedStates::LOADED
)
1589 PostEvent_Impl( "OnSave" );
1591 SAL_WARN_IF( !m_pDocHolder
->GetComponent().is(), "embeddedobj.common", "If an object is activated or in running state it must have a document!" );
1592 if ( !m_pDocHolder
->GetComponent().is() )
1593 throw uno::RuntimeException();
1597 // TODO: just store the document to its location
1598 uno::Reference
< frame::XStorable
> xStorable( m_pDocHolder
->GetComponent(), uno::UNO_QUERY
);
1599 if ( !xStorable
.is() )
1600 throw uno::RuntimeException(); // TODO
1602 // free the main mutex for the storing time
1611 OSL_ENSURE( m_xParentStorage
.is() && m_xObjectStorage
.is(), "The object has no valid persistence!\n" );
1613 if ( !m_xObjectStorage
.is() )
1614 throw io::IOException(); //TODO: access denied
1616 sal_Int32 nStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1618 nStorageFormat
= ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage
);
1620 catch ( const beans::IllegalTypeException
& )
1622 // the container just has an unknown type, use current file format
1624 catch ( const uno::Exception
& )
1626 SAL_WARN( "embeddedobj.common", "Can not retrieve storage media type!" );
1628 if (nStorageFormat
== SOFFICE_FILEFORMAT_60
)
1630 SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1631 nStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1632 // setting MediaType is done later anyway, no need to do it here
1636 uno::Sequence
<beans::PropertyValue
> aEmpty
;
1637 uno::Sequence
<beans::PropertyValue
> aMediaArgs(1);
1638 aMediaArgs
[0].Name
= "DocumentBaseURL";
1639 aMediaArgs
[0].Value
<<= GetBaseURL_Impl();
1640 StoreDocToStorage_Impl( m_xObjectStorage
, aMediaArgs
, aEmpty
, nStorageFormat
, m_aEntryName
, true );
1644 uno::Reference
< util::XModifiable
> xModif( m_pDocHolder
->GetComponent(), uno::UNO_QUERY
);
1646 xModif
->setModified( false );
1648 PostEvent_Impl( "OnSaveDone" );
1652 sal_Bool SAL_CALL
OCommonEmbeddedObject::isReadonly()
1653 throw ( embed::WrongStateException
,
1654 uno::RuntimeException
, std::exception
)
1656 ::osl::MutexGuard
aGuard( m_aMutex
);
1658 throw lang::DisposedException(); // TODO
1660 if ( m_nObjectState
== -1 )
1662 // the object is still not loaded
1663 throw embed::WrongStateException( "The object persistence is not initialized!",
1664 static_cast< ::cppu::OWeakObject
* >(this) );
1667 if ( m_bWaitSaveCompleted
)
1668 throw embed::WrongStateException(
1669 "The object waits for saveCompleted() call!",
1670 static_cast< ::cppu::OWeakObject
* >(this) );
1676 void SAL_CALL
OCommonEmbeddedObject::reload(
1677 const uno::Sequence
< beans::PropertyValue
>& lArguments
,
1678 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
1679 throw ( lang::IllegalArgumentException
,
1680 embed::WrongStateException
,
1683 uno::RuntimeException
, std::exception
)
1685 // TODO: use lObjArgs
1686 // for now this method is used only to switch readonly state
1688 ::osl::MutexGuard
aGuard( m_aMutex
);
1690 throw lang::DisposedException(); // TODO
1692 if ( m_nObjectState
== -1 )
1694 // the object is still not loaded
1695 throw embed::WrongStateException( "The object persistence is not initialized!",
1696 static_cast< ::cppu::OWeakObject
* >(this) );
1699 if ( m_nObjectState
!= embed::EmbedStates::LOADED
)
1701 // the object is still not loaded
1702 throw embed::WrongStateException(
1703 "The object must be in loaded state to be reloaded!",
1704 static_cast< ::cppu::OWeakObject
* >(this) );
1707 if ( m_bWaitSaveCompleted
)
1708 throw embed::WrongStateException(
1709 "The object waits for saveCompleted() call!",
1710 static_cast< ::cppu::OWeakObject
* >(this) );
1714 // reload of the link
1715 OUString aOldLinkFilter
= m_aLinkFilterName
;
1717 OUString aNewLinkFilter
;
1718 for ( sal_Int32 nInd
= 0; nInd
< lArguments
.getLength(); nInd
++ )
1720 if ( lArguments
[nInd
].Name
== "URL" )
1723 lArguments
[nInd
].Value
>>= m_aLinkURL
;
1724 m_aLinkFilterName
.clear();
1726 else if ( lArguments
[nInd
].Name
== "FilterName" )
1728 lArguments
[nInd
].Value
>>= aNewLinkFilter
;
1729 m_aLinkFilterName
.clear();
1733 ::comphelper::MimeConfigurationHelper
aHelper( m_xContext
);
1734 if ( m_aLinkFilterName
.isEmpty() )
1736 if ( !aNewLinkFilter
.isEmpty() )
1737 m_aLinkFilterName
= aNewLinkFilter
;
1740 uno::Sequence
< beans::PropertyValue
> aArgs( 1 );
1741 aArgs
[0].Name
= "URL";
1742 aArgs
[0].Value
<<= m_aLinkURL
;
1743 m_aLinkFilterName
= aHelper
.UpdateMediaDescriptorWithFilterName( aArgs
, false );
1747 if ( !aOldLinkFilter
.equals( m_aLinkFilterName
) )
1749 uno::Sequence
< beans::NamedValue
> aObject
= aHelper
.GetObjectPropsByFilter( m_aLinkFilterName
);
1751 // TODO/LATER: probably the document holder could be cleaned explicitly as in the destructor
1752 m_pDocHolder
->release();
1753 m_pDocHolder
= nullptr;
1755 LinkInit_Impl( aObject
, lArguments
, lObjArgs
);
1759 m_aDocMediaDescriptor
= GetValuableArgs_Impl( lArguments
, true );
1761 // TODO: use lObjArgs for StoreVisualReplacement
1762 for ( sal_Int32 nObjInd
= 0; nObjInd
< lObjArgs
.getLength(); nObjInd
++ )
1763 if ( lObjArgs
[nObjInd
].Name
== "OutplaceDispatchInterceptor" )
1765 uno::Reference
< frame::XDispatchProviderInterceptor
> xDispatchInterceptor
;
1766 if ( lObjArgs
[nObjInd
].Value
>>= xDispatchInterceptor
)
1767 m_pDocHolder
->SetOutplaceDispatchInterceptor( xDispatchInterceptor
);
1773 // when document allows reloading through API the object can be reloaded not only in loaded state
1775 bool bOldReadOnlyValue
= m_bReadOnly
;
1777 m_bReadOnly
= false;
1778 for ( sal_Int32 nInd
= 0; nInd
< lArguments
.getLength(); nInd
++ )
1779 if ( lArguments
[nInd
].Name
== "ReadOnly" )
1780 lArguments
[nInd
].Value
>>= m_bReadOnly
;
1782 if ( bOldReadOnlyValue
!= m_bReadOnly
&& !m_bIsLink
)
1784 // close own storage
1786 uno::Reference
< lang::XComponent
> xComponent( m_xObjectStorage
, uno::UNO_QUERY
);
1787 OSL_ENSURE( !m_xObjectStorage
.is() || xComponent
.is(), "Wrong storage implementation!" );
1788 if ( xComponent
.is() )
1789 xComponent
->dispose();
1791 catch ( const uno::Exception
& )
1795 sal_Int32 nStorageMode
= m_bReadOnly
? embed::ElementModes::READ
: embed::ElementModes::READWRITE
;
1796 m_xObjectStorage
= m_xParentStorage
->openStorageElement( m_aEntryName
, nStorageMode
);
1800 sal_Bool SAL_CALL
OCommonEmbeddedObject::isStored() throw (css::uno::RuntimeException
, std::exception
)
1802 uno::Reference
<container::XNameAccess
> xNA(m_xObjectStorage
, uno::UNO_QUERY
);
1806 return xNA
->getElementNames().getLength() > 0;
1810 void SAL_CALL
OCommonEmbeddedObject::breakLink( const uno::Reference
< embed::XStorage
>& xStorage
,
1811 const OUString
& sEntName
)
1812 throw ( lang::IllegalArgumentException
,
1813 embed::WrongStateException
,
1816 uno::RuntimeException
, std::exception
)
1818 ::osl::ResettableMutexGuard
aGuard( m_aMutex
);
1820 throw lang::DisposedException(); // TODO
1824 // it must be a linked initialized object
1825 throw embed::WrongStateException(
1826 "The object is not a valid linked object!",
1827 static_cast< ::cppu::OWeakObject
* >(this) );
1831 // the current implementation of OOo links does not implement this method since it does not implement
1832 // all the set of interfaces required for OOo embedded object ( XEmbedPersist is not supported ).
1835 if ( !xStorage
.is() )
1836 throw lang::IllegalArgumentException( "No parent storage is provided!",
1837 static_cast< ::cppu::OWeakObject
* >(this),
1840 if ( sEntName
.isEmpty() )
1841 throw lang::IllegalArgumentException( "Empty element name is provided!",
1842 static_cast< ::cppu::OWeakObject
* >(this),
1845 if ( !m_bIsLink
|| m_nObjectState
== -1 )
1847 // it must be a linked initialized object
1848 throw embed::WrongStateException(
1849 "The object is not a valid linked object!",
1850 static_cast< ::cppu::OWeakObject
* >(this) );
1853 if ( m_bWaitSaveCompleted
)
1854 throw embed::WrongStateException(
1855 "The object waits for saveCompleted() call!",
1856 static_cast< ::cppu::OWeakObject
* >(this) );
1858 uno::Reference
< container::XNameAccess
> xNameAccess( xStorage
, uno::UNO_QUERY
);
1859 if ( !xNameAccess
.is() )
1860 throw uno::RuntimeException(); //TODO
1862 m_bReadOnly
= false;
1864 if ( m_xParentStorage
!= xStorage
|| !m_aEntryName
.equals( sEntName
) )
1865 SwitchOwnPersistence( xStorage
, sEntName
);
1867 // for linked object it means that it becomes embedded object
1868 // the document must switch it's persistence also
1870 // TODO/LATER: handle the case when temp doc can not be created
1871 // the document is a new embedded object so it must be marked as modified
1872 uno::Reference
< util::XCloseable
> xDocument
= CreateTempDocFromLink_Impl();
1873 uno::Reference
< util::XModifiable
> xModif( m_pDocHolder
->GetComponent(), uno::UNO_QUERY
);
1875 throw uno::RuntimeException();
1878 xModif
->setModified( true );
1880 catch( const uno::Exception
& )
1883 m_pDocHolder
->SetComponent( xDocument
, m_bReadOnly
);
1884 SAL_WARN_IF( !m_pDocHolder
->GetComponent().is(), "embeddedobj.common", "If document can't be created, an exception must be thrown!" );
1886 if ( m_nObjectState
== embed::EmbedStates::LOADED
)
1888 // the state is changed and can not be switched to loaded state back without saving
1889 m_nObjectState
= embed::EmbedStates::RUNNING
;
1890 StateChangeNotification_Impl( false, embed::EmbedStates::LOADED
, m_nObjectState
, aGuard
);
1892 else if ( m_nObjectState
== embed::EmbedStates::ACTIVE
)
1893 m_pDocHolder
->Show();
1896 m_aLinkFilterName
.clear();
1901 sal_Bool SAL_CALL
OCommonEmbeddedObject::isLink()
1902 throw ( embed::WrongStateException
,
1903 uno::RuntimeException
, std::exception
)
1905 ::osl::MutexGuard
aGuard( m_aMutex
);
1907 throw lang::DisposedException(); // TODO
1913 OUString SAL_CALL
OCommonEmbeddedObject::getLinkURL()
1914 throw ( embed::WrongStateException
,
1916 uno::RuntimeException
, std::exception
)
1918 ::osl::MutexGuard
aGuard( m_aMutex
);
1920 throw lang::DisposedException(); // TODO
1923 throw embed::WrongStateException(
1924 "The object is not a link object!",
1925 static_cast< ::cppu::OWeakObject
* >(this) );
1930 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */