bump product version to 5.0.4.1
[LibreOffice.git] / comphelper / source / container / embeddedobjectcontainer.cxx
blob10a75516e868d2163364c620b225d0a35ad4bd2f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
47 #include <algorithm>
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;
58 struct EmbedImpl
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;
69 /// bitfield
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() )
80 try
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);
145 if ( xSet.is() )
147 // get the open mode from the parent storage
148 sal_Int32 nMode = 0;
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 );
156 xTransact->commit();
159 catch (const uno::Exception&)
161 return false;
165 return true;
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;
194 delete pImpl;
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 );
203 if ( xClose.is() )
207 xClose->close( sal_True );
209 catch (const uno::Exception&)
214 ++aIt;
218 OUString EmbeddedObjectContainer::CreateUniqueObjectName()
220 OUString aPersistName("Object ");
221 OUString aStr;
222 sal_Int32 i=1;
225 aStr = aPersistName;
226 aStr += OUString::number( i++ );
228 while( HasEmbeddedObject( aStr ) );
229 // TODO/LATER: should we consider deleted objects?
231 return aStr;
234 uno::Sequence < OUString > EmbeddedObjectContainer::GetObjectNames()
236 uno::Sequence < OUString > aSeq( pImpl->maObjectContainer.size() );
237 EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin();
238 sal_Int32 nIdx=0;
239 while ( aIt != pImpl->maObjectContainer.end() )
240 aSeq[nIdx++] = (*aIt++).first;
241 return aSeq;
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);
257 else
258 return true;
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 )
267 return true;
268 else
269 ++aIt;
272 return false;
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 )
290 return (*aIt).first;
291 else
292 ++aIt;
295 SAL_WARN( "comphelper.container", "Unknown object!" );
296 return OUString();
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)
313 (void)*pIter;
315 OSL_ENSURE( aIt != pImpl->maObjectContainer.end() || xAccess->hasByName(rName), "Could not return object!" );
316 #endif
318 // check if object was already created
319 if ( aIt != pImpl->maObjectContainer.end() )
320 xObj = (*aIt).second;
321 else
322 xObj = Get_Impl( rName, uno::Reference < embed::XEmbeddedObject >() );
324 return xObj;
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;
335 if ( xSet.is() )
337 // get the open mode from the parent storage
338 sal_Int32 nMode = 0;
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();
350 if ( xCopy.is() )
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);
371 return xObj;
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);
406 return xObj;
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!" );
424 #endif
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;
444 OUString aMediaType;
445 uno::Reference < io::XInputStream > xStream = pImpl->mpTempObjectContainer->GetGraphicStream( xObj, &aMediaType );
446 if ( xStream.is() )
448 InsertGraphicStream( xStream, rName, aMediaType );
449 xStream = 0;
450 pImpl->mpTempObjectContainer->RemoveGraphicStream( aTempName );
453 // remove object from storage of temporary container
454 uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
455 if ( xPersist.is() )
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 );
468 break;
470 else
471 ++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!");
488 #endif
490 // insert objects' storage into the container storage (if object has one)
493 if ( xPersist.is() )
495 uno::Sequence < beans::PropertyValue > aSeq;
496 if ( bCopy )
498 auto aObjArgs(::comphelper::InitPropertySequence({
499 { "SourceShellID", uno::makeAny(rSrcShellID) },
500 { "DestinationShellID", uno::makeAny(rDestShellID) }
501 }));
502 xPersist->storeToEntry(pImpl->mxStorage, rName, aSeq, aObjArgs);
504 else
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
517 return false;
520 return true;
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()))
528 // remember object
529 AddEmbeddedObject( xObj, rName );
530 return true;
532 else
533 return false;
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
549 bIsStorage = true;
551 uno::Reference < embed::XStorage > xNewStore = pImpl->mxStorage->openStorageElement( rNewName, embed::ElementModes::READWRITE );
552 xStore->copyToStorage( xNewStore );
554 catch (const uno::Exception&)
556 if ( bIsStorage )
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 );
585 if ( !xRet.is() )
586 // no object could be created, so withdraw insertion
587 pImpl->mxStorage->removeElement( rNewName );
589 catch (const uno::Exception&)
593 return xRet;
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!
616 if ( xPersist.is())
617 xPersist->storeOwn();
619 AddEmbeddedObject( xObj, rNewName );
621 catch (const uno::Exception&)
625 return xObj;
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!
649 if ( xPersist.is())
650 xPersist->storeOwn();
652 AddEmbeddedObject( xObj, rNewName );
654 catch (uno::Exception const& e)
656 SAL_WARN("comphelper", "EmbeddedObjectContainer::InsertEmbeddedLink: "
657 "exception caught: " << e.Message);
660 return xObj;
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() )
671 OUString aMediaType;
672 uno::Reference < io::XInputStream > xGrStream = rSrc.GetGraphicStream( aOrigName, &aMediaType );
673 if ( xGrStream.is() )
674 bResult = InsertGraphicStream( xGrStream, aTargetName, aMediaType );
677 return bResult;
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
688 OUString aOrigName;
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);
705 if ( !xResult.is() )
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(
731 pImpl->mxStorage,
732 rName,
733 aMediaDescr,
734 aObjDescr ),
735 uno::UNO_QUERY_THROW );
737 else
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(
755 xObj->getClassID(),
756 xObj->getClassName(),
757 pImpl->mxStorage,
758 rName,
759 aObjDescr ),
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" );
790 if ( xResult.is() )
791 AddEmbeddedObject( xResult, rName );
793 catch (const uno::Exception&)
795 if ( xResult.is() )
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" );
812 if ( xResult.is() )
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&)
830 return xResult;
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 );
837 OUString aName;
838 if ( xPersist.is() )
839 aName = xPersist->getEntryName();
841 // now move the object to the new container; the returned name is the new persist name in this container
842 bool bRet;
846 bRet = InsertEmbeddedObject( xObj, rName );
847 if ( bRet )
848 TryToCopyGraphReplacement( rSrc, aName, rName );
850 catch (const uno::Exception&)
852 SAL_WARN( "comphelper.container", "Failed to insert embedded object into storage!" );
853 bRet = false;
856 if ( bRet )
858 // now remove the object from the former container
859 bRet = false;
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 );
866 bRet = true;
867 break;
870 ++aIt;
873 SAL_WARN_IF( !bRet, "comphelper.container", "Object not found for removal!" );
874 if ( xPersist.is() )
876 // now it's time to remove the storage from the container storage
879 if ( xPersist.is() )
880 rSrc.pImpl->mxStorage->removeElement( aName );
882 catch (const uno::Exception&)
884 SAL_WARN( "comphelper.container", "Failed to remove object from storage!" );
885 bRet = false;
889 // rSrc.RemoveGraphicStream( aName );
892 return bRet;
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 );
899 if ( xObj.is() )
900 //return RemoveEmbeddedObject( xObj, bClose );
901 return RemoveEmbeddedObject( xObj, bClose, bKeepToTempStorage );
902 else
903 return false;
906 bool EmbeddedObjectContainer::MoveEmbeddedObject( const OUString& rName, EmbeddedObjectContainer& rCnt )
908 // find object entry
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() )
913 return false;
915 uno::Reference < embed::XEmbeddedObject > xObj;
916 EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.find( rName );
917 if ( aIt != pImpl->maObjectContainer.end() )
919 xObj = (*aIt).second;
922 if ( xObj.is() )
924 // move object
925 OUString aName( rName );
926 rCnt.InsertEmbeddedObject( xObj, aName );
927 pImpl->maObjectContainer.erase( aIt );
928 uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
929 if ( xPersist.is() )
930 pImpl->mxStorage->removeElement( rName );
932 else
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 );
943 return true;
945 catch (const uno::Exception&)
947 SAL_WARN( "comphelper.container", "Could not move object!");
948 return false;
952 else
953 SAL_WARN( "comphelper.container", "Unknown object!");
954 return false;
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 );
962 OUString aName;
963 if ( xPersist.is() )
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!" );
973 #endif
975 // try to close it if permitted
976 if ( bClose )
978 uno::Reference < ::util::XCloseable > xClose( xObj, uno::UNO_QUERY );
981 xClose->close( sal_True );
983 catch (const util::CloseVetoException&)
985 bClose = false;
989 if ( !bClose )
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 );
1041 if ( xStream.is() )
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 );
1047 else
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&)
1053 return false;
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 );
1064 bFound = true;
1065 uno::Reference < container::XChild > xChild( xObj, uno::UNO_QUERY );
1066 if ( xChild.is() )
1067 xChild->setParent( uno::Reference < uno::XInterface >() );
1068 break;
1071 ++aIt;
1074 SAL_WARN_IF( !bFound,"comphelper.container", "Object not found for removal!" );
1075 (void)bFound;
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!" );
1087 #endif
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!" );
1094 return false;
1098 return true;
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 );
1112 bFound = true;
1113 break;
1116 ++aIt;
1119 if ( bFound )
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?
1133 return bFound;
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();
1148 if ( pMediaType )
1150 uno::Reference < beans::XPropertySet > xSet( xStream, uno::UNO_QUERY );
1151 if ( xSet.is() )
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);
1165 return xStream;
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();
1185 if ( pMediaType )
1187 uno::Reference < beans::XPropertySet > xSet( xInputStream, uno::UNO_QUERY );
1188 if ( xSet.is() )
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 ) );
1229 uno::Any aAny;
1230 aAny <<= rMediaType;
1231 xPropSet->setPropertyValue("MediaType", aAny );
1233 xPropSet->setPropertyValue("Compressed",
1234 uno::makeAny( true ) );
1236 catch (const uno::Exception&)
1238 return false;
1241 return true;
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&)
1267 return false;
1270 return true;
1274 bool EmbeddedObjectContainer::RemoveGraphicStream( const OUString& rObjectName )
1278 uno::Reference < embed::XStorage > xReplacements = pImpl->GetReplacements();
1279 xReplacements->removeElement( rObjectName );
1281 catch (const uno::Exception&)
1283 return false;
1286 return true;
1288 namespace {
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(
1301 aStreamName,
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" );
1334 if ( xObj.is() )
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,
1359 xObj,
1360 &aMediaType );
1363 if ( _bOasisFormat || (xLink.is() && xLink->isLink()) )
1365 if ( xStream.is() )
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 );
1374 else
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
1421 bResult = false;
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;
1438 bResult = false;
1441 return bResult;
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" );
1454 if ( xObj.is() )
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,
1467 xObj,
1468 &aMediaType );
1469 if ( xStream.is() )
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();
1503 else
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();
1512 //end i120168
1514 catch (const uno::Exception&)
1516 // TODO/LATER: error handling
1517 bResult = false;
1518 break;
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
1558 bResult = false;
1561 return bResult;
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;
1570 if ( xObj.is() )
1574 // retrieving of the visual representation can switch object to running state
1575 embed::VisualRepresentation aRep = xObj->getPreferredVisualRepresentation( nViewAspect );
1576 if ( pMediaType )
1577 *pMediaType = aRep.Flavor.MimeType;
1579 uno::Sequence < sal_Int8 > aSeq;
1580 aRep.Data >>= aSeq;
1581 xInStream = new ::comphelper::SequenceInputStream( aSeq );
1583 catch (const uno::Exception&)
1588 return xInStream;
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" );
1601 if ( xObj.is() )
1603 uno::Reference< embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
1604 if ( xPersist.is() )
1608 xPersist->setPersistentEntry( _xStorage,
1609 *pIter,
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
1618 bError = true;
1619 break;
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&)
1637 return bError;
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: */