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 if (!pImpl
->mxStorage
.is())
243 return pImpl
->mxStorage
->hasByName(rName
);
246 bool EmbeddedObjectContainer::HasEmbeddedObject( const uno::Reference
< embed::XEmbeddedObject
>& xObj
) const
248 return pImpl
->maObjectToNameMap
.find(xObj
) != pImpl
->maObjectToNameMap
.end();
251 bool EmbeddedObjectContainer::HasInstantiatedEmbeddedObject( const OUString
& rName
)
253 // allows to detect whether the object was already instantiated
254 // currently the filter instantiate it on loading, so this method allows
255 // to avoid objects pointing to the same persistence
256 auto aIt
= pImpl
->maNameToObjectMap
.find( rName
);
257 return ( aIt
!= pImpl
->maNameToObjectMap
.end() );
260 OUString
EmbeddedObjectContainer::GetEmbeddedObjectName( const css::uno::Reference
< css::embed::XEmbeddedObject
>& xObj
) const
262 auto it
= pImpl
->maObjectToNameMap
.find(xObj
);
263 if (it
== pImpl
->maObjectToNameMap
.end())
265 SAL_WARN( "comphelper.container", "Unknown object!" );
271 uno::Reference
< embed::XEmbeddedObject
>
272 EmbeddedObjectContainer::GetEmbeddedObject(
273 const OUString
& rName
, OUString
const*const pBaseURL
)
275 SAL_WARN_IF( rName
.isEmpty(), "comphelper.container", "Empty object name!");
277 uno::Reference
< embed::XEmbeddedObject
> xObj
;
278 auto aIt
= pImpl
->maNameToObjectMap
.find( rName
);
280 #if OSL_DEBUG_LEVEL > 1
281 uno::Reference
< container::XNameAccess
> xAccess( pImpl
->mxStorage
, uno::UNO_QUERY
);
282 uno::Sequence
< OUString
> aSeq
= xAccess
->getElementNames();
283 const OUString
* pIter
= aSeq
.getConstArray();
284 const OUString
* pEnd
= pIter
+ aSeq
.getLength();
285 for(;pIter
!= pEnd
;++pIter
)
289 OSL_ENSURE( aIt
!= pImpl
->maNameToObjectMap
.end() || xAccess
->hasByName(rName
), "Could not return object!" );
292 // check if object was already created
293 if ( aIt
!= pImpl
->maNameToObjectMap
.end() )
294 xObj
= (*aIt
).second
;
296 xObj
= Get_Impl(rName
, uno::Reference
<embed::XEmbeddedObject
>(), pBaseURL
);
301 uno::Reference
<embed::XEmbeddedObject
> EmbeddedObjectContainer::Get_Impl(
302 const OUString
& rName
,
303 const uno::Reference
<embed::XEmbeddedObject
>& xCopy
,
304 OUString
const*const pBaseURL
)
306 uno::Reference
< embed::XEmbeddedObject
> xObj
;
309 // create the object from the storage
310 uno::Reference
< beans::XPropertySet
> xSet( pImpl
->mxStorage
, uno::UNO_QUERY
);
311 bool bReadOnlyMode
= true;
314 // get the open mode from the parent storage
316 uno::Any aAny
= xSet
->getPropertyValue("OpenMode");
317 if ( aAny
>>= nMode
)
318 bReadOnlyMode
= !(nMode
& embed::ElementModes::WRITE
);
321 // object was not added until now - should happen only by calling this method from "inside"
322 //TODO/LATER: it would be good to detect an error when an object should be created already, but isn't (not an "inside" call)
323 uno::Reference
< embed::XEmbeddedObjectCreator
> xFactory
= embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() );
324 uno::Sequence
< beans::PropertyValue
> aObjDescr(1 + (xCopy
.is() ? 1 : 0) + (pBaseURL
? 1 : 0));
325 aObjDescr
[0].Name
= "Parent";
326 aObjDescr
[0].Value
<<= pImpl
->m_xModel
.get();
330 aObjDescr
[i
].Name
= "DefaultParentBaseURL";
331 aObjDescr
[i
].Value
<<= *pBaseURL
;
336 aObjDescr
[i
].Name
= "CloneFrom";
337 aObjDescr
[i
].Value
<<= xCopy
;
340 uno::Sequence
< beans::PropertyValue
> aMediaDescr( 1 );
341 aMediaDescr
[0].Name
= "ReadOnly";
342 aMediaDescr
[0].Value
<<= bReadOnlyMode
;
343 xObj
.set( xFactory
->createInstanceInitFromEntry(
344 pImpl
->mxStorage
, rName
,
345 aMediaDescr
, aObjDescr
), uno::UNO_QUERY
);
347 // insert object into my list
348 AddEmbeddedObject( xObj
, rName
);
350 catch (uno::Exception
const& e
)
352 SAL_WARN("comphelper.container", "EmbeddedObjectContainer::Get_Impl: exception caught: " << e
);
358 uno::Reference
< embed::XEmbeddedObject
> EmbeddedObjectContainer::CreateEmbeddedObject( const uno::Sequence
< sal_Int8
>& rClassId
,
359 const uno::Sequence
< beans::PropertyValue
>& rArgs
, OUString
& rNewName
, OUString
const* pBaseURL
)
361 if ( rNewName
.isEmpty() )
362 rNewName
= CreateUniqueObjectName();
364 SAL_WARN_IF( HasEmbeddedObject(rNewName
), "comphelper.container", "Object to create already exists!");
366 // create object from classid by inserting it into storage
367 uno::Reference
< embed::XEmbeddedObject
> xObj
;
370 uno::Reference
< embed::XEmbeddedObjectCreator
> xFactory
= embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() );
372 const size_t nExtraArgs
= pBaseURL
? 2 : 1;
373 uno::Sequence
< beans::PropertyValue
> aObjDescr( rArgs
.getLength() + nExtraArgs
);
374 aObjDescr
[0].Name
= "Parent";
375 aObjDescr
[0].Value
<<= pImpl
->m_xModel
.get();
378 aObjDescr
[1].Name
= "DefaultParentBaseURL";
379 aObjDescr
[1].Value
<<= *pBaseURL
;
381 std::copy( rArgs
.begin(), rArgs
.end(), aObjDescr
.getArray() + nExtraArgs
);
382 xObj
.set( xFactory
->createInstanceInitNew(
383 rClassId
, OUString(), pImpl
->mxStorage
, rNewName
,
384 aObjDescr
), uno::UNO_QUERY
);
386 AddEmbeddedObject( xObj
, rNewName
);
388 OSL_ENSURE( !xObj
.is() || xObj
->getCurrentState() != embed::EmbedStates::LOADED
,
389 "A freshly create object should be running always!" );
391 catch (uno::Exception
const& e
)
393 SAL_WARN("comphelper.container", "EmbeddedObjectContainer::CreateEmbeddedObject: exception caught: " << e
);
399 uno::Reference
< embed::XEmbeddedObject
> EmbeddedObjectContainer::CreateEmbeddedObject( const uno::Sequence
< sal_Int8
>& rClassId
, OUString
& rNewName
, OUString
const* pBaseURL
)
401 return CreateEmbeddedObject( rClassId
, uno::Sequence
< beans::PropertyValue
>(), rNewName
, pBaseURL
);
404 void EmbeddedObjectContainer::AddEmbeddedObject( const css::uno::Reference
< css::embed::XEmbeddedObject
>& xObj
, const OUString
& rName
)
406 #if OSL_DEBUG_LEVEL > 1
407 SAL_WARN_IF( rName
.isEmpty(), "comphelper.container", "Added object doesn't have a name!");
408 uno::Reference
< container::XNameAccess
> xAccess( pImpl
->mxStorage
, uno::UNO_QUERY
);
409 uno::Reference
< embed::XEmbedPersist
> xEmb( xObj
, uno::UNO_QUERY
);
410 uno::Reference
< embed::XLinkageSupport
> xLink( xEmb
, uno::UNO_QUERY
);
411 // if the object has a persistence and the object is not a link than it must have persistence entry in the storage
412 OSL_ENSURE( !( xEmb
.is() && ( !xLink
.is() || !xLink
->isLink() ) ) || xAccess
->hasByName(rName
),
413 "Added element not in storage!" );
416 // remember object - it needs to be in storage already
417 auto aIt
= pImpl
->maNameToObjectMap
.find( rName
);
418 OSL_ENSURE( aIt
== pImpl
->maNameToObjectMap
.end(), "Element already inserted!" );
419 pImpl
->maNameToObjectMap
[ rName
] = xObj
;
420 pImpl
->maObjectToNameMap
[ xObj
] = rName
;
421 uno::Reference
< container::XChild
> xChild( xObj
, uno::UNO_QUERY
);
422 if ( xChild
.is() && xChild
->getParent() != pImpl
->m_xModel
.get() )
423 xChild
->setParent( pImpl
->m_xModel
.get() );
425 // look for object in temporary container
426 if ( pImpl
->mpTempObjectContainer
)
428 auto& rObjectContainer
= pImpl
->mpTempObjectContainer
->pImpl
->maNameToObjectMap
;
429 auto aIter
= std::find_if(rObjectContainer
.begin(), rObjectContainer
.end(),
430 [&xObj
](const EmbeddedObjectContainerNameMap::value_type
& rEntry
) { return rEntry
.second
== xObj
; });
431 if (aIter
!= rObjectContainer
.end())
433 // copy replacement image from temporary container (if there is any)
434 OUString aTempName
= aIter
->first
;
436 uno::Reference
< io::XInputStream
> xStream
= pImpl
->mpTempObjectContainer
->GetGraphicStream( xObj
, &aMediaType
);
439 InsertGraphicStream( xStream
, rName
, aMediaType
);
441 pImpl
->mpTempObjectContainer
->RemoveGraphicStream( aTempName
);
444 // remove object from storage of temporary container
445 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
450 pImpl
->mpTempObjectContainer
->pImpl
->mxStorage
->removeElement( aTempName
);
452 catch (const uno::Exception
&)
457 // temp. container needs to forget the object
458 pImpl
->mpTempObjectContainer
->pImpl
->maObjectToNameMap
.erase( aIter
->second
);
459 pImpl
->mpTempObjectContainer
->pImpl
->maNameToObjectMap
.erase( aIter
);
464 bool EmbeddedObjectContainer::StoreEmbeddedObject(
465 const uno::Reference
< embed::XEmbeddedObject
>& xObj
, OUString
& rName
, bool bCopy
,
466 const OUString
& rSrcShellID
, const OUString
& rDestShellID
)
468 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
469 if ( rName
.isEmpty() )
470 rName
= CreateUniqueObjectName();
472 #if OSL_DEBUG_LEVEL > 1
473 uno::Reference
< container::XNameAccess
> xAccess( pImpl
->mxStorage
, uno::UNO_QUERY
);
474 OSL_ENSURE( !xPersist
.is() || !xAccess
->hasByName(rName
), "Inserting element already present in storage!" );
475 OSL_ENSURE( xPersist
.is() || xObj
->getCurrentState() == embed::EmbedStates::RUNNING
, "Non persistent object inserted!");
478 // insert objects' storage into the container storage (if object has one)
483 uno::Sequence
< beans::PropertyValue
> aSeq
;
486 auto aObjArgs(::comphelper::InitPropertySequence({
487 { "SourceShellID", uno::Any(rSrcShellID
) },
488 { "DestinationShellID", uno::Any(rDestShellID
) }
490 xPersist
->storeToEntry(pImpl
->mxStorage
, rName
, aSeq
, aObjArgs
);
494 //TODO/LATER: possible optimization, don't store immediately
495 //xPersist->setPersistentEntry( pImpl->mxStorage, rName, embed::EntryInitModes::ENTRY_NO_INIT, aSeq, aSeq );
496 xPersist
->storeAsEntry( pImpl
->mxStorage
, rName
, aSeq
, aSeq
);
497 xPersist
->saveCompleted( true );
501 catch (uno::Exception
const& e
)
503 SAL_WARN("comphelper.container", "EmbeddedObjectContainer::StoreEmbeddedObject: exception caught: " << e
);
504 // TODO/LATER: better error recovery should keep storage intact
511 bool EmbeddedObjectContainer::InsertEmbeddedObject( const uno::Reference
< embed::XEmbeddedObject
>& xObj
, OUString
& rName
)
513 // store it into the container storage
514 if (StoreEmbeddedObject(xObj
, rName
, false, OUString(), OUString()))
517 AddEmbeddedObject( xObj
, rName
);
524 uno::Reference
< embed::XEmbeddedObject
> EmbeddedObjectContainer::InsertEmbeddedObject( const uno::Reference
< io::XInputStream
>& xStm
, OUString
& rNewName
)
526 if ( rNewName
.isEmpty() )
527 rNewName
= CreateUniqueObjectName();
529 // store it into the container storage
530 bool bIsStorage
= false;
533 // first try storage persistence
534 uno::Reference
< embed::XStorage
> xStore
= ::comphelper::OStorageHelper::GetStorageFromInputStream( xStm
);
536 // storage was created from stream successfully
539 uno::Reference
< embed::XStorage
> xNewStore
= pImpl
->mxStorage
->openStorageElement( rNewName
, embed::ElementModes::READWRITE
);
540 xStore
->copyToStorage( xNewStore
);
542 catch (const uno::Exception
&)
545 // it is storage persistence, but opening of new substorage or copying to it failed
546 return uno::Reference
< embed::XEmbeddedObject
>();
548 // stream didn't contain a storage, now try stream persistence
551 uno::Reference
< io::XStream
> xNewStream
= pImpl
->mxStorage
->openStreamElement( rNewName
, embed::ElementModes::READWRITE
);
552 ::comphelper::OStorageHelper::CopyInputToOutput( xStm
, xNewStream
->getOutputStream() );
554 // No mediatype is provided so the default for OLE objects value is used
555 // it is correct so for now, but what if somebody introduces a new stream based embedded object?
556 // Probably introducing of such an object must be restricted ( a storage must be used! ).
557 uno::Reference
< beans::XPropertySet
> xProps( xNewStream
, uno::UNO_QUERY_THROW
);
558 xProps
->setPropertyValue("MediaType",
559 uno::Any( OUString( "application/vnd.sun.star.oleobject" ) ) );
561 catch (uno::Exception
const& e
)
563 // complete disaster!
564 SAL_WARN("comphelper.container", "EmbeddedObjectContainer::InsertEmbeddedObject: exception caught: " << e
);
565 return uno::Reference
< embed::XEmbeddedObject
>();
569 // stream was copied into the container storage in either way, now try to open something form it
570 uno::Reference
< embed::XEmbeddedObject
> xRet
= GetEmbeddedObject( rNewName
);
574 // no object could be created, so withdraw insertion
575 pImpl
->mxStorage
->removeElement( rNewName
);
577 catch (const uno::Exception
&)
584 uno::Reference
< embed::XEmbeddedObject
> EmbeddedObjectContainer::InsertEmbeddedObject( const css::uno::Sequence
< css::beans::PropertyValue
>& aMedium
, OUString
& rNewName
, OUString
const* pBaseURL
)
586 if ( rNewName
.isEmpty() )
587 rNewName
= CreateUniqueObjectName();
589 uno::Reference
< embed::XEmbeddedObject
> xObj
;
592 uno::Reference
< embed::XEmbeddedObjectCreator
> xFactory
= embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() );
593 uno::Sequence
< beans::PropertyValue
> aObjDescr(pBaseURL
? 2 : 1);
594 aObjDescr
[0].Name
= "Parent";
595 aObjDescr
[0].Value
<<= pImpl
->m_xModel
.get();
598 aObjDescr
[1].Name
= "DefaultParentBaseURL";
599 aObjDescr
[1].Value
<<= *pBaseURL
;
601 xObj
.set( xFactory
->createInstanceInitFromMediaDescriptor(
602 pImpl
->mxStorage
, rNewName
, aMedium
, aObjDescr
), uno::UNO_QUERY
);
603 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
605 OSL_ENSURE( !xObj
.is() || xObj
->getCurrentState() != embed::EmbedStates::LOADED
,
606 "A freshly create object should be running always!" );
608 // possible optimization: store later!
610 xPersist
->storeOwn();
612 AddEmbeddedObject( xObj
, rNewName
);
614 catch (const uno::Exception
&)
621 uno::Reference
< embed::XEmbeddedObject
> EmbeddedObjectContainer::InsertEmbeddedLink( const css::uno::Sequence
< css::beans::PropertyValue
>& aMedium
, OUString
& rNewName
)
623 if ( rNewName
.isEmpty() )
624 rNewName
= CreateUniqueObjectName();
626 uno::Reference
< embed::XEmbeddedObject
> xObj
;
629 uno::Reference
< embed::XEmbeddedObjectCreator
> xFactory
= embed::EmbeddedObjectCreator::create(::comphelper::getProcessComponentContext());
630 uno::Sequence
< beans::PropertyValue
> aObjDescr( 1 );
631 aObjDescr
[0].Name
= "Parent";
632 aObjDescr
[0].Value
<<= pImpl
->m_xModel
.get();
633 xObj
.set( xFactory
->createInstanceLink( pImpl
->mxStorage
, rNewName
, aMedium
, aObjDescr
), uno::UNO_QUERY
);
635 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
637 OSL_ENSURE( !xObj
.is() || xObj
->getCurrentState() != embed::EmbedStates::LOADED
,
638 "A freshly create object should be running always!" );
640 // possible optimization: store later!
642 xPersist
->storeOwn();
644 AddEmbeddedObject( xObj
, rNewName
);
646 catch (uno::Exception
const& e
)
648 SAL_WARN("comphelper.container", "EmbeddedObjectContainer::InsertEmbeddedLink: "
649 "exception caught: " << e
);
655 bool EmbeddedObjectContainer::TryToCopyGraphReplacement( EmbeddedObjectContainer
& rSrc
,
656 const OUString
& aOrigName
,
657 const OUString
& aTargetName
)
659 bool bResult
= false;
661 if ( ( &rSrc
!= this || aOrigName
!= aTargetName
) && !aOrigName
.isEmpty() && !aTargetName
.isEmpty() )
664 uno::Reference
< io::XInputStream
> xGrStream
= rSrc
.GetGraphicStream( aOrigName
, &aMediaType
);
665 if ( xGrStream
.is() )
666 bResult
= InsertGraphicStream( xGrStream
, aTargetName
, aMediaType
);
672 uno::Reference
< embed::XEmbeddedObject
> EmbeddedObjectContainer::CopyAndGetEmbeddedObject(
673 EmbeddedObjectContainer
& rSrc
, const uno::Reference
<embed::XEmbeddedObject
>& xObj
, OUString
& rName
,
674 const OUString
& rSrcShellID
, const OUString
& rDestShellID
)
676 uno::Reference
< embed::XEmbeddedObject
> xResult
;
678 // TODO/LATER: For now only objects that implement XEmbedPersist have a replacement image, it might change in future
679 // do an incompatible change so that object name is provided in all the move and copy methods
683 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY_THROW
);
684 aOrigName
= xPersist
->getEntryName();
686 catch (const uno::Exception
&)
690 if ( rName
.isEmpty() )
691 rName
= CreateUniqueObjectName();
693 // objects without persistence are not really stored by the method
694 if (xObj
.is() && StoreEmbeddedObject(xObj
, rName
, true, rSrcShellID
, rDestShellID
))
696 SAL_INFO_IF(rDestShellID
.isEmpty(), "comphelper.container",
697 "SfxObjectShell with no base URL?"); // every shell has a base URL, except the clipboard SwDocShell
698 xResult
= Get_Impl(rName
, xObj
, &rDestShellID
);
701 // this is a case when object has no real persistence
702 // in such cases a new object should be explicitly created and initialized with the data of the old one
705 uno::Reference
< embed::XLinkageSupport
> xOrigLinkage( xObj
, uno::UNO_QUERY
);
706 if ( xOrigLinkage
.is() && xOrigLinkage
->isLink() )
708 // this is an OOo link, it has no persistence
709 OUString aURL
= xOrigLinkage
->getLinkURL();
710 if ( aURL
.isEmpty() )
711 throw uno::RuntimeException();
713 // create new linked object from the URL the link is based on
714 uno::Reference
< embed::XEmbeddedObjectCreator
> xCreator
=
715 embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() );
717 uno::Sequence
< beans::PropertyValue
> aMediaDescr( 1 );
718 aMediaDescr
[0].Name
= "URL";
719 aMediaDescr
[0].Value
<<= aURL
;
720 uno::Sequence
< beans::PropertyValue
> aObjDescr( 1 );
721 aObjDescr
[0].Name
= "Parent";
722 aObjDescr
[0].Value
<<= 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( 1 );
744 aObjDescr
[0].Name
= "Parent";
745 aObjDescr
[0].Value
<<= pImpl
->m_xModel
.get();
746 xResult
.set(xCreator
->createInstanceInitNew(
748 xObj
->getClassName(),
752 uno::UNO_QUERY_THROW
);
754 if ( xResult
->getCurrentState() == embed::EmbedStates::LOADED
)
755 xResult
->changeState( embed::EmbedStates::RUNNING
);
757 uno::Reference
< beans::XPropertySet
> xTargetProps( xResult
->getComponent(), uno::UNO_QUERY_THROW
);
759 // copy all the properties from xOrigProps to xTargetProps
760 uno::Reference
< beans::XPropertySetInfo
> xOrigInfo
= xOrigProps
->getPropertySetInfo();
761 if ( !xOrigInfo
.is() )
762 throw uno::RuntimeException();
764 uno::Sequence
< beans::Property
> aPropertiesList
= xOrigInfo
->getProperties();
765 for ( sal_Int32 nInd
= 0; nInd
< aPropertiesList
.getLength(); nInd
++ )
769 xTargetProps
->setPropertyValue(
770 aPropertiesList
[nInd
].Name
,
771 xOrigProps
->getPropertyValue( aPropertiesList
[nInd
].Name
) );
773 catch (const beans::PropertyVetoException
&)
775 // impossibility to copy readonly property is not treated as an error for now
776 // but the assertion is helpful to detect such scenarios and review them
777 SAL_WARN( "comphelper.container", "Could not copy readonly property!" );
783 AddEmbeddedObject( xResult
, rName
);
785 catch (const uno::Exception
&)
791 xResult
->close( true );
793 catch (const uno::Exception
&)
802 SAL_WARN_IF( !xResult
.is(), "comphelper.container", "Can not copy embedded object that has no persistence!" );
806 // the object is successfully copied, try to copy graphical replacement
807 if ( !aOrigName
.isEmpty() )
808 TryToCopyGraphReplacement( rSrc
, aOrigName
, rName
);
810 // the object might need the size to be set
813 if ( xResult
->getStatus( embed::Aspects::MSOLE_CONTENT
) & embed::EmbedMisc::EMBED_NEEDSSIZEONLOAD
)
814 xResult
->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT
,
815 xObj
->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT
) );
817 catch (const uno::Exception
&)
825 // #i119941, bKeepToTempStorage: use to specify whether store the removed object to temporary storage+
826 void EmbeddedObjectContainer::RemoveEmbeddedObject( const OUString
& rName
, bool bKeepToTempStorage
)
828 uno::Reference
< embed::XEmbeddedObject
> xObj
= GetEmbeddedObject( rName
);
830 RemoveEmbeddedObject( xObj
, bKeepToTempStorage
);
833 bool EmbeddedObjectContainer::MoveEmbeddedObject( const OUString
& rName
, EmbeddedObjectContainer
& rCnt
)
836 auto aIt2
= rCnt
.pImpl
->maNameToObjectMap
.find( rName
);
837 OSL_ENSURE( aIt2
== rCnt
.pImpl
->maNameToObjectMap
.end(), "Object does already exist in target container!" );
839 if ( aIt2
!= rCnt
.pImpl
->maNameToObjectMap
.end() )
842 uno::Reference
< embed::XEmbeddedObject
> xObj
;
843 auto aIt
= pImpl
->maNameToObjectMap
.find( rName
);
844 if ( aIt
!= pImpl
->maNameToObjectMap
.end() )
846 xObj
= (*aIt
).second
;
852 OUString
aName( rName
);
853 rCnt
.InsertEmbeddedObject( xObj
, aName
);
854 pImpl
->maObjectToNameMap
.erase( aIt
->second
);
855 pImpl
->maNameToObjectMap
.erase( aIt
);
856 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
858 pImpl
->mxStorage
->removeElement( rName
);
862 // copy storages; object *must* have persistence!
863 uno::Reference
< embed::XStorage
> xOld
= pImpl
->mxStorage
->openStorageElement( rName
, embed::ElementModes::READ
);
864 uno::Reference
< embed::XStorage
> xNew
= rCnt
.pImpl
->mxStorage
->openStorageElement( rName
, embed::ElementModes::READWRITE
);
865 xOld
->copyToStorage( xNew
);
868 rCnt
.TryToCopyGraphReplacement( *this, rName
, rName
);
869 // RemoveGraphicStream( rName );
873 catch (const uno::Exception
&)
875 SAL_WARN( "comphelper.container", "Could not move object!");
881 SAL_WARN( "comphelper.container", "Unknown object!");
885 // #i119941, bKeepToTempStorage: use to specify whether store the removed object to temporary storage+
886 bool EmbeddedObjectContainer::RemoveEmbeddedObject( const uno::Reference
< embed::XEmbeddedObject
>& xObj
, bool bKeepToTempStorage
)
888 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
891 aName
= xPersist
->getEntryName();
893 #if OSL_DEBUG_LEVEL > 1
894 uno::Reference
< container::XNameAccess
> xAccess( pImpl
->mxStorage
, uno::UNO_QUERY
);
895 uno::Reference
< embed::XLinkageSupport
> xLink( xPersist
, uno::UNO_QUERY
);
896 sal_Bool bIsNotEmbedded
= !xPersist
.is() || ( xLink
.is() && xLink
->isLink() );
898 // if the object has a persistence and the object is not a link than it must have persistence entry in the storage
899 OSL_ENSURE( bIsNotEmbedded
|| xAccess
->hasByName(aName
), "Removing element not present in storage!" );
902 // somebody still needs the object, so we must assign a temporary persistence
905 if ( xPersist
.is() && bKeepToTempStorage
) // #i119941
908 if ( !pImpl
->mpTempObjectContainer
)
910 pImpl
->mpTempObjectContainer
= new EmbeddedObjectContainer();
913 // TODO/LATER: in future probably the temporary container will have two storages ( of two formats )
914 // the media type will be provided with object insertion
915 OUString aOrigStorMediaType
;
916 uno::Reference
< beans::XPropertySet
> xStorProps( pImpl
->mxStorage
, uno::UNO_QUERY_THROW
);
917 static const OUStringLiteral
s_sMediaType("MediaType");
918 xStorProps
->getPropertyValue( s_sMediaType
) >>= aOrigStorMediaType
;
920 SAL_WARN_IF( aOrigStorMediaType
.isEmpty(), "comphelper.container", "No valuable media type in the storage!" );
922 uno::Reference
< beans::XPropertySet
> xTargetStorProps(
923 pImpl
->mpTempObjectContainer
->pImpl
->mxStorage
,
924 uno::UNO_QUERY_THROW
);
925 xTargetStorProps
->setPropertyValue( s_sMediaType
,uno::Any( aOrigStorMediaType
) );
927 catch (const uno::Exception
&)
929 SAL_WARN( "comphelper.container", "Can not set the new media type to a storage!" );
933 OUString aTempName
, aMediaType
;
934 pImpl
->mpTempObjectContainer
->InsertEmbeddedObject( xObj
, aTempName
);
936 uno::Reference
< io::XInputStream
> xStream
= GetGraphicStream( xObj
, &aMediaType
);
938 pImpl
->mpTempObjectContainer
->InsertGraphicStream( xStream
, aTempName
, aMediaType
);
940 // object is stored, so at least it can be set to loaded state
941 xObj
->changeState( embed::EmbedStates::LOADED
);
944 // objects without persistence need to stay in running state if they shall not be closed
945 xObj
->changeState( embed::EmbedStates::RUNNING
);
947 catch (const uno::Exception
&)
952 auto aIter
= std::find_if(pImpl
->maNameToObjectMap
.begin(), pImpl
->maNameToObjectMap
.end(),
953 [&xObj
](const EmbeddedObjectContainerNameMap::value_type
& rEntry
) { return rEntry
.second
== xObj
; });
954 if (aIter
!= pImpl
->maNameToObjectMap
.end())
956 pImpl
->maObjectToNameMap
.erase( aIter
->second
);
957 pImpl
->maNameToObjectMap
.erase( aIter
);
958 uno::Reference
< container::XChild
> xChild( xObj
, uno::UNO_QUERY
);
960 xChild
->setParent( uno::Reference
< uno::XInterface
>() );
963 SAL_WARN( "comphelper.container", "Object not found for removal!" );
965 if ( xPersist
.is() && bKeepToTempStorage
) // #i119941#
967 // remove replacement image (if there is one)
968 RemoveGraphicStream( aName
);
970 // now it's time to remove the storage from the container storage
973 #if OSL_DEBUG_LEVEL > 1
974 // if the object has a persistence and the object is not a link than it must have persistence entry in storage
975 OSL_ENSURE( bIsNotEmbedded
|| pImpl
->mxStorage
->hasByName( aName
), "The object has no persistence entry in the storage!" );
977 if ( xPersist
.is() && pImpl
->mxStorage
->hasByName( aName
) )
978 pImpl
->mxStorage
->removeElement( aName
);
980 catch (const uno::Exception
&)
982 SAL_WARN( "comphelper.container", "Failed to remove object from storage!" );
990 void EmbeddedObjectContainer::CloseEmbeddedObject( const uno::Reference
< embed::XEmbeddedObject
>& xObj
)
992 // disconnect the object from the container and close it if possible
994 auto aIter
= std::find_if(pImpl
->maNameToObjectMap
.begin(), pImpl
->maNameToObjectMap
.end(),
995 [&xObj
](const EmbeddedObjectContainerNameMap::value_type
& rEntry
) { return rEntry
.second
== xObj
; });
996 if (aIter
!= pImpl
->maNameToObjectMap
.end())
998 pImpl
->maObjectToNameMap
.erase( aIter
->second
);
999 pImpl
->maNameToObjectMap
.erase( aIter
);
1003 xObj
->close( true );
1005 catch (const uno::Exception
&)
1007 // it is no problem if the object is already closed
1008 // TODO/LATER: what if the object can not be closed?
1013 uno::Reference
< io::XInputStream
> EmbeddedObjectContainer::GetGraphicStream( const OUString
& aName
, OUString
* pMediaType
)
1015 uno::Reference
< io::XInputStream
> xStream
;
1017 SAL_WARN_IF( aName
.isEmpty(), "comphelper.container", "Retrieving graphic for unknown object!" );
1018 if ( !aName
.isEmpty() )
1022 uno::Reference
< embed::XStorage
> xReplacements
= pImpl
->GetReplacements();
1023 uno::Reference
< io::XStream
> xGraphicStream
= xReplacements
->openStreamElement( aName
, embed::ElementModes::READ
);
1024 xStream
= xGraphicStream
->getInputStream();
1027 uno::Reference
< beans::XPropertySet
> xSet( xStream
, uno::UNO_QUERY
);
1030 uno::Any aAny
= xSet
->getPropertyValue("MediaType");
1031 aAny
>>= *pMediaType
;
1035 catch (uno::Exception
const& e
)
1037 SAL_INFO("comphelper.container",
1038 "EmbeddedObjectContainer::GetGraphicStream(): " << e
);
1045 uno::Reference
< io::XInputStream
> EmbeddedObjectContainer::GetGraphicStream( const css::uno::Reference
< css::embed::XEmbeddedObject
>& xObj
, OUString
* pMediaType
)
1047 // try to load it from the container storage
1048 return GetGraphicStream( GetEmbeddedObjectName( xObj
), pMediaType
);
1051 bool EmbeddedObjectContainer::InsertGraphicStream( const css::uno::Reference
< css::io::XInputStream
>& rStream
, const OUString
& rObjectName
, const OUString
& rMediaType
)
1055 uno::Reference
< embed::XStorage
> xReplacements
= pImpl
->GetReplacements();
1057 // store it into the subfolder
1058 uno::Reference
< io::XOutputStream
> xOutStream
;
1059 uno::Reference
< io::XStream
> xGraphicStream
= xReplacements
->openStreamElement( rObjectName
,
1060 embed::ElementModes::READWRITE
| embed::ElementModes::TRUNCATE
);
1061 xOutStream
= xGraphicStream
->getOutputStream();
1062 ::comphelper::OStorageHelper::CopyInputToOutput( rStream
, xOutStream
);
1063 xOutStream
->flush();
1065 uno::Reference
< beans::XPropertySet
> xPropSet( xGraphicStream
, uno::UNO_QUERY_THROW
);
1067 xPropSet
->setPropertyValue("UseCommonStoragePasswordEncryption",
1069 xPropSet
->setPropertyValue("MediaType", uno::Any(rMediaType
) );
1071 xPropSet
->setPropertyValue("Compressed",
1074 catch (const uno::Exception
&)
1082 bool EmbeddedObjectContainer::InsertGraphicStreamDirectly( const css::uno::Reference
< css::io::XInputStream
>& rStream
, const OUString
& rObjectName
, const OUString
& rMediaType
)
1086 uno::Reference
< embed::XStorage
> xReplacement
= pImpl
->GetReplacements();
1087 uno::Reference
< embed::XOptimizedStorage
> xOptRepl( xReplacement
, uno::UNO_QUERY_THROW
);
1089 // store it into the subfolder
1090 uno::Sequence
< beans::PropertyValue
> aProps( 3 );
1091 aProps
[0].Name
= "MediaType";
1092 aProps
[0].Value
<<= rMediaType
;
1093 aProps
[1].Name
= "UseCommonStoragePasswordEncryption";
1094 aProps
[1].Value
<<= true;
1095 aProps
[2].Name
= "Compressed";
1096 aProps
[2].Value
<<= true;
1098 if ( xReplacement
->hasByName( rObjectName
) )
1099 xReplacement
->removeElement( rObjectName
);
1101 xOptRepl
->insertStreamElementDirect( rObjectName
, rStream
, aProps
);
1103 catch (const uno::Exception
&)
1112 void EmbeddedObjectContainer::RemoveGraphicStream( const OUString
& rObjectName
)
1116 uno::Reference
< embed::XStorage
> xReplacements
= pImpl
->GetReplacements();
1117 xReplacements
->removeElement( rObjectName
);
1119 catch (const uno::Exception
&)
1124 void InsertStreamIntoPicturesStorage_Impl( const uno::Reference
< embed::XStorage
>& xDocStor
,
1125 const uno::Reference
< io::XInputStream
>& xInStream
,
1126 const OUString
& aStreamName
)
1128 OSL_ENSURE( !aStreamName
.isEmpty() && xInStream
.is() && xDocStor
.is(), "Misuse of the method!" );
1132 uno::Reference
< embed::XStorage
> xPictures
= xDocStor
->openStorageElement(
1134 embed::ElementModes::READWRITE
);
1135 uno::Reference
< io::XStream
> xObjReplStr
= xPictures
->openStreamElement(
1137 embed::ElementModes::READWRITE
| embed::ElementModes::TRUNCATE
);
1138 uno::Reference
< io::XOutputStream
> xOutStream(
1139 xObjReplStr
->getInputStream(), uno::UNO_QUERY_THROW
);
1141 ::comphelper::OStorageHelper::CopyInputToOutput( xInStream
, xOutStream
);
1142 xOutStream
->closeOutput();
1144 uno::Reference
< embed::XTransactedObject
> xTransact( xPictures
, uno::UNO_QUERY
);
1145 if ( xTransact
.is() )
1146 xTransact
->commit();
1148 catch (const uno::Exception
&)
1150 SAL_WARN( "comphelper.container", "The images storage is not available!" );
1156 bool EmbeddedObjectContainer::StoreAsChildren(bool _bOasisFormat
,bool _bCreateEmbedded
,const uno::Reference
< embed::XStorage
>& _xStorage
)
1158 bool bResult
= false;
1161 comphelper::EmbeddedObjectContainer
aCnt( _xStorage
);
1162 const uno::Sequence
< OUString
> aNames
= GetObjectNames();
1163 const OUString
* pIter
= aNames
.getConstArray();
1164 const OUString
* pEnd
= pIter
+ aNames
.getLength();
1165 for(;pIter
!= pEnd
;++pIter
)
1167 uno::Reference
< embed::XEmbeddedObject
> xObj
= GetEmbeddedObject( *pIter
);
1168 SAL_WARN_IF( !xObj
.is(), "comphelper.container", "An empty entry in the embedded objects list!" );
1171 bool bSwitchBackToLoaded
= false;
1172 uno::Reference
< embed::XLinkageSupport
> xLink( xObj
, uno::UNO_QUERY
);
1174 uno::Reference
< io::XInputStream
> xStream
;
1175 OUString aMediaType
;
1177 sal_Int32 nCurState
= xObj
->getCurrentState();
1178 if ( nCurState
== embed::EmbedStates::LOADED
|| nCurState
== embed::EmbedStates::RUNNING
)
1180 // means that the object is not active
1181 // copy replacement image from old to new container
1182 xStream
= GetGraphicStream( xObj
, &aMediaType
);
1185 if ( !xStream
.is() && getUserAllowsLinkUpdate() )
1187 // the image must be regenerated
1188 // TODO/LATER: another aspect could be used
1189 if ( xObj
->getCurrentState() == embed::EmbedStates::LOADED
)
1190 bSwitchBackToLoaded
= true;
1192 xStream
= GetGraphicReplacementStream(
1193 embed::Aspects::MSOLE_CONTENT
,
1198 if ( _bOasisFormat
|| (xLink
.is() && xLink
->isLink()) )
1202 if ( _bOasisFormat
)
1204 // if it is an embedded object or the optimized inserting fails the normal inserting should be done
1205 if ( _bCreateEmbedded
1206 || !aCnt
.InsertGraphicStreamDirectly( xStream
, *pIter
, aMediaType
) )
1207 aCnt
.InsertGraphicStream( xStream
, *pIter
, aMediaType
);
1211 // it is a linked object exported into SO7 format
1212 InsertStreamIntoPicturesStorage_Impl( _xStorage
, xStream
, *pIter
);
1217 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
1218 if ( xPersist
.is() )
1220 uno::Sequence
< beans::PropertyValue
> aArgs( _bOasisFormat
? 2 : 3 );
1221 aArgs
[0].Name
= "StoreVisualReplacement";
1222 aArgs
[0].Value
<<= !_bOasisFormat
;
1224 // if it is an embedded object or the optimized inserting fails the normal inserting should be done
1225 aArgs
[1].Name
= "CanTryOptimization";
1226 aArgs
[1].Value
<<= !_bCreateEmbedded
;
1227 if ( !_bOasisFormat
)
1229 // if object has no cached replacement it will use this one
1230 aArgs
[2].Name
= "VisualReplacement";
1231 aArgs
[2].Value
<<= xStream
;
1236 xPersist
->storeAsEntry( _xStorage
, xPersist
->getEntryName(), uno::Sequence
< beans::PropertyValue
>(), aArgs
);
1238 catch (const embed::WrongStateException
&)
1240 SAL_WARN("comphelper.container", "failed to store '" << *pIter
<< "'");
1244 if ( bSwitchBackToLoaded
)
1245 // switch back to loaded state; that way we have a minimum cache confusion
1246 xObj
->changeState( embed::EmbedStates::LOADED
);
1250 bResult
= aCnt
.CommitImageSubStorage();
1253 catch (const uno::Exception
& e
)
1255 // TODO/LATER: error handling
1257 SAL_WARN("comphelper.container", "failed. Message: " << e
);
1260 // the old SO6 format does not store graphical replacements
1261 if ( !_bOasisFormat
&& bResult
)
1265 // the substorage still can not be locked by the embedded object container
1266 OUString
aObjReplElement( "ObjectReplacements" );
1267 if ( _xStorage
->hasByName( aObjReplElement
) && _xStorage
->isStorageElement( aObjReplElement
) )
1268 _xStorage
->removeElement( aObjReplElement
);
1270 catch (const uno::Exception
&)
1272 // TODO/LATER: error handling;
1279 bool EmbeddedObjectContainer::StoreChildren(bool _bOasisFormat
,bool _bObjectsOnly
)
1281 bool bResult
= true;
1282 const uno::Sequence
< OUString
> aNames
= GetObjectNames();
1283 const OUString
* pIter
= aNames
.getConstArray();
1284 const OUString
* pEnd
= pIter
+ aNames
.getLength();
1285 for(;pIter
!= pEnd
;++pIter
)
1287 uno::Reference
< embed::XEmbeddedObject
> xObj
= GetEmbeddedObject( *pIter
);
1288 SAL_WARN_IF( !xObj
.is(), "comphelper.container", "An empty entry in the embedded objects list!" );
1291 sal_Int32 nCurState
= xObj
->getCurrentState();
1292 if ( _bOasisFormat
&& nCurState
!= embed::EmbedStates::LOADED
&& nCurState
!= embed::EmbedStates::RUNNING
)
1294 // means that the object is active
1295 // the image must be regenerated
1296 OUString aMediaType
;
1298 // TODO/LATER: another aspect could be used
1299 uno::Reference
< io::XInputStream
> xStream
=
1300 GetGraphicReplacementStream(
1301 embed::Aspects::MSOLE_CONTENT
,
1306 if ( !InsertGraphicStreamDirectly( xStream
, *pIter
, aMediaType
) )
1307 InsertGraphicStream( xStream
, *pIter
, aMediaType
);
1311 // TODO/LATER: currently the object by default does not cache replacement image
1312 // that means that if somebody loads SO7 document and store its objects using
1313 // this method the images might be lost.
1314 // Currently this method is only used on storing to alien formats, that means
1315 // that SO7 documents storing does not use it, and all other filters are
1316 // based on OASIS format. But if it changes the method must be fixed. The fix
1317 // must be done only on demand since it can affect performance.
1319 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
1320 if ( xPersist
.is() )
1324 //TODO/LATER: only storing if changed!
1325 //xPersist->storeOwn(); //commented, i120168
1327 // begin:all charts will be persisted as xml format on disk when saving, which is time consuming.
1328 // '_bObjectsOnly' mean we are storing to alien formats.
1329 // 'isStorageElement' mean current object is NOT a MS OLE format. (may also include in future), i120168
1330 if (_bObjectsOnly
&& (nCurState
== embed::EmbedStates::LOADED
|| nCurState
== embed::EmbedStates::RUNNING
)
1331 && (pImpl
->mxStorage
->isStorageElement( *pIter
) ))
1333 uno::Reference
< util::XModifiable
> xModifiable( xObj
->getComponent(), uno::UNO_QUERY
);
1334 if ( xModifiable
.is() && xModifiable
->isModified())
1336 xPersist
->storeOwn();
1340 //do nothing. Embedded model is not modified, no need to persist.
1343 else //the embedded object is in active status, always store back it.
1345 xPersist
->storeOwn();
1349 catch (const uno::Exception
&)
1351 // TODO/LATER: error handling
1357 if ( !_bOasisFormat
&& !_bObjectsOnly
)
1359 // copy replacement images for linked objects
1362 uno::Reference
< embed::XLinkageSupport
> xLink( xObj
, uno::UNO_QUERY
);
1363 if ( xLink
.is() && xLink
->isLink() )
1365 OUString aMediaType
;
1366 uno::Reference
< io::XInputStream
> xInStream
= GetGraphicStream( xObj
, &aMediaType
);
1367 if ( xInStream
.is() )
1368 InsertStreamIntoPicturesStorage_Impl( pImpl
->mxStorage
, xInStream
, *pIter
);
1371 catch (const uno::Exception
&)
1378 if ( bResult
&& _bOasisFormat
)
1379 bResult
= CommitImageSubStorage();
1381 if ( bResult
&& !_bObjectsOnly
)
1385 ReleaseImageSubStorage();
1386 OUString
aObjReplElement( "ObjectReplacements" );
1387 if ( !_bOasisFormat
&& pImpl
->mxStorage
->hasByName( aObjReplElement
) && pImpl
->mxStorage
->isStorageElement( aObjReplElement
) )
1388 pImpl
->mxStorage
->removeElement( aObjReplElement
);
1390 catch (const uno::Exception
&)
1392 // TODO/LATER: error handling
1399 uno::Reference
< io::XInputStream
> EmbeddedObjectContainer::GetGraphicReplacementStream(
1400 sal_Int64 nViewAspect
,
1401 const uno::Reference
< embed::XEmbeddedObject
>& xObj
,
1402 OUString
* pMediaType
)
1404 uno::Reference
< io::XInputStream
> xInStream
;
1409 // retrieving of the visual representation can switch object to running state
1410 embed::VisualRepresentation aRep
= xObj
->getPreferredVisualRepresentation( nViewAspect
);
1412 *pMediaType
= aRep
.Flavor
.MimeType
;
1414 uno::Sequence
< sal_Int8
> aSeq
;
1416 xInStream
= new ::comphelper::SequenceInputStream( aSeq
);
1418 catch (const uno::Exception
&)
1426 bool EmbeddedObjectContainer::SetPersistentEntries(const uno::Reference
< embed::XStorage
>& _xStorage
,bool _bClearModifedFlag
)
1428 bool bError
= false;
1429 const uno::Sequence
< OUString
> aNames
= GetObjectNames();
1430 const OUString
* pIter
= aNames
.getConstArray();
1431 const OUString
* pEnd
= pIter
+ aNames
.getLength();
1432 for(;pIter
!= pEnd
;++pIter
)
1434 uno::Reference
< embed::XEmbeddedObject
> xObj
= GetEmbeddedObject( *pIter
);
1435 SAL_WARN_IF( !xObj
.is(), "comphelper.container", "An empty entry in the embedded objects list!" );
1438 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
1439 if ( xPersist
.is() )
1443 xPersist
->setPersistentEntry( _xStorage
,
1445 embed::EntryInitModes::NO_INIT
,
1446 uno::Sequence
< beans::PropertyValue
>(),
1447 uno::Sequence
< beans::PropertyValue
>() );
1450 catch (const uno::Exception
&)
1452 // TODO/LATER: error handling
1457 if ( _bClearModifedFlag
)
1459 // if this method is used as part of SaveCompleted the object must stay unmodified after execution
1462 uno::Reference
< util::XModifiable
> xModif( xObj
->getComponent(), uno::UNO_QUERY_THROW
);
1463 if ( xModif
->isModified() )
1464 xModif
->setModified( false );
1466 catch (const uno::Exception
&)
1475 bool EmbeddedObjectContainer::getUserAllowsLinkUpdate() const
1477 return pImpl
->mbUserAllowsLinkUpdate
;
1480 void EmbeddedObjectContainer::setUserAllowsLinkUpdate(bool bNew
)
1482 if(pImpl
->mbUserAllowsLinkUpdate
!= bNew
)
1484 pImpl
->mbUserAllowsLinkUpdate
= bNew
;
1490 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */