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 <com/sun/star/container/XChild.hpp>
21 #include <com/sun/star/container/XNameAccess.hpp>
22 #include <com/sun/star/embed/EmbeddedObjectCreator.hpp>
23 #include <com/sun/star/embed/WrongStateException.hpp>
24 #include <com/sun/star/embed/XEmbeddedObject.hpp>
25 #include <com/sun/star/embed/XEmbedPersist.hpp>
26 #include <com/sun/star/embed/XLinkageSupport.hpp>
27 #include <com/sun/star/embed/XTransactedObject.hpp>
28 #include <com/sun/star/embed/XOptimizedStorage.hpp>
29 #include <com/sun/star/embed/EntryInitModes.hpp>
30 #include <com/sun/star/io/IOException.hpp>
31 #include <com/sun/star/util/XCloseable.hpp>
32 #include <com/sun/star/util/XModifiable.hpp>
33 #include <com/sun/star/embed/EmbedStates.hpp>
34 #include <com/sun/star/beans/XPropertySetInfo.hpp>
35 #include <com/sun/star/beans/XPropertySet.hpp>
36 #include <com/sun/star/embed/Aspects.hpp>
37 #include <com/sun/star/embed/EmbedMisc.hpp>
39 #include <comphelper/seqstream.hxx>
40 #include <comphelper/processfactory.hxx>
41 #include <comphelper/storagehelper.hxx>
42 #include <comphelper/embeddedobjectcontainer.hxx>
43 #include <comphelper/sequence.hxx>
44 #include <comphelper/propertysequence.hxx>
45 #include <comphelper/propertyvalue.hxx>
46 #include <cppuhelper/weakref.hxx>
47 #include <sal/log.hxx>
50 #include <unordered_map>
53 using namespace ::com::sun::star
;
55 namespace comphelper
{
57 typedef std::unordered_map
<OUString
, uno::Reference
<embed::XEmbeddedObject
>> EmbeddedObjectContainerNameMap
;
60 // TODO/LATER: remove objects from temp. Container storage when object is disposed
61 EmbeddedObjectContainerNameMap maNameToObjectMap
;
62 // to speed up lookup by Reference
63 std::unordered_map
<uno::Reference
<embed::XEmbeddedObject
>, OUString
> maObjectToNameMap
;
64 uno::Reference
< embed::XStorage
> mxStorage
;
65 EmbeddedObjectContainer
* mpTempObjectContainer
;
66 uno::Reference
< embed::XStorage
> mxImageStorage
;
67 uno::WeakReference
< uno::XInterface
> m_xModel
;
69 bool mbOwnsStorage
: 1;
70 bool mbUserAllowsLinkUpdate
: 1;
72 const uno::Reference
< embed::XStorage
>& GetReplacements();
75 const uno::Reference
< embed::XStorage
>& EmbedImpl::GetReplacements()
77 if ( !mxImageStorage
.is() )
81 mxImageStorage
= mxStorage
->openStorageElement(
82 "ObjectReplacements", embed::ElementModes::READWRITE
);
84 catch (const uno::Exception
&)
86 mxImageStorage
= mxStorage
->openStorageElement(
87 "ObjectReplacements", embed::ElementModes::READ
);
91 if ( !mxImageStorage
.is() )
92 throw io::IOException("No ObjectReplacements");
94 return mxImageStorage
;
97 EmbeddedObjectContainer::EmbeddedObjectContainer()
98 : pImpl(new EmbedImpl
)
100 pImpl
->mxStorage
= ::comphelper::OStorageHelper::GetTemporaryStorage();
101 pImpl
->mbOwnsStorage
= true;
102 pImpl
->mbUserAllowsLinkUpdate
= true;
103 pImpl
->mpTempObjectContainer
= nullptr;
106 EmbeddedObjectContainer::EmbeddedObjectContainer( const uno::Reference
< embed::XStorage
>& rStor
)
107 : pImpl(new EmbedImpl
)
109 pImpl
->mxStorage
= rStor
;
110 pImpl
->mbOwnsStorage
= false;
111 pImpl
->mbUserAllowsLinkUpdate
= true;
112 pImpl
->mpTempObjectContainer
= nullptr;
115 EmbeddedObjectContainer::EmbeddedObjectContainer( const uno::Reference
< embed::XStorage
>& rStor
, const uno::Reference
< uno::XInterface
>& xModel
)
116 : pImpl(new EmbedImpl
)
118 pImpl
->mxStorage
= rStor
;
119 pImpl
->mbOwnsStorage
= false;
120 pImpl
->mbUserAllowsLinkUpdate
= true;
121 pImpl
->mpTempObjectContainer
= nullptr;
122 pImpl
->m_xModel
= xModel
;
125 void EmbeddedObjectContainer::SwitchPersistence( const uno::Reference
< embed::XStorage
>& rStor
)
127 ReleaseImageSubStorage();
129 if ( pImpl
->mbOwnsStorage
)
130 pImpl
->mxStorage
->dispose();
132 pImpl
->mxStorage
= rStor
;
133 pImpl
->mbOwnsStorage
= false;
136 bool EmbeddedObjectContainer::CommitImageSubStorage()
138 if ( !pImpl
->mxImageStorage
)
143 bool bReadOnlyMode
= true;
144 uno::Reference
< beans::XPropertySet
> xSet(pImpl
->mxImageStorage
,uno::UNO_QUERY
);
147 // get the open mode from the parent storage
149 uno::Any aAny
= xSet
->getPropertyValue("OpenMode");
150 if ( aAny
>>= nMode
)
151 bReadOnlyMode
= !(nMode
& embed::ElementModes::WRITE
);
152 } // if ( xSet.is() )
153 if ( !bReadOnlyMode
)
155 uno::Reference
< embed::XTransactedObject
> xTransact( pImpl
->mxImageStorage
, uno::UNO_QUERY_THROW
);
159 catch (const uno::Exception
&)
167 void EmbeddedObjectContainer::ReleaseImageSubStorage()
169 CommitImageSubStorage();
171 if ( pImpl
->mxImageStorage
.is() )
175 pImpl
->mxImageStorage
->dispose();
176 pImpl
->mxImageStorage
.clear();
178 catch (const uno::Exception
&)
180 SAL_WARN( "comphelper.container", "Problems releasing image substorage!" );
185 EmbeddedObjectContainer::~EmbeddedObjectContainer()
187 ReleaseImageSubStorage();
189 if ( pImpl
->mbOwnsStorage
)
190 pImpl
->mxStorage
->dispose();
192 delete pImpl
->mpTempObjectContainer
;
195 void EmbeddedObjectContainer::CloseEmbeddedObjects()
197 for( const auto& rObj
: pImpl
->maNameToObjectMap
)
199 uno::Reference
< util::XCloseable
> const & xClose
= rObj
.second
;
204 xClose
->close( true );
206 catch (const uno::Exception
&)
213 OUString
EmbeddedObjectContainer::CreateUniqueObjectName()
219 aStr
= "Object " + OUString::number( i
++ );
221 while( HasEmbeddedObject( aStr
) );
222 // TODO/LATER: should we consider deleted objects?
227 uno::Sequence
< OUString
> EmbeddedObjectContainer::GetObjectNames() const
229 return comphelper::mapKeysToSequence(pImpl
->maNameToObjectMap
);
232 bool EmbeddedObjectContainer::HasEmbeddedObjects() const
234 return !pImpl
->maNameToObjectMap
.empty();
237 bool EmbeddedObjectContainer::HasEmbeddedObject( const OUString
& rName
)
239 auto aIt
= pImpl
->maNameToObjectMap
.find( rName
);
240 if (aIt
!= pImpl
->maNameToObjectMap
.end())
242 if (!pImpl
->mxStorage
.is())
244 return pImpl
->mxStorage
->hasByName(rName
);
247 bool EmbeddedObjectContainer::HasEmbeddedObject( const uno::Reference
< embed::XEmbeddedObject
>& xObj
) const
249 return pImpl
->maObjectToNameMap
.find(xObj
) != pImpl
->maObjectToNameMap
.end();
252 bool EmbeddedObjectContainer::HasInstantiatedEmbeddedObject( const OUString
& rName
)
254 // allows to detect whether the object was already instantiated
255 // currently the filter instantiate it on loading, so this method allows
256 // to avoid objects pointing to the same persistence
257 auto aIt
= pImpl
->maNameToObjectMap
.find( rName
);
258 return ( aIt
!= pImpl
->maNameToObjectMap
.end() );
261 OUString
EmbeddedObjectContainer::GetEmbeddedObjectName( const css::uno::Reference
< css::embed::XEmbeddedObject
>& xObj
) const
263 auto it
= pImpl
->maObjectToNameMap
.find(xObj
);
264 if (it
== pImpl
->maObjectToNameMap
.end())
266 SAL_WARN( "comphelper.container", "Unknown object!" );
272 uno::Reference
< embed::XEmbeddedObject
>
273 EmbeddedObjectContainer::GetEmbeddedObject(
274 const OUString
& rName
, OUString
const*const pBaseURL
)
276 SAL_WARN_IF( rName
.isEmpty(), "comphelper.container", "Empty object name!");
278 uno::Reference
< embed::XEmbeddedObject
> xObj
;
279 auto aIt
= pImpl
->maNameToObjectMap
.find( rName
);
281 #if OSL_DEBUG_LEVEL > 1
282 uno::Reference
< container::XNameAccess
> xAccess( pImpl
->mxStorage
, uno::UNO_QUERY
);
283 uno::Sequence
< OUString
> aSeq
= xAccess
->getElementNames();
284 const OUString
* pIter
= aSeq
.getConstArray();
285 const OUString
* pEnd
= pIter
+ aSeq
.getLength();
286 for(;pIter
!= pEnd
;++pIter
)
290 OSL_ENSURE( aIt
!= pImpl
->maNameToObjectMap
.end() || xAccess
->hasByName(rName
), "Could not return object!" );
293 // check if object was already created
294 if ( aIt
!= pImpl
->maNameToObjectMap
.end() )
295 xObj
= (*aIt
).second
;
297 xObj
= Get_Impl(rName
, uno::Reference
<embed::XEmbeddedObject
>(), pBaseURL
);
302 uno::Reference
<embed::XEmbeddedObject
> EmbeddedObjectContainer::Get_Impl(
303 const OUString
& rName
,
304 const uno::Reference
<embed::XEmbeddedObject
>& xCopy
,
305 OUString
const*const pBaseURL
)
307 uno::Reference
< embed::XEmbeddedObject
> xObj
;
310 // create the object from the storage
311 uno::Reference
< beans::XPropertySet
> xSet( pImpl
->mxStorage
, uno::UNO_QUERY
);
312 bool bReadOnlyMode
= true;
315 // get the open mode from the parent storage
317 uno::Any aAny
= xSet
->getPropertyValue("OpenMode");
318 if ( aAny
>>= nMode
)
319 bReadOnlyMode
= !(nMode
& embed::ElementModes::WRITE
);
322 // object was not added until now - should happen only by calling this method from "inside"
323 //TODO/LATER: it would be good to detect an error when an object should be created already, but isn't (not an "inside" call)
324 uno::Reference
< embed::XEmbeddedObjectCreator
> xFactory
= embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() );
325 uno::Sequence
< beans::PropertyValue
> aObjDescr(1 + (xCopy
.is() ? 1 : 0) + (pBaseURL
? 1 : 0));
326 auto itObjDescr
= aObjDescr
.getArray();
327 itObjDescr
->Name
= "Parent";
328 itObjDescr
->Value
<<= pImpl
->m_xModel
.get();
332 itObjDescr
->Name
= "DefaultParentBaseURL";
333 itObjDescr
->Value
<<= *pBaseURL
;
338 itObjDescr
->Name
= "CloneFrom";
339 itObjDescr
->Value
<<= xCopy
;
342 uno::Sequence
< beans::PropertyValue
> aMediaDescr
{ comphelper::makePropertyValue(
343 "ReadOnly", bReadOnlyMode
) };
344 xObj
.set( xFactory
->createInstanceInitFromEntry(
345 pImpl
->mxStorage
, rName
,
346 aMediaDescr
, aObjDescr
), uno::UNO_QUERY
);
348 // insert object into my list
349 AddEmbeddedObject( xObj
, rName
);
351 catch (uno::Exception
const& e
)
353 SAL_WARN("comphelper.container", "EmbeddedObjectContainer::Get_Impl: exception caught: " << e
);
359 uno::Reference
< embed::XEmbeddedObject
> EmbeddedObjectContainer::CreateEmbeddedObject( const uno::Sequence
< sal_Int8
>& rClassId
,
360 const uno::Sequence
< beans::PropertyValue
>& rArgs
, OUString
& rNewName
, OUString
const* pBaseURL
)
362 if ( rNewName
.isEmpty() )
363 rNewName
= CreateUniqueObjectName();
365 SAL_WARN_IF( HasEmbeddedObject(rNewName
), "comphelper.container", "Object to create already exists!");
367 // create object from classid by inserting it into storage
368 uno::Reference
< embed::XEmbeddedObject
> xObj
;
371 uno::Reference
< embed::XEmbeddedObjectCreator
> xFactory
= embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() );
373 const size_t nExtraArgs
= pBaseURL
? 2 : 1;
374 uno::Sequence
< beans::PropertyValue
> aObjDescr( rArgs
.getLength() + nExtraArgs
);
375 auto pObjDescr
= aObjDescr
.getArray();
376 pObjDescr
[0].Name
= "Parent";
377 pObjDescr
[0].Value
<<= pImpl
->m_xModel
.get();
380 pObjDescr
[1].Name
= "DefaultParentBaseURL";
381 pObjDescr
[1].Value
<<= *pBaseURL
;
383 std::copy( rArgs
.begin(), rArgs
.end(), pObjDescr
+ nExtraArgs
);
384 xObj
.set( xFactory
->createInstanceInitNew(
385 rClassId
, OUString(), pImpl
->mxStorage
, rNewName
,
386 aObjDescr
), uno::UNO_QUERY
);
388 AddEmbeddedObject( xObj
, rNewName
);
390 OSL_ENSURE( !xObj
.is() || xObj
->getCurrentState() != embed::EmbedStates::LOADED
,
391 "A freshly create object should be running always!" );
393 catch (uno::Exception
const& e
)
395 SAL_WARN("comphelper.container", "EmbeddedObjectContainer::CreateEmbeddedObject: exception caught: " << e
);
401 uno::Reference
< embed::XEmbeddedObject
> EmbeddedObjectContainer::CreateEmbeddedObject( const uno::Sequence
< sal_Int8
>& rClassId
, OUString
& rNewName
, OUString
const* pBaseURL
)
403 return CreateEmbeddedObject( rClassId
, uno::Sequence
< beans::PropertyValue
>(), rNewName
, pBaseURL
);
406 void EmbeddedObjectContainer::AddEmbeddedObject( const css::uno::Reference
< css::embed::XEmbeddedObject
>& xObj
, const OUString
& rName
)
408 #if OSL_DEBUG_LEVEL > 1
409 SAL_WARN_IF( rName
.isEmpty(), "comphelper.container", "Added object doesn't have a name!");
410 uno::Reference
< container::XNameAccess
> xAccess( pImpl
->mxStorage
, uno::UNO_QUERY
);
411 uno::Reference
< embed::XEmbedPersist
> xEmb( xObj
, uno::UNO_QUERY
);
412 uno::Reference
< embed::XLinkageSupport
> xLink( xEmb
, uno::UNO_QUERY
);
413 // if the object has a persistence and the object is not a link than it must have persistence entry in the storage
414 OSL_ENSURE( !( xEmb
.is() && ( !xLink
.is() || !xLink
->isLink() ) ) || xAccess
->hasByName(rName
),
415 "Added element not in storage!" );
418 // remember object - it needs to be in storage already
419 auto aIt
= pImpl
->maNameToObjectMap
.find( rName
);
420 OSL_ENSURE( aIt
== pImpl
->maNameToObjectMap
.end(), "Element already inserted!" );
421 pImpl
->maNameToObjectMap
[ rName
] = xObj
;
422 pImpl
->maObjectToNameMap
[ xObj
] = rName
;
423 uno::Reference
< container::XChild
> xChild( xObj
, uno::UNO_QUERY
);
424 if ( xChild
.is() && xChild
->getParent() != pImpl
->m_xModel
.get() )
425 xChild
->setParent( pImpl
->m_xModel
.get() );
427 // look for object in temporary container
428 if ( !pImpl
->mpTempObjectContainer
)
431 auto& rObjectContainer
= pImpl
->mpTempObjectContainer
->pImpl
->maNameToObjectMap
;
432 auto aIter
= std::find_if(rObjectContainer
.begin(), rObjectContainer
.end(),
433 [&xObj
](const EmbeddedObjectContainerNameMap::value_type
& rEntry
) { return rEntry
.second
== xObj
; });
434 if (aIter
== rObjectContainer
.end())
437 // copy replacement image from temporary container (if there is any)
438 OUString aTempName
= aIter
->first
;
440 uno::Reference
< io::XInputStream
> xStream
= pImpl
->mpTempObjectContainer
->GetGraphicStream( xObj
, &aMediaType
);
443 InsertGraphicStream( xStream
, rName
, aMediaType
);
445 pImpl
->mpTempObjectContainer
->RemoveGraphicStream( aTempName
);
448 // remove object from storage of temporary container
449 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
454 pImpl
->mpTempObjectContainer
->pImpl
->mxStorage
->removeElement( aTempName
);
456 catch (const uno::Exception
&)
461 // temp. container needs to forget the object
462 pImpl
->mpTempObjectContainer
->pImpl
->maObjectToNameMap
.erase( aIter
->second
);
463 pImpl
->mpTempObjectContainer
->pImpl
->maNameToObjectMap
.erase( aIter
);
466 bool EmbeddedObjectContainer::StoreEmbeddedObject(
467 const uno::Reference
< embed::XEmbeddedObject
>& xObj
, OUString
& rName
, bool bCopy
,
468 const OUString
& rSrcShellID
, const OUString
& rDestShellID
)
470 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
471 if ( rName
.isEmpty() )
472 rName
= CreateUniqueObjectName();
474 #if OSL_DEBUG_LEVEL > 1
475 uno::Reference
< container::XNameAccess
> xAccess( pImpl
->mxStorage
, uno::UNO_QUERY
);
476 OSL_ENSURE( !xPersist
.is() || !xAccess
->hasByName(rName
), "Inserting element already present in storage!" );
477 OSL_ENSURE( xPersist
.is() || xObj
->getCurrentState() == embed::EmbedStates::RUNNING
, "Non persistent object inserted!");
480 // insert objects' storage into the container storage (if object has one)
485 uno::Sequence
< beans::PropertyValue
> aSeq
;
488 auto aObjArgs(::comphelper::InitPropertySequence({
489 { "SourceShellID", uno::Any(rSrcShellID
) },
490 { "DestinationShellID", uno::Any(rDestShellID
) }
492 xPersist
->storeToEntry(pImpl
->mxStorage
, rName
, aSeq
, aObjArgs
);
496 //TODO/LATER: possible optimization, don't store immediately
497 //xPersist->setPersistentEntry( pImpl->mxStorage, rName, embed::EntryInitModes::ENTRY_NO_INIT, aSeq, aSeq );
498 xPersist
->storeAsEntry( pImpl
->mxStorage
, rName
, aSeq
, aSeq
);
499 xPersist
->saveCompleted( true );
503 catch (uno::Exception
const& e
)
505 SAL_WARN("comphelper.container", "EmbeddedObjectContainer::StoreEmbeddedObject: exception caught: " << e
);
506 // TODO/LATER: better error recovery should keep storage intact
513 bool EmbeddedObjectContainer::InsertEmbeddedObject( const uno::Reference
< embed::XEmbeddedObject
>& xObj
, OUString
& rName
)
515 // store it into the container storage
516 if (StoreEmbeddedObject(xObj
, rName
, false, OUString(), OUString()))
519 AddEmbeddedObject( xObj
, rName
);
526 uno::Reference
< embed::XEmbeddedObject
> EmbeddedObjectContainer::InsertEmbeddedObject( const uno::Reference
< io::XInputStream
>& xStm
, OUString
& rNewName
)
528 if ( rNewName
.isEmpty() )
529 rNewName
= CreateUniqueObjectName();
531 // store it into the container storage
532 bool bIsStorage
= false;
535 // first try storage persistence
536 uno::Reference
< embed::XStorage
> xStore
= ::comphelper::OStorageHelper::GetStorageFromInputStream( xStm
);
538 // storage was created from stream successfully
541 uno::Reference
< embed::XStorage
> xNewStore
= pImpl
->mxStorage
->openStorageElement( rNewName
, embed::ElementModes::READWRITE
);
542 xStore
->copyToStorage( xNewStore
);
544 catch (const uno::Exception
&)
547 // it is storage persistence, but opening of new substorage or copying to it failed
548 return uno::Reference
< embed::XEmbeddedObject
>();
550 // stream didn't contain a storage, now try stream persistence
553 uno::Reference
< io::XStream
> xNewStream
= pImpl
->mxStorage
->openStreamElement( rNewName
, embed::ElementModes::READWRITE
);
554 ::comphelper::OStorageHelper::CopyInputToOutput( xStm
, xNewStream
->getOutputStream() );
556 // No mediatype is provided so the default for OLE objects value is used
557 // it is correct so for now, but what if somebody introduces a new stream based embedded object?
558 // Probably introducing of such an object must be restricted ( a storage must be used! ).
559 uno::Reference
< beans::XPropertySet
> xProps( xNewStream
, uno::UNO_QUERY_THROW
);
560 xProps
->setPropertyValue("MediaType",
561 uno::Any( OUString( "application/vnd.sun.star.oleobject" ) ) );
563 catch (uno::Exception
const& e
)
565 // complete disaster!
566 SAL_WARN("comphelper.container", "EmbeddedObjectContainer::InsertEmbeddedObject: exception caught: " << e
);
567 return uno::Reference
< embed::XEmbeddedObject
>();
571 // stream was copied into the container storage in either way, now try to open something form it
572 uno::Reference
< embed::XEmbeddedObject
> xRet
= GetEmbeddedObject( rNewName
);
576 // no object could be created, so withdraw insertion
577 pImpl
->mxStorage
->removeElement( rNewName
);
579 catch (const uno::Exception
&)
586 uno::Reference
< embed::XEmbeddedObject
> EmbeddedObjectContainer::InsertEmbeddedObject( const css::uno::Sequence
< css::beans::PropertyValue
>& aMedium
, OUString
& rNewName
, OUString
const* pBaseURL
)
588 if ( rNewName
.isEmpty() )
589 rNewName
= CreateUniqueObjectName();
591 uno::Reference
< embed::XEmbeddedObject
> xObj
;
594 uno::Reference
< embed::XEmbeddedObjectCreator
> xFactory
= embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() );
595 uno::Sequence
< beans::PropertyValue
> aObjDescr(pBaseURL
? 2 : 1);
596 auto pObjDescr
= aObjDescr
.getArray();
597 pObjDescr
[0].Name
= "Parent";
598 pObjDescr
[0].Value
<<= pImpl
->m_xModel
.get();
601 pObjDescr
[1].Name
= "DefaultParentBaseURL";
602 pObjDescr
[1].Value
<<= *pBaseURL
;
604 xObj
.set( xFactory
->createInstanceInitFromMediaDescriptor(
605 pImpl
->mxStorage
, rNewName
, aMedium
, aObjDescr
), uno::UNO_QUERY
);
606 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
608 OSL_ENSURE( !xObj
.is() || xObj
->getCurrentState() != embed::EmbedStates::LOADED
,
609 "A freshly create object should be running always!" );
611 // possible optimization: store later!
613 xPersist
->storeOwn();
615 AddEmbeddedObject( xObj
, rNewName
);
617 catch (const uno::Exception
&)
624 uno::Reference
< embed::XEmbeddedObject
> EmbeddedObjectContainer::InsertEmbeddedLink( const css::uno::Sequence
< css::beans::PropertyValue
>& aMedium
, OUString
& rNewName
)
626 if ( rNewName
.isEmpty() )
627 rNewName
= CreateUniqueObjectName();
629 uno::Reference
< embed::XEmbeddedObject
> xObj
;
632 uno::Reference
< embed::XEmbeddedObjectCreator
> xFactory
= embed::EmbeddedObjectCreator::create(::comphelper::getProcessComponentContext());
633 uno::Sequence
< beans::PropertyValue
> aObjDescr
{ comphelper::makePropertyValue(
634 "Parent", pImpl
->m_xModel
.get()) };
635 xObj
.set( xFactory
->createInstanceLink( pImpl
->mxStorage
, rNewName
, aMedium
, aObjDescr
), uno::UNO_QUERY
);
637 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
639 OSL_ENSURE( !xObj
.is() || xObj
->getCurrentState() != embed::EmbedStates::LOADED
,
640 "A freshly create object should be running always!" );
642 // possible optimization: store later!
644 xPersist
->storeOwn();
646 AddEmbeddedObject( xObj
, rNewName
);
648 catch (uno::Exception
const& e
)
650 SAL_WARN("comphelper.container", "EmbeddedObjectContainer::InsertEmbeddedLink: "
651 "exception caught: " << e
);
657 bool EmbeddedObjectContainer::TryToCopyGraphReplacement( EmbeddedObjectContainer
& rSrc
,
658 const OUString
& aOrigName
,
659 const OUString
& aTargetName
)
661 bool bResult
= false;
663 if ( ( &rSrc
!= this || aOrigName
!= aTargetName
) && !aOrigName
.isEmpty() && !aTargetName
.isEmpty() )
666 uno::Reference
< io::XInputStream
> xGrStream
= rSrc
.GetGraphicStream( aOrigName
, &aMediaType
);
667 if ( xGrStream
.is() )
668 bResult
= InsertGraphicStream( xGrStream
, aTargetName
, aMediaType
);
674 uno::Reference
< embed::XEmbeddedObject
> EmbeddedObjectContainer::CopyAndGetEmbeddedObject(
675 EmbeddedObjectContainer
& rSrc
, const uno::Reference
<embed::XEmbeddedObject
>& xObj
, OUString
& rName
,
676 const OUString
& rSrcShellID
, const OUString
& rDestShellID
)
678 uno::Reference
< embed::XEmbeddedObject
> xResult
;
680 // TODO/LATER: For now only objects that implement XEmbedPersist have a replacement image, it might change in future
681 // do an incompatible change so that object name is provided in all the move and copy methods
685 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY_THROW
);
686 aOrigName
= xPersist
->getEntryName();
688 catch (const uno::Exception
&)
692 if ( rName
.isEmpty() )
693 rName
= CreateUniqueObjectName();
695 // objects without persistence are not really stored by the method
696 if (xObj
.is() && StoreEmbeddedObject(xObj
, rName
, true, rSrcShellID
, rDestShellID
))
698 SAL_INFO_IF(rDestShellID
.isEmpty(), "comphelper.container",
699 "SfxObjectShell with no base URL?"); // every shell has a base URL, except the clipboard SwDocShell
700 xResult
= Get_Impl(rName
, xObj
, &rDestShellID
);
703 // this is a case when object has no real persistence
704 // in such cases a new object should be explicitly created and initialized with the data of the old one
707 uno::Reference
< embed::XLinkageSupport
> xOrigLinkage( xObj
, uno::UNO_QUERY
);
708 if ( xOrigLinkage
.is() && xOrigLinkage
->isLink() )
710 // this is an OOo link, it has no persistence
711 OUString aURL
= xOrigLinkage
->getLinkURL();
712 if ( aURL
.isEmpty() )
713 throw uno::RuntimeException();
715 // create new linked object from the URL the link is based on
716 uno::Reference
< embed::XEmbeddedObjectCreator
> xCreator
=
717 embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() );
719 uno::Sequence
< beans::PropertyValue
> aMediaDescr
{ comphelper::makePropertyValue(
721 uno::Sequence
< beans::PropertyValue
> aObjDescr
{ comphelper::makePropertyValue(
722 "Parent", pImpl
->m_xModel
.get()) };
723 xResult
.set(xCreator
->createInstanceLink(
728 uno::UNO_QUERY_THROW
);
732 // the component is required for copying of this object
733 if ( xObj
->getCurrentState() == embed::EmbedStates::LOADED
)
734 xObj
->changeState( embed::EmbedStates::RUNNING
);
736 // this must be an object based on properties, otherwise we can not copy it currently
737 uno::Reference
< beans::XPropertySet
> xOrigProps( xObj
->getComponent(), uno::UNO_QUERY_THROW
);
739 // use object class ID to create a new one and transfer all the properties
740 uno::Reference
< embed::XEmbeddedObjectCreator
> xCreator
=
741 embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() );
743 uno::Sequence
< beans::PropertyValue
> aObjDescr
{ comphelper::makePropertyValue(
744 "Parent", pImpl
->m_xModel
.get()) };
745 xResult
.set(xCreator
->createInstanceInitNew(
747 xObj
->getClassName(),
751 uno::UNO_QUERY_THROW
);
753 if ( xResult
->getCurrentState() == embed::EmbedStates::LOADED
)
754 xResult
->changeState( embed::EmbedStates::RUNNING
);
756 uno::Reference
< beans::XPropertySet
> xTargetProps( xResult
->getComponent(), uno::UNO_QUERY_THROW
);
758 // copy all the properties from xOrigProps to xTargetProps
759 uno::Reference
< beans::XPropertySetInfo
> xOrigInfo
= xOrigProps
->getPropertySetInfo();
760 if ( !xOrigInfo
.is() )
761 throw uno::RuntimeException();
763 const uno::Sequence
< beans::Property
> aPropertiesList
= xOrigInfo
->getProperties();
764 for ( const auto & p
: aPropertiesList
)
768 xTargetProps
->setPropertyValue(
770 xOrigProps
->getPropertyValue( p
.Name
) );
772 catch (const beans::PropertyVetoException
&)
774 // impossibility to copy readonly property is not treated as an error for now
775 // but the assertion is helpful to detect such scenarios and review them
776 SAL_WARN( "comphelper.container", "Could not copy readonly property!" );
782 AddEmbeddedObject( xResult
, rName
);
784 catch (const uno::Exception
&)
790 xResult
->close( true );
792 catch (const uno::Exception
&)
801 SAL_WARN_IF( !xResult
.is(), "comphelper.container", "Can not copy embedded object that has no persistence!" );
805 // the object is successfully copied, try to copy graphical replacement
806 if ( !aOrigName
.isEmpty() )
807 TryToCopyGraphReplacement( rSrc
, aOrigName
, rName
);
809 // the object might need the size to be set
812 if ( xResult
->getStatus( embed::Aspects::MSOLE_CONTENT
) & embed::EmbedMisc::EMBED_NEEDSSIZEONLOAD
)
813 xResult
->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT
,
814 xObj
->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT
) );
816 catch (const uno::Exception
&)
824 // #i119941, bKeepToTempStorage: use to specify whether store the removed object to temporary storage+
825 void EmbeddedObjectContainer::RemoveEmbeddedObject( const OUString
& rName
, bool bKeepToTempStorage
)
827 uno::Reference
< embed::XEmbeddedObject
> xObj
= GetEmbeddedObject( rName
);
829 RemoveEmbeddedObject( xObj
, bKeepToTempStorage
);
832 bool EmbeddedObjectContainer::MoveEmbeddedObject( const OUString
& rName
, EmbeddedObjectContainer
& rCnt
)
835 auto aIt2
= rCnt
.pImpl
->maNameToObjectMap
.find( rName
);
836 OSL_ENSURE( aIt2
== rCnt
.pImpl
->maNameToObjectMap
.end(), "Object does already exist in target container!" );
838 if ( aIt2
!= rCnt
.pImpl
->maNameToObjectMap
.end() )
841 uno::Reference
< embed::XEmbeddedObject
> xObj
;
842 auto aIt
= pImpl
->maNameToObjectMap
.find( rName
);
843 if ( aIt
!= pImpl
->maNameToObjectMap
.end() )
845 xObj
= (*aIt
).second
;
851 OUString
aName( rName
);
852 rCnt
.InsertEmbeddedObject( xObj
, aName
);
853 pImpl
->maObjectToNameMap
.erase( aIt
->second
);
854 pImpl
->maNameToObjectMap
.erase( aIt
);
855 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
857 pImpl
->mxStorage
->removeElement( rName
);
861 // copy storages; object *must* have persistence!
862 uno::Reference
< embed::XStorage
> xOld
= pImpl
->mxStorage
->openStorageElement( rName
, embed::ElementModes::READ
);
863 uno::Reference
< embed::XStorage
> xNew
= rCnt
.pImpl
->mxStorage
->openStorageElement( rName
, embed::ElementModes::READWRITE
);
864 xOld
->copyToStorage( xNew
);
867 rCnt
.TryToCopyGraphReplacement( *this, rName
, rName
);
868 // RemoveGraphicStream( rName );
872 catch (const uno::Exception
&)
874 SAL_WARN( "comphelper.container", "Could not move object!");
880 SAL_WARN( "comphelper.container", "Unknown object!");
884 // #i119941, bKeepToTempStorage: use to specify whether store the removed object to temporary storage+
885 bool EmbeddedObjectContainer::RemoveEmbeddedObject( const uno::Reference
< embed::XEmbeddedObject
>& xObj
, bool bKeepToTempStorage
)
887 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
890 aName
= xPersist
->getEntryName();
892 #if OSL_DEBUG_LEVEL > 1
893 uno::Reference
< container::XNameAccess
> xAccess( pImpl
->mxStorage
, uno::UNO_QUERY
);
894 uno::Reference
< embed::XLinkageSupport
> xLink( xPersist
, uno::UNO_QUERY
);
895 sal_Bool bIsNotEmbedded
= !xPersist
.is() || ( xLink
.is() && xLink
->isLink() );
897 // if the object has a persistence and the object is not a link than it must have persistence entry in the storage
898 OSL_ENSURE( bIsNotEmbedded
|| xAccess
->hasByName(aName
), "Removing element not present in storage!" );
901 // somebody still needs the object, so we must assign a temporary persistence
904 if ( xPersist
.is() && bKeepToTempStorage
) // #i119941
907 if ( !pImpl
->mpTempObjectContainer
)
909 pImpl
->mpTempObjectContainer
= new EmbeddedObjectContainer();
912 // TODO/LATER: in future probably the temporary container will have two storages ( of two formats )
913 // the media type will be provided with object insertion
914 OUString aOrigStorMediaType
;
915 uno::Reference
< beans::XPropertySet
> xStorProps( pImpl
->mxStorage
, uno::UNO_QUERY_THROW
);
916 static constexpr OUStringLiteral
s_sMediaType(u
"MediaType");
917 xStorProps
->getPropertyValue( s_sMediaType
) >>= aOrigStorMediaType
;
919 SAL_WARN_IF( aOrigStorMediaType
.isEmpty(), "comphelper.container", "No valuable media type in the storage!" );
921 uno::Reference
< beans::XPropertySet
> xTargetStorProps(
922 pImpl
->mpTempObjectContainer
->pImpl
->mxStorage
,
923 uno::UNO_QUERY_THROW
);
924 xTargetStorProps
->setPropertyValue( s_sMediaType
,uno::Any( aOrigStorMediaType
) );
926 catch (const uno::Exception
&)
928 SAL_WARN( "comphelper.container", "Can not set the new media type to a storage!" );
932 OUString aTempName
, aMediaType
;
933 /* Do not create a new name for a removed object, in the pImpl->mpTempObjectContainer,
934 because the original m_aEntryName of xObj will be overwritten by InsertEmbeddedObject(),
935 so uno::Reference < embed::XEmbeddedObject >& xObj will misbehave in
936 EmbeddedObjectContainer::StoreAsChildren and SfxObjectShell::SaveCompletedChildren
937 and will throw an exception because of objects with the same names! */
938 if( !pImpl
->mpTempObjectContainer
->HasEmbeddedObject(aName
) )
941 pImpl
->mpTempObjectContainer
->InsertEmbeddedObject( xObj
, aTempName
);
943 uno::Reference
< io::XInputStream
> xStream
= GetGraphicStream( xObj
, &aMediaType
);
945 pImpl
->mpTempObjectContainer
->InsertGraphicStream( xStream
, aTempName
, aMediaType
);
947 // object is stored, so at least it can be set to loaded state
948 xObj
->changeState( embed::EmbedStates::LOADED
);
951 // objects without persistence need to stay in running state if they shall not be closed
952 xObj
->changeState( embed::EmbedStates::RUNNING
);
954 catch (const uno::Exception
&)
959 auto aIter
= std::find_if(pImpl
->maNameToObjectMap
.begin(), pImpl
->maNameToObjectMap
.end(),
960 [&xObj
](const EmbeddedObjectContainerNameMap::value_type
& rEntry
) { return rEntry
.second
== xObj
; });
961 if (aIter
!= pImpl
->maNameToObjectMap
.end())
963 pImpl
->maObjectToNameMap
.erase( aIter
->second
);
964 pImpl
->maNameToObjectMap
.erase( aIter
);
965 uno::Reference
< container::XChild
> xChild( xObj
, uno::UNO_QUERY
);
967 xChild
->setParent( uno::Reference
< uno::XInterface
>() );
970 SAL_WARN( "comphelper.container", "Object not found for removal!" );
972 if ( !xPersist
|| !bKeepToTempStorage
) // #i119941#
975 // remove replacement image (if there is one)
976 RemoveGraphicStream( aName
);
978 // now it's time to remove the storage from the container storage
981 #if OSL_DEBUG_LEVEL > 1
982 // if the object has a persistence and the object is not a link than it must have persistence entry in storage
983 OSL_ENSURE( bIsNotEmbedded
|| pImpl
->mxStorage
->hasByName( aName
), "The object has no persistence entry in the storage!" );
985 if ( xPersist
.is() && pImpl
->mxStorage
->hasByName( aName
) )
986 pImpl
->mxStorage
->removeElement( aName
);
988 catch (const uno::Exception
&)
990 SAL_WARN( "comphelper.container", "Failed to remove object from storage!" );
997 void EmbeddedObjectContainer::CloseEmbeddedObject( const uno::Reference
< embed::XEmbeddedObject
>& xObj
)
999 // disconnect the object from the container and close it if possible
1001 auto aIter
= std::find_if(pImpl
->maNameToObjectMap
.begin(), pImpl
->maNameToObjectMap
.end(),
1002 [&xObj
](const EmbeddedObjectContainerNameMap::value_type
& rEntry
) { return rEntry
.second
== xObj
; });
1003 if (aIter
== pImpl
->maNameToObjectMap
.end())
1006 pImpl
->maObjectToNameMap
.erase( aIter
->second
);
1007 pImpl
->maNameToObjectMap
.erase( aIter
);
1011 xObj
->close( true );
1013 catch (const uno::Exception
&)
1015 // it is no problem if the object is already closed
1016 // TODO/LATER: what if the object can not be closed?
1020 uno::Reference
< io::XInputStream
> EmbeddedObjectContainer::GetGraphicStream( const OUString
& aName
, OUString
* pMediaType
)
1022 uno::Reference
< io::XInputStream
> xStream
;
1024 SAL_WARN_IF( aName
.isEmpty(), "comphelper.container", "Retrieving graphic for unknown object!" );
1025 if ( !aName
.isEmpty() )
1029 uno::Reference
< embed::XStorage
> xReplacements
= pImpl
->GetReplacements();
1030 uno::Reference
< io::XStream
> xGraphicStream
= xReplacements
->openStreamElement( aName
, embed::ElementModes::READ
);
1031 xStream
= xGraphicStream
->getInputStream();
1034 uno::Reference
< beans::XPropertySet
> xSet( xStream
, uno::UNO_QUERY
);
1037 uno::Any aAny
= xSet
->getPropertyValue("MediaType");
1038 aAny
>>= *pMediaType
;
1042 catch (uno::Exception
const& e
)
1044 SAL_INFO("comphelper.container",
1045 "EmbeddedObjectContainer::GetGraphicStream(): " << e
);
1052 uno::Reference
< io::XInputStream
> EmbeddedObjectContainer::GetGraphicStream( const css::uno::Reference
< css::embed::XEmbeddedObject
>& xObj
, OUString
* pMediaType
)
1054 // try to load it from the container storage
1055 return GetGraphicStream( GetEmbeddedObjectName( xObj
), pMediaType
);
1058 bool EmbeddedObjectContainer::InsertGraphicStream( const css::uno::Reference
< css::io::XInputStream
>& rStream
, const OUString
& rObjectName
, const OUString
& rMediaType
)
1062 uno::Reference
< embed::XStorage
> xReplacements
= pImpl
->GetReplacements();
1064 // store it into the subfolder
1065 uno::Reference
< io::XOutputStream
> xOutStream
;
1066 uno::Reference
< io::XStream
> xGraphicStream
= xReplacements
->openStreamElement( rObjectName
,
1067 embed::ElementModes::READWRITE
| embed::ElementModes::TRUNCATE
);
1068 xOutStream
= xGraphicStream
->getOutputStream();
1069 ::comphelper::OStorageHelper::CopyInputToOutput( rStream
, xOutStream
);
1070 xOutStream
->flush();
1072 uno::Reference
< beans::XPropertySet
> xPropSet( xGraphicStream
, uno::UNO_QUERY_THROW
);
1074 xPropSet
->setPropertyValue("UseCommonStoragePasswordEncryption",
1076 xPropSet
->setPropertyValue("MediaType", uno::Any(rMediaType
) );
1078 xPropSet
->setPropertyValue("Compressed",
1081 catch (const uno::Exception
&)
1089 bool EmbeddedObjectContainer::InsertGraphicStreamDirectly( const css::uno::Reference
< css::io::XInputStream
>& rStream
, const OUString
& rObjectName
, const OUString
& rMediaType
)
1093 uno::Reference
< embed::XStorage
> xReplacement
= pImpl
->GetReplacements();
1094 uno::Reference
< embed::XOptimizedStorage
> xOptRepl( xReplacement
, uno::UNO_QUERY_THROW
);
1096 // store it into the subfolder
1097 uno::Sequence
< beans::PropertyValue
> aProps
{
1098 comphelper::makePropertyValue("MediaType", rMediaType
),
1099 comphelper::makePropertyValue("UseCommonStoragePasswordEncryption", true),
1100 comphelper::makePropertyValue("Compressed", true)
1103 if ( xReplacement
->hasByName( rObjectName
) )
1104 xReplacement
->removeElement( rObjectName
);
1106 xOptRepl
->insertStreamElementDirect( rObjectName
, rStream
, aProps
);
1108 catch (const uno::Exception
&)
1117 void EmbeddedObjectContainer::RemoveGraphicStream( const OUString
& rObjectName
)
1121 uno::Reference
< embed::XStorage
> xReplacements
= pImpl
->GetReplacements();
1122 xReplacements
->removeElement( rObjectName
);
1124 catch (const uno::Exception
&)
1129 void InsertStreamIntoPicturesStorage_Impl( const uno::Reference
< embed::XStorage
>& xDocStor
,
1130 const uno::Reference
< io::XInputStream
>& xInStream
,
1131 const OUString
& aStreamName
)
1133 OSL_ENSURE( !aStreamName
.isEmpty() && xInStream
.is() && xDocStor
.is(), "Misuse of the method!" );
1137 uno::Reference
< embed::XStorage
> xPictures
= xDocStor
->openStorageElement(
1139 embed::ElementModes::READWRITE
);
1140 uno::Reference
< io::XStream
> xObjReplStr
= xPictures
->openStreamElement(
1142 embed::ElementModes::READWRITE
| embed::ElementModes::TRUNCATE
);
1143 uno::Reference
< io::XOutputStream
> xOutStream(
1144 xObjReplStr
->getInputStream(), uno::UNO_QUERY_THROW
);
1146 ::comphelper::OStorageHelper::CopyInputToOutput( xInStream
, xOutStream
);
1147 xOutStream
->closeOutput();
1149 uno::Reference
< embed::XTransactedObject
> xTransact( xPictures
, uno::UNO_QUERY
);
1150 if ( xTransact
.is() )
1151 xTransact
->commit();
1153 catch (const uno::Exception
&)
1155 SAL_WARN( "comphelper.container", "The images storage is not available!" );
1161 bool EmbeddedObjectContainer::StoreAsChildren(bool _bOasisFormat
,bool _bCreateEmbedded
, bool _bAutoSaveEvent
,
1162 const uno::Reference
< embed::XStorage
>& _xStorage
)
1164 bool bResult
= false;
1167 comphelper::EmbeddedObjectContainer
aCnt( _xStorage
);
1168 const uno::Sequence
< OUString
> aNames
= GetObjectNames();
1169 const OUString
* pIter
= aNames
.getConstArray();
1170 const OUString
* pEnd
= pIter
+ aNames
.getLength();
1171 for(;pIter
!= pEnd
;++pIter
)
1173 uno::Reference
< embed::XEmbeddedObject
> xObj
= GetEmbeddedObject( *pIter
);
1174 SAL_WARN_IF( !xObj
.is(), "comphelper.container", "An empty entry in the embedded objects list!" );
1177 bool bSwitchBackToLoaded
= false;
1178 uno::Reference
< embed::XLinkageSupport
> xLink( xObj
, uno::UNO_QUERY
);
1180 uno::Reference
< io::XInputStream
> xStream
;
1181 OUString aMediaType
;
1183 sal_Int32 nCurState
= xObj
->getCurrentState();
1184 if ( nCurState
== embed::EmbedStates::LOADED
|| nCurState
== embed::EmbedStates::RUNNING
)
1186 // means that the object is not active
1187 // copy replacement image from old to new container
1188 xStream
= GetGraphicStream( xObj
, &aMediaType
);
1191 if ( !xStream
.is() && getUserAllowsLinkUpdate() )
1193 // the image must be regenerated
1194 // TODO/LATER: another aspect could be used
1195 if ( xObj
->getCurrentState() == embed::EmbedStates::LOADED
)
1196 bSwitchBackToLoaded
= true;
1198 xStream
= GetGraphicReplacementStream(
1199 embed::Aspects::MSOLE_CONTENT
,
1204 if ( _bOasisFormat
|| (xLink
.is() && xLink
->isLink()) )
1208 if ( _bOasisFormat
)
1210 // if it is an embedded object or the optimized inserting fails the normal inserting should be done
1211 if ( _bCreateEmbedded
1212 || !aCnt
.InsertGraphicStreamDirectly( xStream
, *pIter
, aMediaType
) )
1213 aCnt
.InsertGraphicStream( xStream
, *pIter
, aMediaType
);
1217 // it is a linked object exported into SO7 format
1218 InsertStreamIntoPicturesStorage_Impl( _xStorage
, xStream
, *pIter
);
1223 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
1224 if ( xPersist
.is() )
1226 uno::Sequence
< beans::PropertyValue
> aArgs( _bOasisFormat
? 3 : 4 );
1227 auto pArgs
= aArgs
.getArray();
1228 pArgs
[0].Name
= "StoreVisualReplacement";
1229 pArgs
[0].Value
<<= !_bOasisFormat
;
1231 // if it is an embedded object or the optimized inserting fails the normal inserting should be done
1232 pArgs
[1].Name
= "CanTryOptimization";
1233 pArgs
[1].Value
<<= !_bCreateEmbedded
;
1235 pArgs
[2].Name
= "AutoSaveEvent";
1236 pArgs
[2].Value
<<= _bAutoSaveEvent
;
1238 if ( !_bOasisFormat
)
1240 // if object has no cached replacement it will use this one
1241 pArgs
[3].Name
= "VisualReplacement";
1242 pArgs
[3].Value
<<= xStream
;
1247 xPersist
->storeAsEntry( _xStorage
, xPersist
->getEntryName(), uno::Sequence
< beans::PropertyValue
>(), aArgs
);
1249 catch (const embed::WrongStateException
&)
1251 SAL_WARN("comphelper.container", "failed to store '" << *pIter
<< "'");
1255 if ( bSwitchBackToLoaded
)
1256 // switch back to loaded state; that way we have a minimum cache confusion
1257 xObj
->changeState( embed::EmbedStates::LOADED
);
1261 bResult
= aCnt
.CommitImageSubStorage();
1264 catch (const uno::Exception
& e
)
1266 // TODO/LATER: error handling
1268 SAL_WARN("comphelper.container", "failed. Message: " << e
);
1271 // the old SO6 format does not store graphical replacements
1272 if ( !_bOasisFormat
&& bResult
)
1276 // the substorage still can not be locked by the embedded object container
1277 OUString
aObjReplElement( "ObjectReplacements" );
1278 if ( _xStorage
->hasByName( aObjReplElement
) && _xStorage
->isStorageElement( aObjReplElement
) )
1279 _xStorage
->removeElement( aObjReplElement
);
1281 catch (const uno::Exception
&)
1283 // TODO/LATER: error handling;
1290 bool EmbeddedObjectContainer::StoreChildren(bool _bOasisFormat
,bool _bObjectsOnly
)
1292 bool bResult
= true;
1293 const uno::Sequence
< OUString
> aNames
= GetObjectNames();
1294 const OUString
* pIter
= aNames
.getConstArray();
1295 const OUString
* pEnd
= pIter
+ aNames
.getLength();
1296 for(;pIter
!= pEnd
;++pIter
)
1300 uno::Reference
< embed::XEmbeddedObject
> xObj
= GetEmbeddedObject( *pIter
);
1301 SAL_WARN_IF( !xObj
.is(), "comphelper.container", "An empty entry in the embedded objects list!" );
1304 sal_Int32 nCurState
= xObj
->getCurrentState();
1305 if ( _bOasisFormat
&& nCurState
!= embed::EmbedStates::LOADED
&& nCurState
!= embed::EmbedStates::RUNNING
)
1307 // means that the object is active
1308 // the image must be regenerated
1309 OUString aMediaType
;
1311 // TODO/LATER: another aspect could be used
1312 uno::Reference
< io::XInputStream
> xStream
=
1313 GetGraphicReplacementStream(
1314 embed::Aspects::MSOLE_CONTENT
,
1319 if ( !InsertGraphicStreamDirectly( xStream
, *pIter
, aMediaType
) )
1320 InsertGraphicStream( xStream
, *pIter
, aMediaType
);
1324 // TODO/LATER: currently the object by default does not cache replacement image
1325 // that means that if somebody loads SO7 document and store its objects using
1326 // this method the images might be lost.
1327 // Currently this method is only used on storing to alien formats, that means
1328 // that SO7 documents storing does not use it, and all other filters are
1329 // based on OASIS format. But if it changes the method must be fixed. The fix
1330 // must be done only on demand since it can affect performance.
1332 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
1333 if ( xPersist
.is() )
1337 //TODO/LATER: only storing if changed!
1338 //xPersist->storeOwn(); //commented, i120168
1340 // begin:all charts will be persisted as xml format on disk when saving, which is time consuming.
1341 // '_bObjectsOnly' mean we are storing to alien formats.
1342 // 'isStorageElement' mean current object is NOT a MS OLE format. (may also include in future), i120168
1343 if (_bObjectsOnly
&& (nCurState
== embed::EmbedStates::LOADED
|| nCurState
== embed::EmbedStates::RUNNING
)
1344 && (pImpl
->mxStorage
->isStorageElement( *pIter
) ))
1346 uno::Reference
< util::XModifiable
> xModifiable( xObj
->getComponent(), uno::UNO_QUERY
);
1347 if ( xModifiable
.is() && xModifiable
->isModified())
1349 xPersist
->storeOwn();
1353 //do nothing. Embedded model is not modified, no need to persist.
1356 else //the embedded object is in active status, always store back it.
1358 xPersist
->storeOwn();
1362 catch (const uno::Exception
&)
1364 // TODO/LATER: error handling
1370 if ( !_bOasisFormat
&& !_bObjectsOnly
)
1372 // copy replacement images for linked objects
1375 uno::Reference
< embed::XLinkageSupport
> xLink( xObj
, uno::UNO_QUERY
);
1376 if ( xLink
.is() && xLink
->isLink() )
1378 OUString aMediaType
;
1379 uno::Reference
< io::XInputStream
> xInStream
= GetGraphicStream( xObj
, &aMediaType
);
1380 if ( xInStream
.is() )
1381 InsertStreamIntoPicturesStorage_Impl( pImpl
->mxStorage
, xInStream
, *pIter
);
1384 catch (const uno::Exception
&)
1390 catch (const uno::Exception
&)
1392 // TODO/LATER: error handling
1396 if ( bResult
&& _bOasisFormat
)
1397 bResult
= CommitImageSubStorage();
1399 if ( bResult
&& !_bObjectsOnly
)
1403 ReleaseImageSubStorage();
1404 OUString
aObjReplElement( "ObjectReplacements" );
1405 if ( !_bOasisFormat
&& pImpl
->mxStorage
->hasByName( aObjReplElement
) && pImpl
->mxStorage
->isStorageElement( aObjReplElement
) )
1406 pImpl
->mxStorage
->removeElement( aObjReplElement
);
1408 catch (const uno::Exception
&)
1410 // TODO/LATER: error handling
1417 uno::Reference
< io::XInputStream
> EmbeddedObjectContainer::GetGraphicReplacementStream(
1418 sal_Int64 nViewAspect
,
1419 const uno::Reference
< embed::XEmbeddedObject
>& xObj
,
1420 OUString
* pMediaType
)
1422 uno::Reference
< io::XInputStream
> xInStream
;
1427 // retrieving of the visual representation can switch object to running state
1428 embed::VisualRepresentation aRep
= xObj
->getPreferredVisualRepresentation( nViewAspect
);
1430 *pMediaType
= aRep
.Flavor
.MimeType
;
1432 uno::Sequence
< sal_Int8
> aSeq
;
1434 xInStream
= new ::comphelper::SequenceInputStream( aSeq
);
1436 catch (const uno::Exception
&)
1444 bool EmbeddedObjectContainer::SetPersistentEntries(const uno::Reference
< embed::XStorage
>& _xStorage
,bool _bClearModifiedFlag
)
1446 bool bError
= false;
1447 const uno::Sequence
< OUString
> aNames
= GetObjectNames();
1448 const OUString
* pIter
= aNames
.getConstArray();
1449 const OUString
* pEnd
= pIter
+ aNames
.getLength();
1450 for(;pIter
!= pEnd
;++pIter
)
1452 uno::Reference
< embed::XEmbeddedObject
> xObj
= GetEmbeddedObject( *pIter
);
1453 SAL_WARN_IF( !xObj
.is(), "comphelper.container", "An empty entry in the embedded objects list!" );
1456 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
1457 if ( xPersist
.is() )
1461 xPersist
->setPersistentEntry( _xStorage
,
1463 embed::EntryInitModes::NO_INIT
,
1464 uno::Sequence
< beans::PropertyValue
>(),
1465 uno::Sequence
< beans::PropertyValue
>() );
1468 catch (const uno::Exception
&)
1470 // TODO/LATER: error handling
1475 if ( _bClearModifiedFlag
)
1477 // if this method is used as part of SaveCompleted the object must stay unmodified after execution
1480 uno::Reference
< util::XModifiable
> xModif( xObj
->getComponent(), uno::UNO_QUERY_THROW
);
1481 if ( xModif
->isModified() )
1482 xModif
->setModified( false );
1484 catch (const uno::Exception
&)
1493 bool EmbeddedObjectContainer::getUserAllowsLinkUpdate() const
1495 return pImpl
->mbUserAllowsLinkUpdate
;
1498 void EmbeddedObjectContainer::setUserAllowsLinkUpdate(bool bNew
)
1500 if(pImpl
->mbUserAllowsLinkUpdate
!= bNew
)
1502 pImpl
->mbUserAllowsLinkUpdate
= bNew
;
1508 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */