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/XLinkCreator.hpp>
24 #include <com/sun/star/embed/XEmbedPersist.hpp>
25 #include <com/sun/star/embed/XLinkageSupport.hpp>
26 #include <com/sun/star/embed/XTransactedObject.hpp>
27 #include <com/sun/star/embed/XOptimizedStorage.hpp>
28 #include <com/sun/star/embed/EntryInitModes.hpp>
29 #include <com/sun/star/util/XCloseable.hpp>
30 #include <com/sun/star/util/XModifiable.hpp>
31 #include <com/sun/star/embed/EmbedStates.hpp>
32 #include <com/sun/star/datatransfer/XTransferable.hpp>
33 #include <com/sun/star/beans/XPropertySetInfo.hpp>
34 #include <com/sun/star/beans/XPropertySet.hpp>
35 #include <com/sun/star/embed/Aspects.hpp>
36 #include <com/sun/star/embed/EmbedMisc.hpp>
38 #include <comphelper/seqstream.hxx>
39 #include <comphelper/processfactory.hxx>
40 #include <comphelper/storagehelper.hxx>
41 #include <comphelper/embeddedobjectcontainer.hxx>
42 #include <comphelper/sequence.hxx>
43 #include <comphelper/propertysequence.hxx>
44 #include <cppuhelper/weakref.hxx>
45 #include <sal/log.hxx>
48 #include <unordered_map>
51 using namespace ::com::sun::star
;
53 namespace comphelper
{
55 typedef std::unordered_map
<OUString
, uno::Reference
<embed::XEmbeddedObject
>, OUStringHash
>
56 EmbeddedObjectContainerNameMap
;
60 // TODO/LATER: remove objects from temp. Container storage when object is disposed
61 EmbeddedObjectContainerNameMap maObjectContainer
;
62 uno::Reference
< embed::XStorage
> mxStorage
;
63 EmbeddedObjectContainer
* mpTempObjectContainer
;
64 uno::Reference
< embed::XStorage
> mxImageStorage
;
65 uno::WeakReference
< uno::XInterface
> m_xModel
;
66 //EmbeddedObjectContainerNameMap maTempObjectContainer;
67 //uno::Reference < embed::XStorage > mxTempStorage;
70 bool mbOwnsStorage
: 1;
71 bool mbUserAllowsLinkUpdate
: 1;
73 const uno::Reference
< embed::XStorage
>& GetReplacements();
76 const uno::Reference
< embed::XStorage
>& EmbedImpl::GetReplacements()
78 if ( !mxImageStorage
.is() )
82 mxImageStorage
= mxStorage
->openStorageElement(
83 OUString("ObjectReplacements"), embed::ElementModes::READWRITE
);
85 catch (const uno::Exception
&)
87 mxImageStorage
= mxStorage
->openStorageElement(
88 OUString("ObjectReplacements"), embed::ElementModes::READ
);
92 if ( !mxImageStorage
.is() )
93 throw io::IOException();
95 return mxImageStorage
;
98 EmbeddedObjectContainer::EmbeddedObjectContainer()
100 pImpl
= new EmbedImpl
;
101 pImpl
->mxStorage
= ::comphelper::OStorageHelper::GetTemporaryStorage();
102 pImpl
->mbOwnsStorage
= true;
103 pImpl
->mbUserAllowsLinkUpdate
= true;
104 pImpl
->mpTempObjectContainer
= 0;
107 EmbeddedObjectContainer::EmbeddedObjectContainer( const uno::Reference
< embed::XStorage
>& rStor
)
109 pImpl
= new EmbedImpl
;
110 pImpl
->mxStorage
= rStor
;
111 pImpl
->mbOwnsStorage
= false;
112 pImpl
->mbUserAllowsLinkUpdate
= true;
113 pImpl
->mpTempObjectContainer
= 0;
116 EmbeddedObjectContainer::EmbeddedObjectContainer( const uno::Reference
< embed::XStorage
>& rStor
, const uno::Reference
< uno::XInterface
>& xModel
)
118 pImpl
= new EmbedImpl
;
119 pImpl
->mxStorage
= rStor
;
120 pImpl
->mbOwnsStorage
= false;
121 pImpl
->mbUserAllowsLinkUpdate
= true;
122 pImpl
->mpTempObjectContainer
= 0;
123 pImpl
->m_xModel
= xModel
;
126 void EmbeddedObjectContainer::SwitchPersistence( const uno::Reference
< embed::XStorage
>& rStor
)
128 ReleaseImageSubStorage();
130 if ( pImpl
->mbOwnsStorage
)
131 pImpl
->mxStorage
->dispose();
133 pImpl
->mxStorage
= rStor
;
134 pImpl
->mbOwnsStorage
= false;
137 bool EmbeddedObjectContainer::CommitImageSubStorage()
139 if ( pImpl
->mxImageStorage
.is() )
143 bool bReadOnlyMode
= true;
144 uno::Reference
< beans::XPropertySet
> xSet(pImpl
->mxImageStorage
,uno::UNO_QUERY
);
147 // get the open mode from the parent storage
149 uno::Any aAny
= xSet
->getPropertyValue("OpenMode");
150 if ( aAny
>>= nMode
)
151 bReadOnlyMode
= !(nMode
& embed::ElementModes::WRITE
);
152 } // if ( xSet.is() )
153 if ( !bReadOnlyMode
)
155 uno::Reference
< embed::XTransactedObject
> xTransact( pImpl
->mxImageStorage
, uno::UNO_QUERY_THROW
);
159 catch (const uno::Exception
&)
168 void EmbeddedObjectContainer::ReleaseImageSubStorage()
170 CommitImageSubStorage();
172 if ( pImpl
->mxImageStorage
.is() )
176 pImpl
->mxImageStorage
->dispose();
177 pImpl
->mxImageStorage
= uno::Reference
< embed::XStorage
>();
179 catch (const uno::Exception
&)
181 SAL_WARN( "comphelper.container", "Problems releasing image substorage!\n" );
186 EmbeddedObjectContainer::~EmbeddedObjectContainer()
188 ReleaseImageSubStorage();
190 if ( pImpl
->mbOwnsStorage
)
191 pImpl
->mxStorage
->dispose();
193 delete pImpl
->mpTempObjectContainer
;
197 void EmbeddedObjectContainer::CloseEmbeddedObjects()
199 EmbeddedObjectContainerNameMap::iterator aIt
= pImpl
->maObjectContainer
.begin();
200 while ( aIt
!= pImpl
->maObjectContainer
.end() )
202 uno::Reference
< util::XCloseable
> xClose( (*aIt
).second
, uno::UNO_QUERY
);
207 xClose
->close( sal_True
);
209 catch (const uno::Exception
&)
218 OUString
EmbeddedObjectContainer::CreateUniqueObjectName()
220 OUString
aPersistName("Object ");
226 aStr
+= OUString::number( i
++ );
228 while( HasEmbeddedObject( aStr
) );
229 // TODO/LATER: should we consider deleted objects?
234 uno::Sequence
< OUString
> EmbeddedObjectContainer::GetObjectNames()
236 uno::Sequence
< OUString
> aSeq( pImpl
->maObjectContainer
.size() );
237 EmbeddedObjectContainerNameMap::iterator aIt
= pImpl
->maObjectContainer
.begin();
239 while ( aIt
!= pImpl
->maObjectContainer
.end() )
240 aSeq
[nIdx
++] = (*aIt
++).first
;
244 bool EmbeddedObjectContainer::HasEmbeddedObjects()
246 return pImpl
->maObjectContainer
.size() != 0;
249 bool EmbeddedObjectContainer::HasEmbeddedObject( const OUString
& rName
)
251 EmbeddedObjectContainerNameMap::iterator aIt
= pImpl
->maObjectContainer
.find( rName
);
252 if ( aIt
== pImpl
->maObjectContainer
.end() )
254 uno::Reference
< container::XNameAccess
> xAccess( pImpl
->mxStorage
, uno::UNO_QUERY
);
255 return xAccess
->hasByName(rName
);
261 bool EmbeddedObjectContainer::HasEmbeddedObject( const uno::Reference
< embed::XEmbeddedObject
>& xObj
)
263 EmbeddedObjectContainerNameMap::iterator aIt
= pImpl
->maObjectContainer
.begin();
264 while ( aIt
!= pImpl
->maObjectContainer
.end() )
266 if ( (*aIt
).second
== xObj
)
275 bool EmbeddedObjectContainer::HasInstantiatedEmbeddedObject( const OUString
& rName
)
277 // allows to detect whether the object was already instantiated
278 // currently the filter instantiate it on loading, so this method allows
279 // to avoid objects pointing to the same persistence
280 EmbeddedObjectContainerNameMap::iterator aIt
= pImpl
->maObjectContainer
.find( rName
);
281 return ( aIt
!= pImpl
->maObjectContainer
.end() );
284 OUString
EmbeddedObjectContainer::GetEmbeddedObjectName( const ::com::sun::star::uno::Reference
< ::com::sun::star::embed::XEmbeddedObject
>& xObj
)
286 EmbeddedObjectContainerNameMap::iterator aIt
= pImpl
->maObjectContainer
.begin();
287 while ( aIt
!= pImpl
->maObjectContainer
.end() )
289 if ( (*aIt
).second
== xObj
)
295 SAL_WARN( "comphelper.container", "Unknown object!" );
299 uno::Reference
< embed::XEmbeddedObject
> EmbeddedObjectContainer::GetEmbeddedObject( const OUString
& rName
)
301 SAL_WARN_IF( rName
.isEmpty(), "comphelper.container", "Empty object name!");
303 uno::Reference
< embed::XEmbeddedObject
> xObj
;
304 EmbeddedObjectContainerNameMap::iterator aIt
= pImpl
->maObjectContainer
.find( rName
);
306 #if OSL_DEBUG_LEVEL > 1
307 uno::Reference
< container::XNameAccess
> xAccess( pImpl
->mxStorage
, uno::UNO_QUERY
);
308 uno::Sequence
< OUString
> aSeq
= xAccess
->getElementNames();
309 const OUString
* pIter
= aSeq
.getConstArray();
310 const OUString
* pEnd
= pIter
+ aSeq
.getLength();
311 for(;pIter
!= pEnd
;++pIter
)
315 OSL_ENSURE( aIt
!= pImpl
->maObjectContainer
.end() || xAccess
->hasByName(rName
), "Could not return object!" );
318 // check if object was already created
319 if ( aIt
!= pImpl
->maObjectContainer
.end() )
320 xObj
= (*aIt
).second
;
322 xObj
= Get_Impl( rName
, uno::Reference
< embed::XEmbeddedObject
>() );
327 uno::Reference
< embed::XEmbeddedObject
> EmbeddedObjectContainer::Get_Impl( const OUString
& rName
, const uno::Reference
< embed::XEmbeddedObject
>& xCopy
)
329 uno::Reference
< embed::XEmbeddedObject
> xObj
;
332 // create the object from the storage
333 uno::Reference
< beans::XPropertySet
> xSet( pImpl
->mxStorage
, uno::UNO_QUERY
);
334 bool bReadOnlyMode
= true;
337 // get the open mode from the parent storage
339 uno::Any aAny
= xSet
->getPropertyValue("OpenMode");
340 if ( aAny
>>= nMode
)
341 bReadOnlyMode
= !(nMode
& embed::ElementModes::WRITE
);
344 // object was not added until now - should happen only by calling this method from "inside"
345 //TODO/LATER: it would be good to detect an error when an object should be created already, but isn't (not an "inside" call)
346 uno::Reference
< embed::XEmbeddedObjectCreator
> xFactory
= embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() );
347 uno::Sequence
< beans::PropertyValue
> aObjDescr( xCopy
.is() ? 2 : 1 );
348 aObjDescr
[0].Name
= "Parent";
349 aObjDescr
[0].Value
<<= pImpl
->m_xModel
.get();
352 aObjDescr
[1].Name
= "CloneFrom";
353 aObjDescr
[1].Value
<<= xCopy
;
356 uno::Sequence
< beans::PropertyValue
> aMediaDescr( 1 );
357 aMediaDescr
[0].Name
= "ReadOnly";
358 aMediaDescr
[0].Value
<<= bReadOnlyMode
;
359 xObj
= uno::Reference
< embed::XEmbeddedObject
>( xFactory
->createInstanceInitFromEntry(
360 pImpl
->mxStorage
, rName
,
361 aMediaDescr
, aObjDescr
), uno::UNO_QUERY
);
363 // insert object into my list
364 AddEmbeddedObject( xObj
, rName
);
366 catch (uno::Exception
const& e
)
368 SAL_WARN("comphelper.container", "EmbeddedObjectContainer::Get_Impl: exception caught: " << e
.Message
);
374 uno::Reference
< embed::XEmbeddedObject
> EmbeddedObjectContainer::CreateEmbeddedObject( const uno::Sequence
< sal_Int8
>& rClassId
,
375 const uno::Sequence
< beans::PropertyValue
>& rArgs
, OUString
& rNewName
)
377 if ( rNewName
.isEmpty() )
378 rNewName
= CreateUniqueObjectName();
380 SAL_WARN_IF( HasEmbeddedObject(rNewName
), "comphelper.container", "Object to create already exists!");
382 // create object from classid by inserting it into storage
383 uno::Reference
< embed::XEmbeddedObject
> xObj
;
386 uno::Reference
< embed::XEmbeddedObjectCreator
> xFactory
= embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() );
388 uno::Sequence
< beans::PropertyValue
> aObjDescr( rArgs
.getLength() + 1 );
389 aObjDescr
[0].Name
= "Parent";
390 aObjDescr
[0].Value
<<= pImpl
->m_xModel
.get();
391 ::std::copy( rArgs
.getConstArray(), rArgs
.getConstArray() + rArgs
.getLength(), aObjDescr
.getArray() + 1 );
392 xObj
= uno::Reference
< embed::XEmbeddedObject
>( xFactory
->createInstanceInitNew(
393 rClassId
, OUString(), pImpl
->mxStorage
, rNewName
,
394 aObjDescr
), uno::UNO_QUERY
);
396 AddEmbeddedObject( xObj
, rNewName
);
398 OSL_ENSURE( !xObj
.is() || xObj
->getCurrentState() != embed::EmbedStates::LOADED
,
399 "A freshly create object should be running always!\n" );
401 catch (uno::Exception
const& e
)
403 SAL_WARN("comphelper.container", "EmbeddedObjectContainer::CreateEmbeddedObject: exception caught: " << e
.Message
);
409 uno::Reference
< embed::XEmbeddedObject
> EmbeddedObjectContainer::CreateEmbeddedObject( const uno::Sequence
< sal_Int8
>& rClassId
, OUString
& rNewName
)
411 return CreateEmbeddedObject( rClassId
, uno::Sequence
< beans::PropertyValue
>(), rNewName
);
414 void EmbeddedObjectContainer::AddEmbeddedObject( const ::com::sun::star::uno::Reference
< ::com::sun::star::embed::XEmbeddedObject
>& xObj
, const OUString
& rName
)
416 #if OSL_DEBUG_LEVEL > 1
417 SAL_WARN_IF( rName
.isEmpty(), "comphelper.container", "Added object doesn't have a name!");
418 uno::Reference
< container::XNameAccess
> xAccess( pImpl
->mxStorage
, uno::UNO_QUERY
);
419 uno::Reference
< embed::XEmbedPersist
> xEmb( xObj
, uno::UNO_QUERY
);
420 uno::Reference
< embed::XLinkageSupport
> xLink( xEmb
, uno::UNO_QUERY
);
421 // if the object has a persistence and the object is not a link than it must have persistence entry in the storage
422 OSL_ENSURE( !( xEmb
.is() && ( !xLink
.is() || !xLink
->isLink() ) ) || xAccess
->hasByName(rName
),
423 "Added element not in storage!" );
426 // remember object - it needs to be in storage already
427 EmbeddedObjectContainerNameMap::iterator aIt
= pImpl
->maObjectContainer
.find( rName
);
428 OSL_ENSURE( aIt
== pImpl
->maObjectContainer
.end(), "Element already inserted!" );
429 pImpl
->maObjectContainer
[ rName
] = xObj
;
430 uno::Reference
< container::XChild
> xChild( xObj
, uno::UNO_QUERY
);
431 if ( xChild
.is() && xChild
->getParent() != pImpl
->m_xModel
.get() )
432 xChild
->setParent( pImpl
->m_xModel
.get() );
434 // look for object in temporary container
435 if ( pImpl
->mpTempObjectContainer
)
437 aIt
= pImpl
->mpTempObjectContainer
->pImpl
->maObjectContainer
.begin();
438 while ( aIt
!= pImpl
->mpTempObjectContainer
->pImpl
->maObjectContainer
.end() )
440 if ( (*aIt
).second
== xObj
)
442 // copy replacement image from temporary container (if there is any)
443 OUString aTempName
= (*aIt
).first
;
445 uno::Reference
< io::XInputStream
> xStream
= pImpl
->mpTempObjectContainer
->GetGraphicStream( xObj
, &aMediaType
);
448 InsertGraphicStream( xStream
, rName
, aMediaType
);
450 pImpl
->mpTempObjectContainer
->RemoveGraphicStream( aTempName
);
453 // remove object from storage of temporary container
454 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
459 pImpl
->mpTempObjectContainer
->pImpl
->mxStorage
->removeElement( aTempName
);
461 catch (const uno::Exception
&)
466 // temp. container needs to forget the object
467 pImpl
->mpTempObjectContainer
->pImpl
->maObjectContainer
.erase( aIt
);
476 bool EmbeddedObjectContainer::StoreEmbeddedObject(
477 const uno::Reference
< embed::XEmbeddedObject
>& xObj
, OUString
& rName
, bool bCopy
,
478 const OUString
& rSrcShellID
, const OUString
& rDestShellID
)
480 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
481 if ( rName
.isEmpty() )
482 rName
= CreateUniqueObjectName();
484 #if OSL_DEBUG_LEVEL > 1
485 uno::Reference
< container::XNameAccess
> xAccess( pImpl
->mxStorage
, uno::UNO_QUERY
);
486 OSL_ENSURE( !xPersist
.is() || !xAccess
->hasByName(rName
), "Inserting element already present in storage!" );
487 OSL_ENSURE( xPersist
.is() || xObj
->getCurrentState() == embed::EmbedStates::RUNNING
, "Non persistent object inserted!");
490 // insert objects' storage into the container storage (if object has one)
495 uno::Sequence
< beans::PropertyValue
> aSeq
;
498 auto aObjArgs(::comphelper::InitPropertySequence({
499 { "SourceShellID", uno::makeAny(rSrcShellID
) },
500 { "DestinationShellID", uno::makeAny(rDestShellID
) }
502 xPersist
->storeToEntry(pImpl
->mxStorage
, rName
, aSeq
, aObjArgs
);
506 //TODO/LATER: possible optimization, don't store immediately
507 //xPersist->setPersistentEntry( pImpl->mxStorage, rName, embed::EntryInitModes::ENTRY_NO_INIT, aSeq, aSeq );
508 xPersist
->storeAsEntry( pImpl
->mxStorage
, rName
, aSeq
, aSeq
);
509 xPersist
->saveCompleted( sal_True
);
513 catch (uno::Exception
const& e
)
515 SAL_WARN("comphelper.container", "EmbeddedObjectContainer::StoreEmbeddedObject: exception caught: " << e
.Message
);
516 // TODO/LATER: better error recovery should keep storage intact
523 bool EmbeddedObjectContainer::InsertEmbeddedObject( const uno::Reference
< embed::XEmbeddedObject
>& xObj
, OUString
& rName
)
525 // store it into the container storage
526 if (StoreEmbeddedObject(xObj
, rName
, false, OUString(), OUString()))
529 AddEmbeddedObject( xObj
, rName
);
536 uno::Reference
< embed::XEmbeddedObject
> EmbeddedObjectContainer::InsertEmbeddedObject( const uno::Reference
< io::XInputStream
>& xStm
, OUString
& rNewName
)
538 if ( rNewName
.isEmpty() )
539 rNewName
= CreateUniqueObjectName();
541 // store it into the container storage
542 bool bIsStorage
= false;
545 // first try storage persistence
546 uno::Reference
< embed::XStorage
> xStore
= ::comphelper::OStorageHelper::GetStorageFromInputStream( xStm
);
548 // storage was created from stream successfully
551 uno::Reference
< embed::XStorage
> xNewStore
= pImpl
->mxStorage
->openStorageElement( rNewName
, embed::ElementModes::READWRITE
);
552 xStore
->copyToStorage( xNewStore
);
554 catch (const uno::Exception
&)
557 // it is storage persistence, but opening of new substorage or copying to it failed
558 return uno::Reference
< embed::XEmbeddedObject
>();
560 // stream didn't contain a storage, now try stream persistence
563 uno::Reference
< io::XStream
> xNewStream
= pImpl
->mxStorage
->openStreamElement( rNewName
, embed::ElementModes::READWRITE
);
564 ::comphelper::OStorageHelper::CopyInputToOutput( xStm
, xNewStream
->getOutputStream() );
566 // No mediatype is provided so the default for OLE objects value is used
567 // it is correct so for now, but what if somebody introduces a new stream based embedded object?
568 // Probably introducing of such an object must be restricted ( a storage must be used! ).
569 uno::Reference
< beans::XPropertySet
> xProps( xNewStream
, uno::UNO_QUERY_THROW
);
570 xProps
->setPropertyValue("MediaType",
571 uno::makeAny( OUString( "application/vnd.sun.star.oleobject" ) ) );
573 catch (uno::Exception
const& e
)
575 // complete disaster!
576 SAL_WARN("comphelper.container", "EmbeddedObjectContainer::InsertEmbeddedObject: exception caught: " << e
.Message
);
577 return uno::Reference
< embed::XEmbeddedObject
>();
581 // stream was copied into the container storage in either way, now try to open something form it
582 uno::Reference
< embed::XEmbeddedObject
> xRet
= GetEmbeddedObject( rNewName
);
586 // no object could be created, so withdraw insertion
587 pImpl
->mxStorage
->removeElement( rNewName
);
589 catch (const uno::Exception
&)
596 uno::Reference
< embed::XEmbeddedObject
> EmbeddedObjectContainer::InsertEmbeddedObject( const ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
>& aMedium
, OUString
& rNewName
)
598 if ( rNewName
.isEmpty() )
599 rNewName
= CreateUniqueObjectName();
601 uno::Reference
< embed::XEmbeddedObject
> xObj
;
604 uno::Reference
< embed::XEmbeddedObjectCreator
> xFactory
= embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() );
605 uno::Sequence
< beans::PropertyValue
> aObjDescr( 1 );
606 aObjDescr
[0].Name
= "Parent";
607 aObjDescr
[0].Value
<<= pImpl
->m_xModel
.get();
608 xObj
= uno::Reference
< embed::XEmbeddedObject
>( xFactory
->createInstanceInitFromMediaDescriptor(
609 pImpl
->mxStorage
, rNewName
, aMedium
, aObjDescr
), uno::UNO_QUERY
);
610 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
612 OSL_ENSURE( !xObj
.is() || xObj
->getCurrentState() != embed::EmbedStates::LOADED
,
613 "A freshly create object should be running always!\n" );
615 // possible optimization: store later!
617 xPersist
->storeOwn();
619 AddEmbeddedObject( xObj
, rNewName
);
621 catch (const uno::Exception
&)
628 uno::Reference
< embed::XEmbeddedObject
> EmbeddedObjectContainer::InsertEmbeddedLink( const ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
>& aMedium
, OUString
& rNewName
)
630 if ( rNewName
.isEmpty() )
631 rNewName
= CreateUniqueObjectName();
633 uno::Reference
< embed::XEmbeddedObject
> xObj
;
636 uno::Reference
< embed::XEmbeddedObjectCreator
> xFactory
= embed::EmbeddedObjectCreator::create(::comphelper::getProcessComponentContext());
637 uno::Sequence
< beans::PropertyValue
> aObjDescr( 1 );
638 aObjDescr
[0].Name
= "Parent";
639 aObjDescr
[0].Value
<<= pImpl
->m_xModel
.get();
640 xObj
= uno::Reference
< embed::XEmbeddedObject
>( xFactory
->createInstanceLink(
641 pImpl
->mxStorage
, rNewName
, aMedium
, aObjDescr
), uno::UNO_QUERY
);
643 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
645 OSL_ENSURE( !xObj
.is() || xObj
->getCurrentState() != embed::EmbedStates::LOADED
,
646 "A freshly create object should be running always!\n" );
648 // possible optimization: store later!
650 xPersist
->storeOwn();
652 AddEmbeddedObject( xObj
, rNewName
);
654 catch (uno::Exception
const& e
)
656 SAL_WARN("comphelper", "EmbeddedObjectContainer::InsertEmbeddedLink: "
657 "exception caught: " << e
.Message
);
663 bool EmbeddedObjectContainer::TryToCopyGraphReplacement( EmbeddedObjectContainer
& rSrc
,
664 const OUString
& aOrigName
,
665 const OUString
& aTargetName
)
667 bool bResult
= false;
669 if ( ( &rSrc
!= this || !aOrigName
.equals( aTargetName
) ) && !aOrigName
.isEmpty() && !aTargetName
.isEmpty() )
672 uno::Reference
< io::XInputStream
> xGrStream
= rSrc
.GetGraphicStream( aOrigName
, &aMediaType
);
673 if ( xGrStream
.is() )
674 bResult
= InsertGraphicStream( xGrStream
, aTargetName
, aMediaType
);
680 uno::Reference
< embed::XEmbeddedObject
> EmbeddedObjectContainer::CopyAndGetEmbeddedObject(
681 EmbeddedObjectContainer
& rSrc
, const uno::Reference
<embed::XEmbeddedObject
>& xObj
, OUString
& rName
,
682 const OUString
& rSrcShellID
, const OUString
& rDestShellID
)
684 uno::Reference
< embed::XEmbeddedObject
> xResult
;
686 // TODO/LATER: For now only objects that implement XEmbedPersist have a replacement image, it might change in future
687 // do an incompatible change so that object name is provided in all the move and copy methods
691 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY_THROW
);
692 aOrigName
= xPersist
->getEntryName();
694 catch (const uno::Exception
&)
698 if ( rName
.isEmpty() )
699 rName
= CreateUniqueObjectName();
701 // objects without persistence are not really stored by the method
702 if (xObj
.is() && StoreEmbeddedObject(xObj
, rName
, true, rSrcShellID
, rDestShellID
))
704 xResult
= Get_Impl( rName
, xObj
);
707 // this is a case when object has no real persistence
708 // in such cases a new object should be explicitly created and initialized with the data of the old one
711 uno::Reference
< embed::XLinkageSupport
> xOrigLinkage( xObj
, uno::UNO_QUERY
);
712 if ( xOrigLinkage
.is() && xOrigLinkage
->isLink() )
714 // this is a OOo link, it has no persistence
715 OUString aURL
= xOrigLinkage
->getLinkURL();
716 if ( aURL
.isEmpty() )
717 throw uno::RuntimeException();
719 // create new linked object from the URL the link is based on
720 uno::Reference
< embed::XEmbeddedObjectCreator
> xCreator
=
721 embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() );
723 uno::Sequence
< beans::PropertyValue
> aMediaDescr( 1 );
724 aMediaDescr
[0].Name
= "URL";
725 aMediaDescr
[0].Value
<<= aURL
;
726 uno::Sequence
< beans::PropertyValue
> aObjDescr( 1 );
727 aObjDescr
[0].Name
= "Parent";
728 aObjDescr
[0].Value
<<= pImpl
->m_xModel
.get();
729 xResult
= uno::Reference
< embed::XEmbeddedObject
>(
730 xCreator
->createInstanceLink(
735 uno::UNO_QUERY_THROW
);
739 // the component is required for copying of this object
740 if ( xObj
->getCurrentState() == embed::EmbedStates::LOADED
)
741 xObj
->changeState( embed::EmbedStates::RUNNING
);
743 // this must be an object based on properties, otherwise we can not copy it currently
744 uno::Reference
< beans::XPropertySet
> xOrigProps( xObj
->getComponent(), uno::UNO_QUERY_THROW
);
746 // use object class ID to create a new one and transfer all the properties
747 uno::Reference
< embed::XEmbeddedObjectCreator
> xCreator
=
748 embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() );
750 uno::Sequence
< beans::PropertyValue
> aObjDescr( 1 );
751 aObjDescr
[0].Name
= "Parent";
752 aObjDescr
[0].Value
<<= pImpl
->m_xModel
.get();
753 xResult
= uno::Reference
< embed::XEmbeddedObject
>(
754 xCreator
->createInstanceInitNew(
756 xObj
->getClassName(),
760 uno::UNO_QUERY_THROW
);
762 if ( xResult
->getCurrentState() == embed::EmbedStates::LOADED
)
763 xResult
->changeState( embed::EmbedStates::RUNNING
);
765 uno::Reference
< beans::XPropertySet
> xTargetProps( xResult
->getComponent(), uno::UNO_QUERY_THROW
);
767 // copy all the properties from xOrigProps to xTargetProps
768 uno::Reference
< beans::XPropertySetInfo
> xOrigInfo
= xOrigProps
->getPropertySetInfo();
769 if ( !xOrigInfo
.is() )
770 throw uno::RuntimeException();
772 uno::Sequence
< beans::Property
> aPropertiesList
= xOrigInfo
->getProperties();
773 for ( sal_Int32 nInd
= 0; nInd
< aPropertiesList
.getLength(); nInd
++ )
777 xTargetProps
->setPropertyValue(
778 aPropertiesList
[nInd
].Name
,
779 xOrigProps
->getPropertyValue( aPropertiesList
[nInd
].Name
) );
781 catch (const beans::PropertyVetoException
&)
783 // impossibility to copy readonly property is not treated as an error for now
784 // but the assertion is helpful to detect such scenarios and review them
785 SAL_WARN( "comphelper.container", "Could not copy readonly property!\n" );
791 AddEmbeddedObject( xResult
, rName
);
793 catch (const uno::Exception
&)
799 xResult
->close( sal_True
);
801 catch (const uno::Exception
&)
804 xResult
= uno::Reference
< embed::XEmbeddedObject
>();
810 SAL_WARN_IF( !xResult
.is(), "comphelper.container", "Can not copy embedded object that has no persistence!\n" );
814 // the object is successfully copied, try to copy graphical replacement
815 if ( !aOrigName
.isEmpty() )
816 TryToCopyGraphReplacement( rSrc
, aOrigName
, rName
);
818 // the object might need the size to be set
821 if ( xResult
->getStatus( embed::Aspects::MSOLE_CONTENT
) & embed::EmbedMisc::EMBED_NEEDSSIZEONLOAD
)
822 xResult
->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT
,
823 xObj
->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT
) );
825 catch (const uno::Exception
&)
833 bool EmbeddedObjectContainer::MoveEmbeddedObject( EmbeddedObjectContainer
& rSrc
, const uno::Reference
< embed::XEmbeddedObject
>& xObj
, OUString
& rName
)
835 // get the object name before(!) it is assigned to a new storage
836 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
839 aName
= xPersist
->getEntryName();
841 // now move the object to the new container; the returned name is the new persist name in this container
846 bRet
= InsertEmbeddedObject( xObj
, rName
);
848 TryToCopyGraphReplacement( rSrc
, aName
, rName
);
850 catch (const uno::Exception
&)
852 SAL_WARN( "comphelper.container", "Failed to insert embedded object into storage!" );
858 // now remove the object from the former container
860 EmbeddedObjectContainerNameMap::iterator aIt
= rSrc
.pImpl
->maObjectContainer
.begin();
861 while ( aIt
!= rSrc
.pImpl
->maObjectContainer
.end() )
863 if ( (*aIt
).second
== xObj
)
865 rSrc
.pImpl
->maObjectContainer
.erase( aIt
);
873 SAL_WARN_IF( !bRet
, "comphelper.container", "Object not found for removal!" );
876 // now it's time to remove the storage from the container storage
880 rSrc
.pImpl
->mxStorage
->removeElement( aName
);
882 catch (const uno::Exception
&)
884 SAL_WARN( "comphelper.container", "Failed to remove object from storage!" );
889 // rSrc.RemoveGraphicStream( aName );
895 // #i119941, bKeepToTempStorage: use to specify whether store the removed object to temporary storage+
896 bool EmbeddedObjectContainer::RemoveEmbeddedObject( const OUString
& rName
, bool bClose
, bool bKeepToTempStorage
)
898 uno::Reference
< embed::XEmbeddedObject
> xObj
= GetEmbeddedObject( rName
);
900 //return RemoveEmbeddedObject( xObj, bClose );
901 return RemoveEmbeddedObject( xObj
, bClose
, bKeepToTempStorage
);
906 bool EmbeddedObjectContainer::MoveEmbeddedObject( const OUString
& rName
, EmbeddedObjectContainer
& rCnt
)
909 EmbeddedObjectContainerNameMap::iterator aIt2
= rCnt
.pImpl
->maObjectContainer
.find( rName
);
910 OSL_ENSURE( aIt2
== rCnt
.pImpl
->maObjectContainer
.end(), "Object does already exist in target container!" );
912 if ( aIt2
!= rCnt
.pImpl
->maObjectContainer
.end() )
915 uno::Reference
< embed::XEmbeddedObject
> xObj
;
916 EmbeddedObjectContainerNameMap::iterator aIt
= pImpl
->maObjectContainer
.find( rName
);
917 if ( aIt
!= pImpl
->maObjectContainer
.end() )
919 xObj
= (*aIt
).second
;
925 OUString
aName( rName
);
926 rCnt
.InsertEmbeddedObject( xObj
, aName
);
927 pImpl
->maObjectContainer
.erase( aIt
);
928 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
930 pImpl
->mxStorage
->removeElement( rName
);
934 // copy storages; object *must* have persistence!
935 uno::Reference
< embed::XStorage
> xOld
= pImpl
->mxStorage
->openStorageElement( rName
, embed::ElementModes::READ
);
936 uno::Reference
< embed::XStorage
> xNew
= rCnt
.pImpl
->mxStorage
->openStorageElement( rName
, embed::ElementModes::READWRITE
);
937 xOld
->copyToStorage( xNew
);
940 rCnt
.TryToCopyGraphReplacement( *this, rName
, rName
);
941 // RemoveGraphicStream( rName );
945 catch (const uno::Exception
&)
947 SAL_WARN( "comphelper.container", "Could not move object!");
953 SAL_WARN( "comphelper.container", "Unknown object!");
957 //sal_Bool EmbeddedObjectContainer::RemoveEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj, sal_Bool bClose )
958 // #i119941, bKeepToTempStorage: use to specify whether store the removed object to temporary storage+
959 bool EmbeddedObjectContainer::RemoveEmbeddedObject( const uno::Reference
< embed::XEmbeddedObject
>& xObj
, bool bClose
, bool bKeepToTempStorage
)
961 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
964 aName
= xPersist
->getEntryName();
966 #if OSL_DEBUG_LEVEL > 1
967 uno::Reference
< container::XNameAccess
> xAccess( pImpl
->mxStorage
, uno::UNO_QUERY
);
968 uno::Reference
< embed::XLinkageSupport
> xLink( xPersist
, uno::UNO_QUERY
);
969 sal_Bool bIsNotEmbedded
= !xPersist
.is() || ( xLink
.is() && xLink
->isLink() );
971 // if the object has a persistence and the object is not a link than it must have persistence entry in the storage
972 OSL_ENSURE( bIsNotEmbedded
|| xAccess
->hasByName(aName
), "Removing element not present in storage!" );
975 // try to close it if permitted
978 uno::Reference
< ::util::XCloseable
> xClose( xObj
, uno::UNO_QUERY
);
981 xClose
->close( sal_True
);
983 catch (const util::CloseVetoException
&)
991 // somebody still needs the object, so we must assign a temporary persistence
994 // if ( xPersist.is() )
995 if ( xPersist
.is() && bKeepToTempStorage
) // #i119941
998 //TODO/LATER: needs storage handling! Why not letting the object do it?!
999 if ( !pImpl->mxTempStorage.is() )
1000 pImpl->mxTempStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
1001 uno::Sequence < beans::PropertyValue > aSeq;
1003 OUString aTmpPersistName = "Object ";
1004 aTmpPersistName += OUString::valueOf( (sal_Int32) pImpl->maTempObjectContainer.size() );
1006 xPersist->storeAsEntry( pImpl->mxTempStorage, aTmpPersistName, aSeq, aSeq );
1007 xPersist->saveCompleted( sal_True );
1009 pImpl->maTempObjectContainer[ aTmpPersistName ] = uno::Reference < embed::XEmbeddedObject >();
1012 if ( !pImpl
->mpTempObjectContainer
)
1014 pImpl
->mpTempObjectContainer
= new EmbeddedObjectContainer();
1017 // TODO/LATER: in future probably the temporary container will have two storages ( of two formats )
1018 // the media type will be provided with object insertion
1019 OUString aOrigStorMediaType
;
1020 uno::Reference
< beans::XPropertySet
> xStorProps( pImpl
->mxStorage
, uno::UNO_QUERY_THROW
);
1021 static const OUString
s_sMediaType("MediaType");
1022 xStorProps
->getPropertyValue( s_sMediaType
) >>= aOrigStorMediaType
;
1024 SAL_WARN_IF( aOrigStorMediaType
.isEmpty(), "comphelper.container", "No valuable media type in the storage!\n" );
1026 uno::Reference
< beans::XPropertySet
> xTargetStorProps(
1027 pImpl
->mpTempObjectContainer
->pImpl
->mxStorage
,
1028 uno::UNO_QUERY_THROW
);
1029 xTargetStorProps
->setPropertyValue( s_sMediaType
,uno::makeAny( aOrigStorMediaType
) );
1031 catch (const uno::Exception
&)
1033 SAL_WARN( "comphelper.container", "Can not set the new media type to a storage!\n" );
1037 OUString aTempName
, aMediaType
;
1038 pImpl
->mpTempObjectContainer
->InsertEmbeddedObject( xObj
, aTempName
);
1040 uno::Reference
< io::XInputStream
> xStream
= GetGraphicStream( xObj
, &aMediaType
);
1042 pImpl
->mpTempObjectContainer
->InsertGraphicStream( xStream
, aTempName
, aMediaType
);
1044 // object is stored, so at least it can be set to loaded state
1045 xObj
->changeState( embed::EmbedStates::LOADED
);
1048 // objects without persistence need to stay in running state if they shall not be closed
1049 xObj
->changeState( embed::EmbedStates::RUNNING
);
1051 catch (const uno::Exception
&)
1057 bool bFound
= false;
1058 EmbeddedObjectContainerNameMap::iterator aIt
= pImpl
->maObjectContainer
.begin();
1059 while ( aIt
!= pImpl
->maObjectContainer
.end() )
1061 if ( (*aIt
).second
== xObj
)
1063 pImpl
->maObjectContainer
.erase( aIt
);
1065 uno::Reference
< container::XChild
> xChild( xObj
, uno::UNO_QUERY
);
1067 xChild
->setParent( uno::Reference
< uno::XInterface
>() );
1074 SAL_WARN_IF( !bFound
,"comphelper.container", "Object not found for removal!" );
1076 if ( xPersist
.is() && bKeepToTempStorage
) // #i119941#
1078 // remove replacement image (if there is one)
1079 RemoveGraphicStream( aName
);
1081 // now it's time to remove the storage from the container storage
1084 #if OSL_DEBUG_LEVEL > 1
1085 // if the object has a persistence and the object is not a link than it must have persistence entry in storage
1086 OSL_ENSURE( bIsNotEmbedded
|| pImpl
->mxStorage
->hasByName( aName
), "The object has no persistence entry in the storage!" );
1088 if ( xPersist
.is() && pImpl
->mxStorage
->hasByName( aName
) )
1089 pImpl
->mxStorage
->removeElement( aName
);
1091 catch (const uno::Exception
&)
1093 SAL_WARN( "comphelper.container", "Failed to remove object from storage!" );
1101 bool EmbeddedObjectContainer::CloseEmbeddedObject( const uno::Reference
< embed::XEmbeddedObject
>& xObj
)
1103 // disconnect the object from the container and close it if possible
1105 bool bFound
= false;
1106 EmbeddedObjectContainerNameMap::iterator aIt
= pImpl
->maObjectContainer
.begin();
1107 while ( aIt
!= pImpl
->maObjectContainer
.end() )
1109 if ( (*aIt
).second
== xObj
)
1111 pImpl
->maObjectContainer
.erase( aIt
);
1121 uno::Reference
< ::util::XCloseable
> xClose( xObj
, uno::UNO_QUERY
);
1124 xClose
->close( sal_True
);
1126 catch (const uno::Exception
&)
1128 // it is no problem if the object is already closed
1129 // TODO/LATER: what if the object can not be closed?
1136 uno::Reference
< io::XInputStream
> EmbeddedObjectContainer::GetGraphicStream( const OUString
& aName
, OUString
* pMediaType
)
1138 uno::Reference
< io::XInputStream
> xStream
;
1140 SAL_WARN_IF( aName
.isEmpty(), "comphelper.container", "Retrieving graphic for unknown object!" );
1141 if ( !aName
.isEmpty() )
1145 uno::Reference
< embed::XStorage
> xReplacements
= pImpl
->GetReplacements();
1146 uno::Reference
< io::XStream
> xGraphicStream
= xReplacements
->openStreamElement( aName
, embed::ElementModes::READ
);
1147 xStream
= xGraphicStream
->getInputStream();
1150 uno::Reference
< beans::XPropertySet
> xSet( xStream
, uno::UNO_QUERY
);
1153 uno::Any aAny
= xSet
->getPropertyValue("MediaType");
1154 aAny
>>= *pMediaType
;
1158 catch (uno::Exception
const& e
)
1160 SAL_INFO("comphelper.container",
1161 "EmbeddedObjectContainer::GetGraphicStream(): exception: " << e
.Message
);
1168 uno::Reference
< io::XInputStream
> EmbeddedObjectContainer::GetGraphicStream( const ::com::sun::star::uno::Reference
< ::com::sun::star::embed::XEmbeddedObject
>& xObj
, OUString
* pMediaType
)
1170 // try to load it from the container storage
1171 return GetGraphicStream( GetEmbeddedObjectName( xObj
), pMediaType
);
1174 uno::Reference
< io::XInputStream
> EmbeddedObjectContainer::GetObjectStream( const OUString
& aName
, OUString
* pMediaType
)
1176 uno::Reference
< io::XInputStream
> xInputStream
;
1178 SAL_WARN_IF( aName
.isEmpty(), "comphelper.container", "Retrieving stream for unknown object!" );
1179 if ( !aName
.isEmpty() )
1183 uno::Reference
< io::XStream
> xStream
= pImpl
->mxStorage
->cloneStreamElement( aName
); //get a readonly clone
1184 xInputStream
= xStream
->getInputStream();
1187 uno::Reference
< beans::XPropertySet
> xSet( xInputStream
, uno::UNO_QUERY
);
1190 uno::Any aAny
= xSet
->getPropertyValue("MediaType");
1191 aAny
>>= *pMediaType
;
1195 catch (const uno::Exception
&)
1200 return xInputStream
;
1203 uno::Reference
< io::XInputStream
> EmbeddedObjectContainer::GetObjectStream( const uno::Reference
< embed::XEmbeddedObject
>& xObj
, OUString
* pMediaType
)
1205 // try to load it from the container storage
1206 return GetObjectStream( GetEmbeddedObjectName( xObj
), pMediaType
);
1209 bool EmbeddedObjectContainer::InsertGraphicStream( const com::sun::star::uno::Reference
< com::sun::star::io::XInputStream
>& rStream
, const OUString
& rObjectName
, const OUString
& rMediaType
)
1213 uno::Reference
< embed::XStorage
> xReplacements
= pImpl
->GetReplacements();
1215 // store it into the subfolder
1216 uno::Reference
< io::XOutputStream
> xOutStream
;
1217 uno::Reference
< io::XStream
> xGraphicStream
= xReplacements
->openStreamElement( rObjectName
,
1218 embed::ElementModes::READWRITE
| embed::ElementModes::TRUNCATE
);
1219 xOutStream
= xGraphicStream
->getOutputStream();
1220 ::comphelper::OStorageHelper::CopyInputToOutput( rStream
, xOutStream
);
1221 xOutStream
->flush();
1223 uno::Reference
< beans::XPropertySet
> xPropSet( xGraphicStream
, uno::UNO_QUERY
);
1224 if ( !xPropSet
.is() )
1225 throw uno::RuntimeException();
1227 xPropSet
->setPropertyValue("UseCommonStoragePasswordEncryption",
1228 uno::makeAny( true ) );
1230 aAny
<<= rMediaType
;
1231 xPropSet
->setPropertyValue("MediaType", aAny
);
1233 xPropSet
->setPropertyValue("Compressed",
1234 uno::makeAny( true ) );
1236 catch (const uno::Exception
&)
1244 bool EmbeddedObjectContainer::InsertGraphicStreamDirectly( const com::sun::star::uno::Reference
< com::sun::star::io::XInputStream
>& rStream
, const OUString
& rObjectName
, const OUString
& rMediaType
)
1248 uno::Reference
< embed::XStorage
> xReplacement
= pImpl
->GetReplacements();
1249 uno::Reference
< embed::XOptimizedStorage
> xOptRepl( xReplacement
, uno::UNO_QUERY_THROW
);
1251 // store it into the subfolder
1252 uno::Sequence
< beans::PropertyValue
> aProps( 3 );
1253 aProps
[0].Name
= "MediaType";
1254 aProps
[0].Value
<<= rMediaType
;
1255 aProps
[1].Name
= "UseCommonStoragePasswordEncryption";
1256 aProps
[1].Value
<<= true;
1257 aProps
[2].Name
= "Compressed";
1258 aProps
[2].Value
<<= true;
1260 if ( xReplacement
->hasByName( rObjectName
) )
1261 xReplacement
->removeElement( rObjectName
);
1263 xOptRepl
->insertStreamElementDirect( rObjectName
, rStream
, aProps
);
1265 catch (const uno::Exception
&)
1274 bool EmbeddedObjectContainer::RemoveGraphicStream( const OUString
& rObjectName
)
1278 uno::Reference
< embed::XStorage
> xReplacements
= pImpl
->GetReplacements();
1279 xReplacements
->removeElement( rObjectName
);
1281 catch (const uno::Exception
&)
1289 void InsertStreamIntoPicturesStorage_Impl( const uno::Reference
< embed::XStorage
>& xDocStor
,
1290 const uno::Reference
< io::XInputStream
>& xInStream
,
1291 const OUString
& aStreamName
)
1293 OSL_ENSURE( !aStreamName
.isEmpty() && xInStream
.is() && xDocStor
.is(), "Misuse of the method!\n" );
1297 uno::Reference
< embed::XStorage
> xPictures
= xDocStor
->openStorageElement(
1298 OUString( "Pictures" ),
1299 embed::ElementModes::READWRITE
);
1300 uno::Reference
< io::XStream
> xObjReplStr
= xPictures
->openStreamElement(
1302 embed::ElementModes::READWRITE
| embed::ElementModes::TRUNCATE
);
1303 uno::Reference
< io::XOutputStream
> xOutStream(
1304 xObjReplStr
->getInputStream(), uno::UNO_QUERY_THROW
);
1306 ::comphelper::OStorageHelper::CopyInputToOutput( xInStream
, xOutStream
);
1307 xOutStream
->closeOutput();
1309 uno::Reference
< embed::XTransactedObject
> xTransact( xPictures
, uno::UNO_QUERY
);
1310 if ( xTransact
.is() )
1311 xTransact
->commit();
1313 catch (const uno::Exception
&)
1315 SAL_WARN( "comphelper.container", "The pictures storage is not available!\n" );
1321 bool EmbeddedObjectContainer::StoreAsChildren(bool _bOasisFormat
,bool _bCreateEmbedded
,const uno::Reference
< embed::XStorage
>& _xStorage
)
1323 bool bResult
= false;
1326 comphelper::EmbeddedObjectContainer
aCnt( _xStorage
);
1327 const uno::Sequence
< OUString
> aNames
= GetObjectNames();
1328 const OUString
* pIter
= aNames
.getConstArray();
1329 const OUString
* pEnd
= pIter
+ aNames
.getLength();
1330 for(;pIter
!= pEnd
;++pIter
)
1332 uno::Reference
< embed::XEmbeddedObject
> xObj
= GetEmbeddedObject( *pIter
);
1333 SAL_WARN_IF( !xObj
.is(), "comphelper.container", "An empty entry in the embedded objects list!\n" );
1336 bool bSwitchBackToLoaded
= false;
1337 uno::Reference
< embed::XLinkageSupport
> xLink( xObj
, uno::UNO_QUERY
);
1339 uno::Reference
< io::XInputStream
> xStream
;
1340 OUString aMediaType
;
1342 sal_Int32 nCurState
= xObj
->getCurrentState();
1343 if ( nCurState
== embed::EmbedStates::LOADED
|| nCurState
== embed::EmbedStates::RUNNING
)
1345 // means that the object is not active
1346 // copy replacement image from old to new container
1347 xStream
= GetGraphicStream( xObj
, &aMediaType
);
1350 if ( !xStream
.is() && getUserAllowsLinkUpdate() )
1352 // the image must be regenerated
1353 // TODO/LATER: another aspect could be used
1354 if ( xObj
->getCurrentState() == embed::EmbedStates::LOADED
)
1355 bSwitchBackToLoaded
= true;
1357 xStream
= GetGraphicReplacementStream(
1358 embed::Aspects::MSOLE_CONTENT
,
1363 if ( _bOasisFormat
|| (xLink
.is() && xLink
->isLink()) )
1367 if ( _bOasisFormat
)
1369 // if it is an embedded object or the optimized inserting fails the normal inserting should be done
1370 if ( _bCreateEmbedded
1371 || !aCnt
.InsertGraphicStreamDirectly( xStream
, *pIter
, aMediaType
) )
1372 aCnt
.InsertGraphicStream( xStream
, *pIter
, aMediaType
);
1376 // it is a linked object exported into SO7 format
1377 InsertStreamIntoPicturesStorage_Impl( _xStorage
, xStream
, *pIter
);
1382 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
1383 if ( xPersist
.is() )
1385 uno::Sequence
< beans::PropertyValue
> aArgs( _bOasisFormat
? 2 : 3 );
1386 aArgs
[0].Name
= "StoreVisualReplacement";
1387 aArgs
[0].Value
<<= !_bOasisFormat
;
1389 // if it is an embedded object or the optimized inserting fails the normal inserting should be done
1390 aArgs
[1].Name
= "CanTryOptimization";
1391 aArgs
[1].Value
<<= !_bCreateEmbedded
;
1392 if ( !_bOasisFormat
)
1394 // if object has no cached replacement it will use this one
1395 aArgs
[2].Name
= "VisualReplacement";
1396 aArgs
[2].Value
<<= xStream
;
1401 xPersist
->storeAsEntry( _xStorage
, xPersist
->getEntryName(), uno::Sequence
< beans::PropertyValue
>(), aArgs
);
1403 catch (const embed::WrongStateException
&)
1405 SAL_WARN("comphelper.container", "failed to store '" << *pIter
<< "'");
1409 if ( bSwitchBackToLoaded
)
1410 // switch back to loaded state; that way we have a minimum cache confusion
1411 xObj
->changeState( embed::EmbedStates::LOADED
);
1415 bResult
= aCnt
.CommitImageSubStorage();
1418 catch (const uno::Exception
& e
)
1420 // TODO/LATER: error handling
1422 SAL_WARN("comphelper.container", "failed. Message: " << e
.Message
);
1425 // the old SO6 format does not store graphical replacements
1426 if ( !_bOasisFormat
&& bResult
)
1430 // the substorage still can not be locked by the embedded object container
1431 OUString
aObjReplElement( "ObjectReplacements" );
1432 if ( _xStorage
->hasByName( aObjReplElement
) && _xStorage
->isStorageElement( aObjReplElement
) )
1433 _xStorage
->removeElement( aObjReplElement
);
1435 catch (const uno::Exception
&)
1437 // TODO/LATER: error handling;
1444 bool EmbeddedObjectContainer::StoreChildren(bool _bOasisFormat
,bool _bObjectsOnly
)
1446 bool bResult
= true;
1447 const uno::Sequence
< OUString
> aNames
= GetObjectNames();
1448 const OUString
* pIter
= aNames
.getConstArray();
1449 const OUString
* pEnd
= pIter
+ aNames
.getLength();
1450 for(;pIter
!= pEnd
;++pIter
)
1452 uno::Reference
< embed::XEmbeddedObject
> xObj
= GetEmbeddedObject( *pIter
);
1453 SAL_WARN_IF( !xObj
.is(), "comphelper.container", "An empty entry in the embedded objects list!\n" );
1456 sal_Int32 nCurState
= xObj
->getCurrentState();
1457 if ( _bOasisFormat
&& nCurState
!= embed::EmbedStates::LOADED
&& nCurState
!= embed::EmbedStates::RUNNING
)
1459 // means that the object is active
1460 // the image must be regenerated
1461 OUString aMediaType
;
1463 // TODO/LATER: another aspect could be used
1464 uno::Reference
< io::XInputStream
> xStream
=
1465 GetGraphicReplacementStream(
1466 embed::Aspects::MSOLE_CONTENT
,
1471 if ( !InsertGraphicStreamDirectly( xStream
, *pIter
, aMediaType
) )
1472 InsertGraphicStream( xStream
, *pIter
, aMediaType
);
1476 // TODO/LATER: currently the object by default does not cache replacement image
1477 // that means that if somebody loads SO7 document and store its objects using
1478 // this method the images might be lost.
1479 // Currently this method is only used on storing to alien formats, that means
1480 // that SO7 documents storing does not use it, and all other filters are
1481 // based on OASIS format. But if it changes the method must be fixed. The fix
1482 // must be done only on demand since it can affect performance.
1484 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
1485 if ( xPersist
.is() )
1489 //TODO/LATER: only storing if changed!
1490 //xPersist->storeOwn(); //commented, i120168
1492 // begin:all charts will be persited as xml format on disk when saving, which is time consuming.
1493 // '_bObjectsOnly' mean we are storing to alien formats.
1494 // 'isStorageElement' mean current object is NOT an MS OLE format. (may also include in future), i120168
1495 if (_bObjectsOnly
&& (nCurState
== embed::EmbedStates::LOADED
|| nCurState
== embed::EmbedStates::RUNNING
)
1496 && (pImpl
->mxStorage
->isStorageElement( *pIter
) ))
1498 uno::Reference
< util::XModifiable
> xModifiable( xObj
->getComponent(), uno::UNO_QUERY
);
1499 if ( xModifiable
.is() && xModifiable
->isModified())
1501 xPersist
->storeOwn();
1505 //do nothing. Embedded model is not modified, no need to persist.
1508 else //the embedded object is in active status, always store back it.
1510 xPersist
->storeOwn();
1514 catch (const uno::Exception
&)
1516 // TODO/LATER: error handling
1522 if ( !_bOasisFormat
&& !_bObjectsOnly
)
1524 // copy replacement images for linked objects
1527 uno::Reference
< embed::XLinkageSupport
> xLink( xObj
, uno::UNO_QUERY
);
1528 if ( xLink
.is() && xLink
->isLink() )
1530 OUString aMediaType
;
1531 uno::Reference
< io::XInputStream
> xInStream
= GetGraphicStream( xObj
, &aMediaType
);
1532 if ( xInStream
.is() )
1533 InsertStreamIntoPicturesStorage_Impl( pImpl
->mxStorage
, xInStream
, *pIter
);
1536 catch (const uno::Exception
&)
1543 if ( bResult
&& _bOasisFormat
)
1544 bResult
= CommitImageSubStorage();
1546 if ( bResult
&& !_bObjectsOnly
)
1550 ReleaseImageSubStorage();
1551 OUString
aObjReplElement( "ObjectReplacements" );
1552 if ( !_bOasisFormat
&& pImpl
->mxStorage
->hasByName( aObjReplElement
) && pImpl
->mxStorage
->isStorageElement( aObjReplElement
) )
1553 pImpl
->mxStorage
->removeElement( aObjReplElement
);
1555 catch (const uno::Exception
&)
1557 // TODO/LATER: error handling
1564 uno::Reference
< io::XInputStream
> EmbeddedObjectContainer::GetGraphicReplacementStream(
1565 sal_Int64 nViewAspect
,
1566 const uno::Reference
< embed::XEmbeddedObject
>& xObj
,
1567 OUString
* pMediaType
)
1569 uno::Reference
< io::XInputStream
> xInStream
;
1574 // retrieving of the visual representation can switch object to running state
1575 embed::VisualRepresentation aRep
= xObj
->getPreferredVisualRepresentation( nViewAspect
);
1577 *pMediaType
= aRep
.Flavor
.MimeType
;
1579 uno::Sequence
< sal_Int8
> aSeq
;
1581 xInStream
= new ::comphelper::SequenceInputStream( aSeq
);
1583 catch (const uno::Exception
&)
1591 bool EmbeddedObjectContainer::SetPersistentEntries(const uno::Reference
< embed::XStorage
>& _xStorage
,bool _bClearModifedFlag
)
1593 bool bError
= false;
1594 const uno::Sequence
< OUString
> aNames
= GetObjectNames();
1595 const OUString
* pIter
= aNames
.getConstArray();
1596 const OUString
* pEnd
= pIter
+ aNames
.getLength();
1597 for(;pIter
!= pEnd
;++pIter
)
1599 uno::Reference
< embed::XEmbeddedObject
> xObj
= GetEmbeddedObject( *pIter
);
1600 SAL_WARN_IF( !xObj
.is(), "comphelper.container", "An empty entry in the embedded objects list!\n" );
1603 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
1604 if ( xPersist
.is() )
1608 xPersist
->setPersistentEntry( _xStorage
,
1610 embed::EntryInitModes::NO_INIT
,
1611 uno::Sequence
< beans::PropertyValue
>(),
1612 uno::Sequence
< beans::PropertyValue
>() );
1615 catch (const uno::Exception
&)
1617 // TODO/LATER: error handling
1622 if ( _bClearModifedFlag
)
1624 // if this method is used as part of SaveCompleted the object must stay unmodified after execution
1627 uno::Reference
< util::XModifiable
> xModif( xObj
->getComponent(), uno::UNO_QUERY_THROW
);
1628 if ( xModif
->isModified() )
1629 xModif
->setModified( sal_False
);
1631 catch (const uno::Exception
&)
1640 bool EmbeddedObjectContainer::getUserAllowsLinkUpdate() const
1642 return pImpl
->mbUserAllowsLinkUpdate
;
1645 void EmbeddedObjectContainer::setUserAllowsLinkUpdate(bool bNew
)
1647 if(pImpl
->mbUserAllowsLinkUpdate
!= bNew
)
1649 pImpl
->mbUserAllowsLinkUpdate
= bNew
;
1655 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */