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