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 <cppuhelper/weakref.hxx>
46 #include <sal/log.hxx>
49 #include <unordered_map>
52 using namespace ::com::sun::star
;
54 namespace comphelper
{
56 typedef std::unordered_map
<OUString
, uno::Reference
<embed::XEmbeddedObject
>> EmbeddedObjectContainerNameMap
;
59 // TODO/LATER: remove objects from temp. Container storage when object is disposed
60 EmbeddedObjectContainerNameMap maNameToObjectMap
;
61 // to speed up lookup by Reference
62 std::unordered_map
<uno::Reference
<embed::XEmbeddedObject
>, OUString
> maObjectToNameMap
;
63 uno::Reference
< embed::XStorage
> mxStorage
;
64 EmbeddedObjectContainer
* mpTempObjectContainer
;
65 uno::Reference
< embed::XStorage
> mxImageStorage
;
66 uno::WeakReference
< uno::XInterface
> m_xModel
;
68 bool mbOwnsStorage
: 1;
69 bool mbUserAllowsLinkUpdate
: 1;
71 const uno::Reference
< embed::XStorage
>& GetReplacements();
74 const uno::Reference
< embed::XStorage
>& EmbedImpl::GetReplacements()
76 if ( !mxImageStorage
.is() )
80 mxImageStorage
= mxStorage
->openStorageElement(
81 "ObjectReplacements", embed::ElementModes::READWRITE
);
83 catch (const uno::Exception
&)
85 mxImageStorage
= mxStorage
->openStorageElement(
86 "ObjectReplacements", embed::ElementModes::READ
);
90 if ( !mxImageStorage
.is() )
91 throw io::IOException();
93 return mxImageStorage
;
96 EmbeddedObjectContainer::EmbeddedObjectContainer()
97 : pImpl(new EmbedImpl
)
99 pImpl
->mxStorage
= ::comphelper::OStorageHelper::GetTemporaryStorage();
100 pImpl
->mbOwnsStorage
= true;
101 pImpl
->mbUserAllowsLinkUpdate
= true;
102 pImpl
->mpTempObjectContainer
= nullptr;
105 EmbeddedObjectContainer::EmbeddedObjectContainer( const uno::Reference
< embed::XStorage
>& rStor
)
106 : pImpl(new EmbedImpl
)
108 pImpl
->mxStorage
= rStor
;
109 pImpl
->mbOwnsStorage
= false;
110 pImpl
->mbUserAllowsLinkUpdate
= true;
111 pImpl
->mpTempObjectContainer
= nullptr;
114 EmbeddedObjectContainer::EmbeddedObjectContainer( const uno::Reference
< embed::XStorage
>& rStor
, const uno::Reference
< uno::XInterface
>& xModel
)
115 : pImpl(new EmbedImpl
)
117 pImpl
->mxStorage
= rStor
;
118 pImpl
->mbOwnsStorage
= false;
119 pImpl
->mbUserAllowsLinkUpdate
= true;
120 pImpl
->mpTempObjectContainer
= nullptr;
121 pImpl
->m_xModel
= xModel
;
124 void EmbeddedObjectContainer::SwitchPersistence( const uno::Reference
< embed::XStorage
>& rStor
)
126 ReleaseImageSubStorage();
128 if ( pImpl
->mbOwnsStorage
)
129 pImpl
->mxStorage
->dispose();
131 pImpl
->mxStorage
= rStor
;
132 pImpl
->mbOwnsStorage
= false;
135 bool EmbeddedObjectContainer::CommitImageSubStorage()
137 if ( pImpl
->mxImageStorage
.is() )
141 bool bReadOnlyMode
= true;
142 uno::Reference
< beans::XPropertySet
> xSet(pImpl
->mxImageStorage
,uno::UNO_QUERY
);
145 // get the open mode from the parent storage
147 uno::Any aAny
= xSet
->getPropertyValue("OpenMode");
148 if ( aAny
>>= nMode
)
149 bReadOnlyMode
= !(nMode
& embed::ElementModes::WRITE
);
150 } // if ( xSet.is() )
151 if ( !bReadOnlyMode
)
153 uno::Reference
< embed::XTransactedObject
> xTransact( pImpl
->mxImageStorage
, uno::UNO_QUERY_THROW
);
157 catch (const uno::Exception
&)
166 void EmbeddedObjectContainer::ReleaseImageSubStorage()
168 CommitImageSubStorage();
170 if ( pImpl
->mxImageStorage
.is() )
174 pImpl
->mxImageStorage
->dispose();
175 pImpl
->mxImageStorage
.clear();
177 catch (const uno::Exception
&)
179 SAL_WARN( "comphelper.container", "Problems releasing image substorage!" );
184 EmbeddedObjectContainer::~EmbeddedObjectContainer()
186 ReleaseImageSubStorage();
188 if ( pImpl
->mbOwnsStorage
)
189 pImpl
->mxStorage
->dispose();
191 delete pImpl
->mpTempObjectContainer
;
194 void EmbeddedObjectContainer::CloseEmbeddedObjects()
196 for( const auto& rObj
: pImpl
->maNameToObjectMap
)
198 uno::Reference
< util::XCloseable
> xClose( rObj
.second
, uno::UNO_QUERY
);
203 xClose
->close( true );
205 catch (const uno::Exception
&)
212 OUString
EmbeddedObjectContainer::CreateUniqueObjectName()
218 aStr
= "Object " + OUString::number( i
++ );
220 while( HasEmbeddedObject( aStr
) );
221 // TODO/LATER: should we consider deleted objects?
226 uno::Sequence
< OUString
> EmbeddedObjectContainer::GetObjectNames() const
228 return comphelper::mapKeysToSequence(pImpl
->maNameToObjectMap
);
231 bool EmbeddedObjectContainer::HasEmbeddedObjects() const
233 return !pImpl
->maNameToObjectMap
.empty();
236 bool EmbeddedObjectContainer::HasEmbeddedObject( const OUString
& rName
)
238 auto aIt
= pImpl
->maNameToObjectMap
.find( rName
);
239 if (aIt
!= pImpl
->maNameToObjectMap
.end())
241 uno::Reference
<container::XNameAccess
> xAccess(pImpl
->mxStorage
, uno::UNO_QUERY
);
244 return xAccess
->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 aObjDescr
[0].Name
= "Parent";
327 aObjDescr
[0].Value
<<= pImpl
->m_xModel
.get();
331 aObjDescr
[i
].Name
= "DefaultParentBaseURL";
332 aObjDescr
[i
].Value
<<= *pBaseURL
;
337 aObjDescr
[i
].Name
= "CloneFrom";
338 aObjDescr
[i
].Value
<<= xCopy
;
341 uno::Sequence
< beans::PropertyValue
> aMediaDescr( 1 );
342 aMediaDescr
[0].Name
= "ReadOnly";
343 aMediaDescr
[0].Value
<<= 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 aObjDescr
[0].Name
= "Parent";
376 aObjDescr
[0].Value
<<= pImpl
->m_xModel
.get();
379 aObjDescr
[1].Name
= "DefaultParentBaseURL";
380 aObjDescr
[1].Value
<<= *pBaseURL
;
382 std::copy( rArgs
.begin(), rArgs
.end(), aObjDescr
.getArray() + nExtraArgs
);
383 xObj
.set( xFactory
->createInstanceInitNew(
384 rClassId
, OUString(), pImpl
->mxStorage
, rNewName
,
385 aObjDescr
), uno::UNO_QUERY
);
387 AddEmbeddedObject( xObj
, rNewName
);
389 OSL_ENSURE( !xObj
.is() || xObj
->getCurrentState() != embed::EmbedStates::LOADED
,
390 "A freshly create object should be running always!" );
392 catch (uno::Exception
const& e
)
394 SAL_WARN("comphelper.container", "EmbeddedObjectContainer::CreateEmbeddedObject: exception caught: " << e
);
400 uno::Reference
< embed::XEmbeddedObject
> EmbeddedObjectContainer::CreateEmbeddedObject( const uno::Sequence
< sal_Int8
>& rClassId
, OUString
& rNewName
, OUString
const* pBaseURL
)
402 return CreateEmbeddedObject( rClassId
, uno::Sequence
< beans::PropertyValue
>(), rNewName
, pBaseURL
);
405 void EmbeddedObjectContainer::AddEmbeddedObject( const css::uno::Reference
< css::embed::XEmbeddedObject
>& xObj
, const OUString
& rName
)
407 #if OSL_DEBUG_LEVEL > 1
408 SAL_WARN_IF( rName
.isEmpty(), "comphelper.container", "Added object doesn't have a name!");
409 uno::Reference
< container::XNameAccess
> xAccess( pImpl
->mxStorage
, uno::UNO_QUERY
);
410 uno::Reference
< embed::XEmbedPersist
> xEmb( xObj
, uno::UNO_QUERY
);
411 uno::Reference
< embed::XLinkageSupport
> xLink( xEmb
, uno::UNO_QUERY
);
412 // if the object has a persistence and the object is not a link than it must have persistence entry in the storage
413 OSL_ENSURE( !( xEmb
.is() && ( !xLink
.is() || !xLink
->isLink() ) ) || xAccess
->hasByName(rName
),
414 "Added element not in storage!" );
417 // remember object - it needs to be in storage already
418 auto aIt
= pImpl
->maNameToObjectMap
.find( rName
);
419 OSL_ENSURE( aIt
== pImpl
->maNameToObjectMap
.end(), "Element already inserted!" );
420 pImpl
->maNameToObjectMap
[ rName
] = xObj
;
421 pImpl
->maObjectToNameMap
[ xObj
] = rName
;
422 uno::Reference
< container::XChild
> xChild( xObj
, uno::UNO_QUERY
);
423 if ( xChild
.is() && xChild
->getParent() != pImpl
->m_xModel
.get() )
424 xChild
->setParent( pImpl
->m_xModel
.get() );
426 // look for object in temporary container
427 if ( pImpl
->mpTempObjectContainer
)
429 auto& rObjectContainer
= pImpl
->mpTempObjectContainer
->pImpl
->maNameToObjectMap
;
430 auto aIter
= std::find_if(rObjectContainer
.begin(), rObjectContainer
.end(),
431 [&xObj
](const EmbeddedObjectContainerNameMap::value_type
& rEntry
) { return rEntry
.second
== xObj
; });
432 if (aIter
!= rObjectContainer
.end())
434 // copy replacement image from temporary container (if there is any)
435 OUString aTempName
= aIter
->first
;
437 uno::Reference
< io::XInputStream
> xStream
= pImpl
->mpTempObjectContainer
->GetGraphicStream( xObj
, &aMediaType
);
440 InsertGraphicStream( xStream
, rName
, aMediaType
);
442 pImpl
->mpTempObjectContainer
->RemoveGraphicStream( aTempName
);
445 // remove object from storage of temporary container
446 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
451 pImpl
->mpTempObjectContainer
->pImpl
->mxStorage
->removeElement( aTempName
);
453 catch (const uno::Exception
&)
458 // temp. container needs to forget the object
459 pImpl
->mpTempObjectContainer
->pImpl
->maObjectToNameMap
.erase( aIter
->second
);
460 pImpl
->mpTempObjectContainer
->pImpl
->maNameToObjectMap
.erase( aIter
);
465 bool EmbeddedObjectContainer::StoreEmbeddedObject(
466 const uno::Reference
< embed::XEmbeddedObject
>& xObj
, OUString
& rName
, bool bCopy
,
467 const OUString
& rSrcShellID
, const OUString
& rDestShellID
)
469 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
470 if ( rName
.isEmpty() )
471 rName
= CreateUniqueObjectName();
473 #if OSL_DEBUG_LEVEL > 1
474 uno::Reference
< container::XNameAccess
> xAccess( pImpl
->mxStorage
, uno::UNO_QUERY
);
475 OSL_ENSURE( !xPersist
.is() || !xAccess
->hasByName(rName
), "Inserting element already present in storage!" );
476 OSL_ENSURE( xPersist
.is() || xObj
->getCurrentState() == embed::EmbedStates::RUNNING
, "Non persistent object inserted!");
479 // insert objects' storage into the container storage (if object has one)
484 uno::Sequence
< beans::PropertyValue
> aSeq
;
487 auto aObjArgs(::comphelper::InitPropertySequence({
488 { "SourceShellID", uno::Any(rSrcShellID
) },
489 { "DestinationShellID", uno::Any(rDestShellID
) }
491 xPersist
->storeToEntry(pImpl
->mxStorage
, rName
, aSeq
, aObjArgs
);
495 //TODO/LATER: possible optimization, don't store immediately
496 //xPersist->setPersistentEntry( pImpl->mxStorage, rName, embed::EntryInitModes::ENTRY_NO_INIT, aSeq, aSeq );
497 xPersist
->storeAsEntry( pImpl
->mxStorage
, rName
, aSeq
, aSeq
);
498 xPersist
->saveCompleted( true );
502 catch (uno::Exception
const& e
)
504 SAL_WARN("comphelper.container", "EmbeddedObjectContainer::StoreEmbeddedObject: exception caught: " << e
);
505 // TODO/LATER: better error recovery should keep storage intact
512 bool EmbeddedObjectContainer::InsertEmbeddedObject( const uno::Reference
< embed::XEmbeddedObject
>& xObj
, OUString
& rName
)
514 // store it into the container storage
515 if (StoreEmbeddedObject(xObj
, rName
, false, OUString(), OUString()))
518 AddEmbeddedObject( xObj
, rName
);
525 uno::Reference
< embed::XEmbeddedObject
> EmbeddedObjectContainer::InsertEmbeddedObject( const uno::Reference
< io::XInputStream
>& xStm
, OUString
& rNewName
)
527 if ( rNewName
.isEmpty() )
528 rNewName
= CreateUniqueObjectName();
530 // store it into the container storage
531 bool bIsStorage
= false;
534 // first try storage persistence
535 uno::Reference
< embed::XStorage
> xStore
= ::comphelper::OStorageHelper::GetStorageFromInputStream( xStm
);
537 // storage was created from stream successfully
540 uno::Reference
< embed::XStorage
> xNewStore
= pImpl
->mxStorage
->openStorageElement( rNewName
, embed::ElementModes::READWRITE
);
541 xStore
->copyToStorage( xNewStore
);
543 catch (const uno::Exception
&)
546 // it is storage persistence, but opening of new substorage or copying to it failed
547 return uno::Reference
< embed::XEmbeddedObject
>();
549 // stream didn't contain a storage, now try stream persistence
552 uno::Reference
< io::XStream
> xNewStream
= pImpl
->mxStorage
->openStreamElement( rNewName
, embed::ElementModes::READWRITE
);
553 ::comphelper::OStorageHelper::CopyInputToOutput( xStm
, xNewStream
->getOutputStream() );
555 // No mediatype is provided so the default for OLE objects value is used
556 // it is correct so for now, but what if somebody introduces a new stream based embedded object?
557 // Probably introducing of such an object must be restricted ( a storage must be used! ).
558 uno::Reference
< beans::XPropertySet
> xProps( xNewStream
, uno::UNO_QUERY_THROW
);
559 xProps
->setPropertyValue("MediaType",
560 uno::Any( OUString( "application/vnd.sun.star.oleobject" ) ) );
562 catch (uno::Exception
const& e
)
564 // complete disaster!
565 SAL_WARN("comphelper.container", "EmbeddedObjectContainer::InsertEmbeddedObject: exception caught: " << e
);
566 return uno::Reference
< embed::XEmbeddedObject
>();
570 // stream was copied into the container storage in either way, now try to open something form it
571 uno::Reference
< embed::XEmbeddedObject
> xRet
= GetEmbeddedObject( rNewName
);
575 // no object could be created, so withdraw insertion
576 pImpl
->mxStorage
->removeElement( rNewName
);
578 catch (const uno::Exception
&)
585 uno::Reference
< embed::XEmbeddedObject
> EmbeddedObjectContainer::InsertEmbeddedObject( const css::uno::Sequence
< css::beans::PropertyValue
>& aMedium
, OUString
& rNewName
, OUString
const* pBaseURL
)
587 if ( rNewName
.isEmpty() )
588 rNewName
= CreateUniqueObjectName();
590 uno::Reference
< embed::XEmbeddedObject
> xObj
;
593 uno::Reference
< embed::XEmbeddedObjectCreator
> xFactory
= embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() );
594 uno::Sequence
< beans::PropertyValue
> aObjDescr(pBaseURL
? 2 : 1);
595 aObjDescr
[0].Name
= "Parent";
596 aObjDescr
[0].Value
<<= pImpl
->m_xModel
.get();
599 aObjDescr
[1].Name
= "DefaultParentBaseURL";
600 aObjDescr
[1].Value
<<= *pBaseURL
;
602 xObj
.set( xFactory
->createInstanceInitFromMediaDescriptor(
603 pImpl
->mxStorage
, rNewName
, aMedium
, aObjDescr
), uno::UNO_QUERY
);
604 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
606 OSL_ENSURE( !xObj
.is() || xObj
->getCurrentState() != embed::EmbedStates::LOADED
,
607 "A freshly create object should be running always!" );
609 // possible optimization: store later!
611 xPersist
->storeOwn();
613 AddEmbeddedObject( xObj
, rNewName
);
615 catch (const uno::Exception
&)
622 uno::Reference
< embed::XEmbeddedObject
> EmbeddedObjectContainer::InsertEmbeddedLink( const css::uno::Sequence
< css::beans::PropertyValue
>& aMedium
, OUString
& rNewName
)
624 if ( rNewName
.isEmpty() )
625 rNewName
= CreateUniqueObjectName();
627 uno::Reference
< embed::XEmbeddedObject
> xObj
;
630 uno::Reference
< embed::XEmbeddedObjectCreator
> xFactory
= embed::EmbeddedObjectCreator::create(::comphelper::getProcessComponentContext());
631 uno::Sequence
< beans::PropertyValue
> aObjDescr( 1 );
632 aObjDescr
[0].Name
= "Parent";
633 aObjDescr
[0].Value
<<= pImpl
->m_xModel
.get();
634 xObj
.set( xFactory
->createInstanceLink( pImpl
->mxStorage
, rNewName
, aMedium
, aObjDescr
), uno::UNO_QUERY
);
636 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
638 OSL_ENSURE( !xObj
.is() || xObj
->getCurrentState() != embed::EmbedStates::LOADED
,
639 "A freshly create object should be running always!" );
641 // possible optimization: store later!
643 xPersist
->storeOwn();
645 AddEmbeddedObject( xObj
, rNewName
);
647 catch (uno::Exception
const& e
)
649 SAL_WARN("comphelper.container", "EmbeddedObjectContainer::InsertEmbeddedLink: "
650 "exception caught: " << e
);
656 bool EmbeddedObjectContainer::TryToCopyGraphReplacement( EmbeddedObjectContainer
& rSrc
,
657 const OUString
& aOrigName
,
658 const OUString
& aTargetName
)
660 bool bResult
= false;
662 if ( ( &rSrc
!= this || aOrigName
!= aTargetName
) && !aOrigName
.isEmpty() && !aTargetName
.isEmpty() )
665 uno::Reference
< io::XInputStream
> xGrStream
= rSrc
.GetGraphicStream( aOrigName
, &aMediaType
);
666 if ( xGrStream
.is() )
667 bResult
= InsertGraphicStream( xGrStream
, aTargetName
, aMediaType
);
673 uno::Reference
< embed::XEmbeddedObject
> EmbeddedObjectContainer::CopyAndGetEmbeddedObject(
674 EmbeddedObjectContainer
& rSrc
, const uno::Reference
<embed::XEmbeddedObject
>& xObj
, OUString
& rName
,
675 const OUString
& rSrcShellID
, const OUString
& rDestShellID
)
677 uno::Reference
< embed::XEmbeddedObject
> xResult
;
679 // TODO/LATER: For now only objects that implement XEmbedPersist have a replacement image, it might change in future
680 // do an incompatible change so that object name is provided in all the move and copy methods
684 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY_THROW
);
685 aOrigName
= xPersist
->getEntryName();
687 catch (const uno::Exception
&)
691 if ( rName
.isEmpty() )
692 rName
= CreateUniqueObjectName();
694 // objects without persistence are not really stored by the method
695 if (xObj
.is() && StoreEmbeddedObject(xObj
, rName
, true, rSrcShellID
, rDestShellID
))
697 SAL_INFO_IF(rDestShellID
.isEmpty(), "comphelper.container",
698 "SfxObjectShell with no base URL?"); // every shell has a base URL, except the clipboard SwDocShell
699 xResult
= Get_Impl(rName
, xObj
, &rDestShellID
);
702 // this is a case when object has no real persistence
703 // in such cases a new object should be explicitly created and initialized with the data of the old one
706 uno::Reference
< embed::XLinkageSupport
> xOrigLinkage( xObj
, uno::UNO_QUERY
);
707 if ( xOrigLinkage
.is() && xOrigLinkage
->isLink() )
709 // this is an OOo link, it has no persistence
710 OUString aURL
= xOrigLinkage
->getLinkURL();
711 if ( aURL
.isEmpty() )
712 throw uno::RuntimeException();
714 // create new linked object from the URL the link is based on
715 uno::Reference
< embed::XEmbeddedObjectCreator
> xCreator
=
716 embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() );
718 uno::Sequence
< beans::PropertyValue
> aMediaDescr( 1 );
719 aMediaDescr
[0].Name
= "URL";
720 aMediaDescr
[0].Value
<<= aURL
;
721 uno::Sequence
< beans::PropertyValue
> aObjDescr( 1 );
722 aObjDescr
[0].Name
= "Parent";
723 aObjDescr
[0].Value
<<= pImpl
->m_xModel
.get();
724 xResult
.set(xCreator
->createInstanceLink(
729 uno::UNO_QUERY_THROW
);
733 // the component is required for copying of this object
734 if ( xObj
->getCurrentState() == embed::EmbedStates::LOADED
)
735 xObj
->changeState( embed::EmbedStates::RUNNING
);
737 // this must be an object based on properties, otherwise we can not copy it currently
738 uno::Reference
< beans::XPropertySet
> xOrigProps( xObj
->getComponent(), uno::UNO_QUERY_THROW
);
740 // use object class ID to create a new one and transfer all the properties
741 uno::Reference
< embed::XEmbeddedObjectCreator
> xCreator
=
742 embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() );
744 uno::Sequence
< beans::PropertyValue
> aObjDescr( 1 );
745 aObjDescr
[0].Name
= "Parent";
746 aObjDescr
[0].Value
<<= pImpl
->m_xModel
.get();
747 xResult
.set(xCreator
->createInstanceInitNew(
749 xObj
->getClassName(),
753 uno::UNO_QUERY_THROW
);
755 if ( xResult
->getCurrentState() == embed::EmbedStates::LOADED
)
756 xResult
->changeState( embed::EmbedStates::RUNNING
);
758 uno::Reference
< beans::XPropertySet
> xTargetProps( xResult
->getComponent(), uno::UNO_QUERY_THROW
);
760 // copy all the properties from xOrigProps to xTargetProps
761 uno::Reference
< beans::XPropertySetInfo
> xOrigInfo
= xOrigProps
->getPropertySetInfo();
762 if ( !xOrigInfo
.is() )
763 throw uno::RuntimeException();
765 uno::Sequence
< beans::Property
> aPropertiesList
= xOrigInfo
->getProperties();
766 for ( sal_Int32 nInd
= 0; nInd
< aPropertiesList
.getLength(); nInd
++ )
770 xTargetProps
->setPropertyValue(
771 aPropertiesList
[nInd
].Name
,
772 xOrigProps
->getPropertyValue( aPropertiesList
[nInd
].Name
) );
774 catch (const beans::PropertyVetoException
&)
776 // impossibility to copy readonly property is not treated as an error for now
777 // but the assertion is helpful to detect such scenarios and review them
778 SAL_WARN( "comphelper.container", "Could not copy readonly property!" );
784 AddEmbeddedObject( xResult
, rName
);
786 catch (const uno::Exception
&)
792 xResult
->close( true );
794 catch (const uno::Exception
&)
803 SAL_WARN_IF( !xResult
.is(), "comphelper.container", "Can not copy embedded object that has no persistence!" );
807 // the object is successfully copied, try to copy graphical replacement
808 if ( !aOrigName
.isEmpty() )
809 TryToCopyGraphReplacement( rSrc
, aOrigName
, rName
);
811 // the object might need the size to be set
814 if ( xResult
->getStatus( embed::Aspects::MSOLE_CONTENT
) & embed::EmbedMisc::EMBED_NEEDSSIZEONLOAD
)
815 xResult
->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT
,
816 xObj
->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT
) );
818 catch (const uno::Exception
&)
826 // #i119941, bKeepToTempStorage: use to specify whether store the removed object to temporary storage+
827 void EmbeddedObjectContainer::RemoveEmbeddedObject( const OUString
& rName
, bool bKeepToTempStorage
)
829 uno::Reference
< embed::XEmbeddedObject
> xObj
= GetEmbeddedObject( rName
);
831 RemoveEmbeddedObject( xObj
, bKeepToTempStorage
);
834 bool EmbeddedObjectContainer::MoveEmbeddedObject( const OUString
& rName
, EmbeddedObjectContainer
& rCnt
)
837 auto aIt2
= rCnt
.pImpl
->maNameToObjectMap
.find( rName
);
838 OSL_ENSURE( aIt2
== rCnt
.pImpl
->maNameToObjectMap
.end(), "Object does already exist in target container!" );
840 if ( aIt2
!= rCnt
.pImpl
->maNameToObjectMap
.end() )
843 uno::Reference
< embed::XEmbeddedObject
> xObj
;
844 auto aIt
= pImpl
->maNameToObjectMap
.find( rName
);
845 if ( aIt
!= pImpl
->maNameToObjectMap
.end() )
847 xObj
= (*aIt
).second
;
853 OUString
aName( rName
);
854 rCnt
.InsertEmbeddedObject( xObj
, aName
);
855 pImpl
->maObjectToNameMap
.erase( aIt
->second
);
856 pImpl
->maNameToObjectMap
.erase( aIt
);
857 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
859 pImpl
->mxStorage
->removeElement( rName
);
863 // copy storages; object *must* have persistence!
864 uno::Reference
< embed::XStorage
> xOld
= pImpl
->mxStorage
->openStorageElement( rName
, embed::ElementModes::READ
);
865 uno::Reference
< embed::XStorage
> xNew
= rCnt
.pImpl
->mxStorage
->openStorageElement( rName
, embed::ElementModes::READWRITE
);
866 xOld
->copyToStorage( xNew
);
869 rCnt
.TryToCopyGraphReplacement( *this, rName
, rName
);
870 // RemoveGraphicStream( rName );
874 catch (const uno::Exception
&)
876 SAL_WARN( "comphelper.container", "Could not move object!");
882 SAL_WARN( "comphelper.container", "Unknown object!");
886 // #i119941, bKeepToTempStorage: use to specify whether store the removed object to temporary storage+
887 bool EmbeddedObjectContainer::RemoveEmbeddedObject( const uno::Reference
< embed::XEmbeddedObject
>& xObj
, bool bKeepToTempStorage
)
889 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
892 aName
= xPersist
->getEntryName();
894 #if OSL_DEBUG_LEVEL > 1
895 uno::Reference
< container::XNameAccess
> xAccess( pImpl
->mxStorage
, uno::UNO_QUERY
);
896 uno::Reference
< embed::XLinkageSupport
> xLink( xPersist
, uno::UNO_QUERY
);
897 sal_Bool bIsNotEmbedded
= !xPersist
.is() || ( xLink
.is() && xLink
->isLink() );
899 // if the object has a persistence and the object is not a link than it must have persistence entry in the storage
900 OSL_ENSURE( bIsNotEmbedded
|| xAccess
->hasByName(aName
), "Removing element not present in storage!" );
903 // somebody still needs the object, so we must assign a temporary persistence
906 if ( xPersist
.is() && bKeepToTempStorage
) // #i119941
909 if ( !pImpl
->mpTempObjectContainer
)
911 pImpl
->mpTempObjectContainer
= new EmbeddedObjectContainer();
914 // TODO/LATER: in future probably the temporary container will have two storages ( of two formats )
915 // the media type will be provided with object insertion
916 OUString aOrigStorMediaType
;
917 uno::Reference
< beans::XPropertySet
> xStorProps( pImpl
->mxStorage
, uno::UNO_QUERY_THROW
);
918 static const OUStringLiteral
s_sMediaType("MediaType");
919 xStorProps
->getPropertyValue( s_sMediaType
) >>= aOrigStorMediaType
;
921 SAL_WARN_IF( aOrigStorMediaType
.isEmpty(), "comphelper.container", "No valuable media type in the storage!" );
923 uno::Reference
< beans::XPropertySet
> xTargetStorProps(
924 pImpl
->mpTempObjectContainer
->pImpl
->mxStorage
,
925 uno::UNO_QUERY_THROW
);
926 xTargetStorProps
->setPropertyValue( s_sMediaType
,uno::Any( aOrigStorMediaType
) );
928 catch (const uno::Exception
&)
930 SAL_WARN( "comphelper.container", "Can not set the new media type to a storage!" );
934 OUString aTempName
, aMediaType
;
935 pImpl
->mpTempObjectContainer
->InsertEmbeddedObject( xObj
, aTempName
);
937 uno::Reference
< io::XInputStream
> xStream
= GetGraphicStream( xObj
, &aMediaType
);
939 pImpl
->mpTempObjectContainer
->InsertGraphicStream( xStream
, aTempName
, aMediaType
);
941 // object is stored, so at least it can be set to loaded state
942 xObj
->changeState( embed::EmbedStates::LOADED
);
945 // objects without persistence need to stay in running state if they shall not be closed
946 xObj
->changeState( embed::EmbedStates::RUNNING
);
948 catch (const uno::Exception
&)
953 auto aIter
= std::find_if(pImpl
->maNameToObjectMap
.begin(), pImpl
->maNameToObjectMap
.end(),
954 [&xObj
](const EmbeddedObjectContainerNameMap::value_type
& rEntry
) { return rEntry
.second
== xObj
; });
955 if (aIter
!= pImpl
->maNameToObjectMap
.end())
957 pImpl
->maObjectToNameMap
.erase( aIter
->second
);
958 pImpl
->maNameToObjectMap
.erase( aIter
);
959 uno::Reference
< container::XChild
> xChild( xObj
, uno::UNO_QUERY
);
961 xChild
->setParent( uno::Reference
< uno::XInterface
>() );
964 SAL_WARN( "comphelper.container", "Object not found for removal!" );
966 if ( xPersist
.is() && bKeepToTempStorage
) // #i119941#
968 // remove replacement image (if there is one)
969 RemoveGraphicStream( aName
);
971 // now it's time to remove the storage from the container storage
974 #if OSL_DEBUG_LEVEL > 1
975 // if the object has a persistence and the object is not a link than it must have persistence entry in storage
976 OSL_ENSURE( bIsNotEmbedded
|| pImpl
->mxStorage
->hasByName( aName
), "The object has no persistence entry in the storage!" );
978 if ( xPersist
.is() && pImpl
->mxStorage
->hasByName( aName
) )
979 pImpl
->mxStorage
->removeElement( aName
);
981 catch (const uno::Exception
&)
983 SAL_WARN( "comphelper.container", "Failed to remove object from storage!" );
991 void EmbeddedObjectContainer::CloseEmbeddedObject( const uno::Reference
< embed::XEmbeddedObject
>& xObj
)
993 // disconnect the object from the container and close it if possible
995 auto aIter
= std::find_if(pImpl
->maNameToObjectMap
.begin(), pImpl
->maNameToObjectMap
.end(),
996 [&xObj
](const EmbeddedObjectContainerNameMap::value_type
& rEntry
) { return rEntry
.second
== xObj
; });
997 if (aIter
!= pImpl
->maNameToObjectMap
.end())
999 pImpl
->maObjectToNameMap
.erase( aIter
->second
);
1000 pImpl
->maNameToObjectMap
.erase( aIter
);
1002 uno::Reference
< ::util::XCloseable
> xClose( xObj
, uno::UNO_QUERY
);
1005 xClose
->close( true );
1007 catch (const uno::Exception
&)
1009 // it is no problem if the object is already closed
1010 // TODO/LATER: what if the object can not be closed?
1015 uno::Reference
< io::XInputStream
> EmbeddedObjectContainer::GetGraphicStream( const OUString
& aName
, OUString
* pMediaType
)
1017 uno::Reference
< io::XInputStream
> xStream
;
1019 SAL_WARN_IF( aName
.isEmpty(), "comphelper.container", "Retrieving graphic for unknown object!" );
1020 if ( !aName
.isEmpty() )
1024 uno::Reference
< embed::XStorage
> xReplacements
= pImpl
->GetReplacements();
1025 uno::Reference
< io::XStream
> xGraphicStream
= xReplacements
->openStreamElement( aName
, embed::ElementModes::READ
);
1026 xStream
= xGraphicStream
->getInputStream();
1029 uno::Reference
< beans::XPropertySet
> xSet( xStream
, uno::UNO_QUERY
);
1032 uno::Any aAny
= xSet
->getPropertyValue("MediaType");
1033 aAny
>>= *pMediaType
;
1037 catch (uno::Exception
const& e
)
1039 SAL_INFO("comphelper.container",
1040 "EmbeddedObjectContainer::GetGraphicStream(): " << e
);
1047 uno::Reference
< io::XInputStream
> EmbeddedObjectContainer::GetGraphicStream( const css::uno::Reference
< css::embed::XEmbeddedObject
>& xObj
, OUString
* pMediaType
)
1049 // try to load it from the container storage
1050 return GetGraphicStream( GetEmbeddedObjectName( xObj
), pMediaType
);
1053 bool EmbeddedObjectContainer::InsertGraphicStream( const css::uno::Reference
< css::io::XInputStream
>& rStream
, const OUString
& rObjectName
, const OUString
& rMediaType
)
1057 uno::Reference
< embed::XStorage
> xReplacements
= pImpl
->GetReplacements();
1059 // store it into the subfolder
1060 uno::Reference
< io::XOutputStream
> xOutStream
;
1061 uno::Reference
< io::XStream
> xGraphicStream
= xReplacements
->openStreamElement( rObjectName
,
1062 embed::ElementModes::READWRITE
| embed::ElementModes::TRUNCATE
);
1063 xOutStream
= xGraphicStream
->getOutputStream();
1064 ::comphelper::OStorageHelper::CopyInputToOutput( rStream
, xOutStream
);
1065 xOutStream
->flush();
1067 uno::Reference
< beans::XPropertySet
> xPropSet( xGraphicStream
, uno::UNO_QUERY_THROW
);
1069 xPropSet
->setPropertyValue("UseCommonStoragePasswordEncryption",
1071 xPropSet
->setPropertyValue("MediaType", uno::Any(rMediaType
) );
1073 xPropSet
->setPropertyValue("Compressed",
1076 catch (const uno::Exception
&)
1084 bool EmbeddedObjectContainer::InsertGraphicStreamDirectly( const css::uno::Reference
< css::io::XInputStream
>& rStream
, const OUString
& rObjectName
, const OUString
& rMediaType
)
1088 uno::Reference
< embed::XStorage
> xReplacement
= pImpl
->GetReplacements();
1089 uno::Reference
< embed::XOptimizedStorage
> xOptRepl( xReplacement
, uno::UNO_QUERY_THROW
);
1091 // store it into the subfolder
1092 uno::Sequence
< beans::PropertyValue
> aProps( 3 );
1093 aProps
[0].Name
= "MediaType";
1094 aProps
[0].Value
<<= rMediaType
;
1095 aProps
[1].Name
= "UseCommonStoragePasswordEncryption";
1096 aProps
[1].Value
<<= true;
1097 aProps
[2].Name
= "Compressed";
1098 aProps
[2].Value
<<= true;
1100 if ( xReplacement
->hasByName( rObjectName
) )
1101 xReplacement
->removeElement( rObjectName
);
1103 xOptRepl
->insertStreamElementDirect( rObjectName
, rStream
, aProps
);
1105 catch (const uno::Exception
&)
1114 void EmbeddedObjectContainer::RemoveGraphicStream( const OUString
& rObjectName
)
1118 uno::Reference
< embed::XStorage
> xReplacements
= pImpl
->GetReplacements();
1119 xReplacements
->removeElement( rObjectName
);
1121 catch (const uno::Exception
&)
1126 void InsertStreamIntoPicturesStorage_Impl( const uno::Reference
< embed::XStorage
>& xDocStor
,
1127 const uno::Reference
< io::XInputStream
>& xInStream
,
1128 const OUString
& aStreamName
)
1130 OSL_ENSURE( !aStreamName
.isEmpty() && xInStream
.is() && xDocStor
.is(), "Misuse of the method!" );
1134 uno::Reference
< embed::XStorage
> xPictures
= xDocStor
->openStorageElement(
1136 embed::ElementModes::READWRITE
);
1137 uno::Reference
< io::XStream
> xObjReplStr
= xPictures
->openStreamElement(
1139 embed::ElementModes::READWRITE
| embed::ElementModes::TRUNCATE
);
1140 uno::Reference
< io::XOutputStream
> xOutStream(
1141 xObjReplStr
->getInputStream(), uno::UNO_QUERY_THROW
);
1143 ::comphelper::OStorageHelper::CopyInputToOutput( xInStream
, xOutStream
);
1144 xOutStream
->closeOutput();
1146 uno::Reference
< embed::XTransactedObject
> xTransact( xPictures
, uno::UNO_QUERY
);
1147 if ( xTransact
.is() )
1148 xTransact
->commit();
1150 catch (const uno::Exception
&)
1152 SAL_WARN( "comphelper.container", "The images storage is not available!" );
1158 bool EmbeddedObjectContainer::StoreAsChildren(bool _bOasisFormat
,bool _bCreateEmbedded
,const uno::Reference
< embed::XStorage
>& _xStorage
)
1160 bool bResult
= false;
1163 comphelper::EmbeddedObjectContainer
aCnt( _xStorage
);
1164 const uno::Sequence
< OUString
> aNames
= GetObjectNames();
1165 const OUString
* pIter
= aNames
.getConstArray();
1166 const OUString
* pEnd
= pIter
+ aNames
.getLength();
1167 for(;pIter
!= pEnd
;++pIter
)
1169 uno::Reference
< embed::XEmbeddedObject
> xObj
= GetEmbeddedObject( *pIter
);
1170 SAL_WARN_IF( !xObj
.is(), "comphelper.container", "An empty entry in the embedded objects list!" );
1173 bool bSwitchBackToLoaded
= false;
1174 uno::Reference
< embed::XLinkageSupport
> xLink( xObj
, uno::UNO_QUERY
);
1176 uno::Reference
< io::XInputStream
> xStream
;
1177 OUString aMediaType
;
1179 sal_Int32 nCurState
= xObj
->getCurrentState();
1180 if ( nCurState
== embed::EmbedStates::LOADED
|| nCurState
== embed::EmbedStates::RUNNING
)
1182 // means that the object is not active
1183 // copy replacement image from old to new container
1184 xStream
= GetGraphicStream( xObj
, &aMediaType
);
1187 if ( !xStream
.is() && getUserAllowsLinkUpdate() )
1189 // the image must be regenerated
1190 // TODO/LATER: another aspect could be used
1191 if ( xObj
->getCurrentState() == embed::EmbedStates::LOADED
)
1192 bSwitchBackToLoaded
= true;
1194 xStream
= GetGraphicReplacementStream(
1195 embed::Aspects::MSOLE_CONTENT
,
1200 if ( _bOasisFormat
|| (xLink
.is() && xLink
->isLink()) )
1204 if ( _bOasisFormat
)
1206 // if it is an embedded object or the optimized inserting fails the normal inserting should be done
1207 if ( _bCreateEmbedded
1208 || !aCnt
.InsertGraphicStreamDirectly( xStream
, *pIter
, aMediaType
) )
1209 aCnt
.InsertGraphicStream( xStream
, *pIter
, aMediaType
);
1213 // it is a linked object exported into SO7 format
1214 InsertStreamIntoPicturesStorage_Impl( _xStorage
, xStream
, *pIter
);
1219 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
1220 if ( xPersist
.is() )
1222 uno::Sequence
< beans::PropertyValue
> aArgs( _bOasisFormat
? 2 : 3 );
1223 aArgs
[0].Name
= "StoreVisualReplacement";
1224 aArgs
[0].Value
<<= !_bOasisFormat
;
1226 // if it is an embedded object or the optimized inserting fails the normal inserting should be done
1227 aArgs
[1].Name
= "CanTryOptimization";
1228 aArgs
[1].Value
<<= !_bCreateEmbedded
;
1229 if ( !_bOasisFormat
)
1231 // if object has no cached replacement it will use this one
1232 aArgs
[2].Name
= "VisualReplacement";
1233 aArgs
[2].Value
<<= xStream
;
1238 xPersist
->storeAsEntry( _xStorage
, xPersist
->getEntryName(), uno::Sequence
< beans::PropertyValue
>(), aArgs
);
1240 catch (const embed::WrongStateException
&)
1242 SAL_WARN("comphelper.container", "failed to store '" << *pIter
<< "'");
1246 if ( bSwitchBackToLoaded
)
1247 // switch back to loaded state; that way we have a minimum cache confusion
1248 xObj
->changeState( embed::EmbedStates::LOADED
);
1252 bResult
= aCnt
.CommitImageSubStorage();
1255 catch (const uno::Exception
& e
)
1257 // TODO/LATER: error handling
1259 SAL_WARN("comphelper.container", "failed. Message: " << e
);
1262 // the old SO6 format does not store graphical replacements
1263 if ( !_bOasisFormat
&& bResult
)
1267 // the substorage still can not be locked by the embedded object container
1268 OUString
aObjReplElement( "ObjectReplacements" );
1269 if ( _xStorage
->hasByName( aObjReplElement
) && _xStorage
->isStorageElement( aObjReplElement
) )
1270 _xStorage
->removeElement( aObjReplElement
);
1272 catch (const uno::Exception
&)
1274 // TODO/LATER: error handling;
1281 bool EmbeddedObjectContainer::StoreChildren(bool _bOasisFormat
,bool _bObjectsOnly
)
1283 bool bResult
= true;
1284 const uno::Sequence
< OUString
> aNames
= GetObjectNames();
1285 const OUString
* pIter
= aNames
.getConstArray();
1286 const OUString
* pEnd
= pIter
+ aNames
.getLength();
1287 for(;pIter
!= pEnd
;++pIter
)
1289 uno::Reference
< embed::XEmbeddedObject
> xObj
= GetEmbeddedObject( *pIter
);
1290 SAL_WARN_IF( !xObj
.is(), "comphelper.container", "An empty entry in the embedded objects list!" );
1293 sal_Int32 nCurState
= xObj
->getCurrentState();
1294 if ( _bOasisFormat
&& nCurState
!= embed::EmbedStates::LOADED
&& nCurState
!= embed::EmbedStates::RUNNING
)
1296 // means that the object is active
1297 // the image must be regenerated
1298 OUString aMediaType
;
1300 // TODO/LATER: another aspect could be used
1301 uno::Reference
< io::XInputStream
> xStream
=
1302 GetGraphicReplacementStream(
1303 embed::Aspects::MSOLE_CONTENT
,
1308 if ( !InsertGraphicStreamDirectly( xStream
, *pIter
, aMediaType
) )
1309 InsertGraphicStream( xStream
, *pIter
, aMediaType
);
1313 // TODO/LATER: currently the object by default does not cache replacement image
1314 // that means that if somebody loads SO7 document and store its objects using
1315 // this method the images might be lost.
1316 // Currently this method is only used on storing to alien formats, that means
1317 // that SO7 documents storing does not use it, and all other filters are
1318 // based on OASIS format. But if it changes the method must be fixed. The fix
1319 // must be done only on demand since it can affect performance.
1321 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
1322 if ( xPersist
.is() )
1326 //TODO/LATER: only storing if changed!
1327 //xPersist->storeOwn(); //commented, i120168
1329 // begin:all charts will be persisted as xml format on disk when saving, which is time consuming.
1330 // '_bObjectsOnly' mean we are storing to alien formats.
1331 // 'isStorageElement' mean current object is NOT a MS OLE format. (may also include in future), i120168
1332 if (_bObjectsOnly
&& (nCurState
== embed::EmbedStates::LOADED
|| nCurState
== embed::EmbedStates::RUNNING
)
1333 && (pImpl
->mxStorage
->isStorageElement( *pIter
) ))
1335 uno::Reference
< util::XModifiable
> xModifiable( xObj
->getComponent(), uno::UNO_QUERY
);
1336 if ( xModifiable
.is() && xModifiable
->isModified())
1338 xPersist
->storeOwn();
1342 //do nothing. Embedded model is not modified, no need to persist.
1345 else //the embedded object is in active status, always store back it.
1347 xPersist
->storeOwn();
1351 catch (const uno::Exception
&)
1353 // TODO/LATER: error handling
1359 if ( !_bOasisFormat
&& !_bObjectsOnly
)
1361 // copy replacement images for linked objects
1364 uno::Reference
< embed::XLinkageSupport
> xLink( xObj
, uno::UNO_QUERY
);
1365 if ( xLink
.is() && xLink
->isLink() )
1367 OUString aMediaType
;
1368 uno::Reference
< io::XInputStream
> xInStream
= GetGraphicStream( xObj
, &aMediaType
);
1369 if ( xInStream
.is() )
1370 InsertStreamIntoPicturesStorage_Impl( pImpl
->mxStorage
, xInStream
, *pIter
);
1373 catch (const uno::Exception
&)
1380 if ( bResult
&& _bOasisFormat
)
1381 bResult
= CommitImageSubStorage();
1383 if ( bResult
&& !_bObjectsOnly
)
1387 ReleaseImageSubStorage();
1388 OUString
aObjReplElement( "ObjectReplacements" );
1389 if ( !_bOasisFormat
&& pImpl
->mxStorage
->hasByName( aObjReplElement
) && pImpl
->mxStorage
->isStorageElement( aObjReplElement
) )
1390 pImpl
->mxStorage
->removeElement( aObjReplElement
);
1392 catch (const uno::Exception
&)
1394 // TODO/LATER: error handling
1401 uno::Reference
< io::XInputStream
> EmbeddedObjectContainer::GetGraphicReplacementStream(
1402 sal_Int64 nViewAspect
,
1403 const uno::Reference
< embed::XEmbeddedObject
>& xObj
,
1404 OUString
* pMediaType
)
1406 uno::Reference
< io::XInputStream
> xInStream
;
1411 // retrieving of the visual representation can switch object to running state
1412 embed::VisualRepresentation aRep
= xObj
->getPreferredVisualRepresentation( nViewAspect
);
1414 *pMediaType
= aRep
.Flavor
.MimeType
;
1416 uno::Sequence
< sal_Int8
> aSeq
;
1418 xInStream
= new ::comphelper::SequenceInputStream( aSeq
);
1420 catch (const uno::Exception
&)
1428 bool EmbeddedObjectContainer::SetPersistentEntries(const uno::Reference
< embed::XStorage
>& _xStorage
,bool _bClearModifedFlag
)
1430 bool bError
= false;
1431 const uno::Sequence
< OUString
> aNames
= GetObjectNames();
1432 const OUString
* pIter
= aNames
.getConstArray();
1433 const OUString
* pEnd
= pIter
+ aNames
.getLength();
1434 for(;pIter
!= pEnd
;++pIter
)
1436 uno::Reference
< embed::XEmbeddedObject
> xObj
= GetEmbeddedObject( *pIter
);
1437 SAL_WARN_IF( !xObj
.is(), "comphelper.container", "An empty entry in the embedded objects list!" );
1440 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
1441 if ( xPersist
.is() )
1445 xPersist
->setPersistentEntry( _xStorage
,
1447 embed::EntryInitModes::NO_INIT
,
1448 uno::Sequence
< beans::PropertyValue
>(),
1449 uno::Sequence
< beans::PropertyValue
>() );
1452 catch (const uno::Exception
&)
1454 // TODO/LATER: error handling
1459 if ( _bClearModifedFlag
)
1461 // if this method is used as part of SaveCompleted the object must stay unmodified after execution
1464 uno::Reference
< util::XModifiable
> xModif( xObj
->getComponent(), uno::UNO_QUERY_THROW
);
1465 if ( xModif
->isModified() )
1466 xModif
->setModified( false );
1468 catch (const uno::Exception
&)
1477 bool EmbeddedObjectContainer::getUserAllowsLinkUpdate() const
1479 return pImpl
->mbUserAllowsLinkUpdate
;
1482 void EmbeddedObjectContainer::setUserAllowsLinkUpdate(bool bNew
)
1484 if(pImpl
->mbUserAllowsLinkUpdate
!= bNew
)
1486 pImpl
->mbUserAllowsLinkUpdate
= bNew
;
1492 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */