update credits
[LibreOffice.git] / comphelper / source / container / embeddedobjectcontainer.cxx
blobfb90a0b216e7d827d646f46fec812e1a16342b52
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 <cppuhelper/weakref.hxx>
44 #include <boost/unordered_map.hpp>
45 #include <algorithm>
48 using namespace ::com::sun::star;
50 namespace comphelper
53 struct hashObjectName_Impl
55 size_t operator()(const OUString Str) const
57 return (size_t)Str.hashCode();
61 struct eqObjectName_Impl
63 sal_Bool operator()(const OUString Str1, const OUString Str2) const
65 return ( Str1 == Str2 );
69 typedef boost::unordered_map
71 OUString,
72 ::com::sun::star::uno::Reference < com::sun::star::embed::XEmbeddedObject >,
73 hashObjectName_Impl,
74 eqObjectName_Impl
76 EmbeddedObjectContainerNameMap;
78 struct EmbedImpl
80 // TODO/LATER: remove objects from temp. Container storage when object is disposed
81 EmbeddedObjectContainerNameMap maObjectContainer;
82 uno::Reference < embed::XStorage > mxStorage;
83 EmbeddedObjectContainer* mpTempObjectContainer;
84 uno::Reference < embed::XStorage > mxImageStorage;
85 uno::WeakReference < uno::XInterface > m_xModel;
86 //EmbeddedObjectContainerNameMap maTempObjectContainer;
87 //uno::Reference < embed::XStorage > mxTempStorage;
88 bool bOwnsStorage;
90 const uno::Reference < embed::XStorage >& GetReplacements();
93 const uno::Reference < embed::XStorage >& EmbedImpl::GetReplacements()
95 if ( !mxImageStorage.is() )
97 try
99 mxImageStorage = mxStorage->openStorageElement(
100 OUString("ObjectReplacements"), embed::ElementModes::READWRITE );
102 catch (const uno::Exception&)
104 mxImageStorage = mxStorage->openStorageElement(
105 OUString("ObjectReplacements"), embed::ElementModes::READ );
109 if ( !mxImageStorage.is() )
110 throw io::IOException();
112 return mxImageStorage;
115 EmbeddedObjectContainer::EmbeddedObjectContainer()
117 pImpl = new EmbedImpl;
118 pImpl->mxStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
119 pImpl->bOwnsStorage = true;
120 pImpl->mpTempObjectContainer = 0;
123 EmbeddedObjectContainer::EmbeddedObjectContainer( const uno::Reference < embed::XStorage >& rStor )
125 pImpl = new EmbedImpl;
126 pImpl->mxStorage = rStor;
127 pImpl->bOwnsStorage = false;
128 pImpl->mpTempObjectContainer = 0;
131 EmbeddedObjectContainer::EmbeddedObjectContainer( const uno::Reference < embed::XStorage >& rStor, const uno::Reference < uno::XInterface >& xModel )
133 pImpl = new EmbedImpl;
134 pImpl->mxStorage = rStor;
135 pImpl->bOwnsStorage = false;
136 pImpl->mpTempObjectContainer = 0;
137 pImpl->m_xModel = xModel;
140 void EmbeddedObjectContainer::SwitchPersistence( const uno::Reference < embed::XStorage >& rStor )
142 ReleaseImageSubStorage();
144 if ( pImpl->bOwnsStorage )
145 pImpl->mxStorage->dispose();
147 pImpl->mxStorage = rStor;
148 pImpl->bOwnsStorage = false;
151 sal_Bool EmbeddedObjectContainer::CommitImageSubStorage()
153 if ( pImpl->mxImageStorage.is() )
157 sal_Bool bReadOnlyMode = sal_True;
158 uno::Reference < beans::XPropertySet > xSet(pImpl->mxImageStorage,uno::UNO_QUERY);
159 if ( xSet.is() )
161 // get the open mode from the parent storage
162 sal_Int32 nMode = 0;
163 uno::Any aAny = xSet->getPropertyValue( OUString("OpenMode") );
164 if ( aAny >>= nMode )
165 bReadOnlyMode = !(nMode & embed::ElementModes::WRITE );
166 } // if ( xSet.is() )
167 if ( !bReadOnlyMode )
169 uno::Reference< embed::XTransactedObject > xTransact( pImpl->mxImageStorage, uno::UNO_QUERY_THROW );
170 xTransact->commit();
173 catch (const uno::Exception&)
175 return sal_False;
179 return sal_True;
182 void EmbeddedObjectContainer::ReleaseImageSubStorage()
184 CommitImageSubStorage();
186 if ( pImpl->mxImageStorage.is() )
190 pImpl->mxImageStorage->dispose();
191 pImpl->mxImageStorage = uno::Reference< embed::XStorage >();
193 catch (const uno::Exception&)
195 SAL_WARN( "comphelper.container", "Problems releasing image substorage!\n" );
200 EmbeddedObjectContainer::~EmbeddedObjectContainer()
202 ReleaseImageSubStorage();
204 if ( pImpl->bOwnsStorage )
205 pImpl->mxStorage->dispose();
207 delete pImpl->mpTempObjectContainer;
208 delete pImpl;
211 void EmbeddedObjectContainer::CloseEmbeddedObjects()
213 EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin();
214 while ( aIt != pImpl->maObjectContainer.end() )
216 uno::Reference < util::XCloseable > xClose( (*aIt).second, uno::UNO_QUERY );
217 if ( xClose.is() )
221 xClose->close( sal_True );
223 catch (const uno::Exception&)
228 ++aIt;
232 OUString EmbeddedObjectContainer::CreateUniqueObjectName()
234 OUString aPersistName("Object ");
235 OUString aStr;
236 sal_Int32 i=1;
239 aStr = aPersistName;
240 aStr += OUString::valueOf( i++ );
242 while( HasEmbeddedObject( aStr ) );
243 // TODO/LATER: should we consider deleted objects?
245 return aStr;
248 uno::Sequence < OUString > EmbeddedObjectContainer::GetObjectNames()
250 uno::Sequence < OUString > aSeq( pImpl->maObjectContainer.size() );
251 EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin();
252 sal_Int32 nIdx=0;
253 while ( aIt != pImpl->maObjectContainer.end() )
254 aSeq[nIdx++] = (*aIt++).first;
255 return aSeq;
258 sal_Bool EmbeddedObjectContainer::HasEmbeddedObjects()
260 return pImpl->maObjectContainer.size() != 0;
263 sal_Bool EmbeddedObjectContainer::HasEmbeddedObject( const OUString& rName )
265 EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.find( rName );
266 if ( aIt == pImpl->maObjectContainer.end() )
268 uno::Reference < container::XNameAccess > xAccess( pImpl->mxStorage, uno::UNO_QUERY );
269 return xAccess->hasByName(rName);
271 else
272 return sal_True;
275 sal_Bool EmbeddedObjectContainer::HasEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj )
277 EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin();
278 while ( aIt != pImpl->maObjectContainer.end() )
280 if ( (*aIt).second == xObj )
281 return sal_True;
282 else
283 ++aIt;
286 return sal_False;
289 sal_Bool EmbeddedObjectContainer::HasInstantiatedEmbeddedObject( const OUString& rName )
291 // allows to detect whether the object was already instantiated
292 // currently the filter instantiate it on loading, so this method allows
293 // to avoid objects pointing to the same persistence
294 EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.find( rName );
295 return ( aIt != pImpl->maObjectContainer.end() );
298 OUString EmbeddedObjectContainer::GetEmbeddedObjectName( const ::com::sun::star::uno::Reference < ::com::sun::star::embed::XEmbeddedObject >& xObj )
300 EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin();
301 while ( aIt != pImpl->maObjectContainer.end() )
303 if ( (*aIt).second == xObj )
304 return (*aIt).first;
305 else
306 ++aIt;
309 SAL_WARN( "comphelper.container", "Unknown object!" );
310 return OUString();
313 uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::GetEmbeddedObject( const OUString& rName )
315 SAL_INFO( "comphelper.container", "comphelper (mv76033) comphelper::EmbeddedObjectContainer::GetEmbeddedObject" );
317 SAL_WARN_IF( rName.isEmpty(), "comphelper.container", "Empty object name!");
319 uno::Reference < embed::XEmbeddedObject > xObj;
320 EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.find( rName );
322 #if OSL_DEBUG_LEVEL > 1
323 uno::Reference < container::XNameAccess > xAccess( pImpl->mxStorage, uno::UNO_QUERY );
324 uno::Sequence< OUString> aSeq = xAccess->getElementNames();
325 const OUString* pIter = aSeq.getConstArray();
326 const OUString* pEnd = pIter + aSeq.getLength();
327 for(;pIter != pEnd;++pIter)
329 (void)*pIter;
331 OSL_ENSURE( aIt != pImpl->maObjectContainer.end() || xAccess->hasByName(rName), "Could not return object!" );
332 #endif
334 // check if object was already created
335 if ( aIt != pImpl->maObjectContainer.end() )
336 xObj = (*aIt).second;
337 else
338 xObj = Get_Impl( rName, uno::Reference < embed::XEmbeddedObject >() );
340 return xObj;
343 uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::Get_Impl( const OUString& rName, const uno::Reference < embed::XEmbeddedObject >& xCopy )
345 uno::Reference < embed::XEmbeddedObject > xObj;
348 // create the object from the storage
349 uno::Reference < beans::XPropertySet > xSet( pImpl->mxStorage, uno::UNO_QUERY );
350 sal_Bool bReadOnlyMode = sal_True;
351 if ( xSet.is() )
353 // get the open mode from the parent storage
354 sal_Int32 nMode = 0;
355 uno::Any aAny = xSet->getPropertyValue( OUString("OpenMode") );
356 if ( aAny >>= nMode )
357 bReadOnlyMode = !(nMode & embed::ElementModes::WRITE );
360 // object was not added until now - should happen only by calling this method from "inside"
361 //TODO/LATER: it would be good to detect an error when an object should be created already, but isn't (not an "inside" call)
362 uno::Reference < embed::XEmbeddedObjectCreator > xFactory = embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() );
363 uno::Sequence< beans::PropertyValue > aObjDescr( xCopy.is() ? 2 : 1 );
364 aObjDescr[0].Name = "Parent";
365 aObjDescr[0].Value <<= pImpl->m_xModel.get();
366 if ( xCopy.is() )
368 aObjDescr[1].Name = "CloneFrom";
369 aObjDescr[1].Value <<= xCopy;
372 uno::Sequence< beans::PropertyValue > aMediaDescr( 1 );
373 aMediaDescr[0].Name = "ReadOnly";
374 aMediaDescr[0].Value <<= bReadOnlyMode;
375 xObj = uno::Reference < embed::XEmbeddedObject >( xFactory->createInstanceInitFromEntry(
376 pImpl->mxStorage, rName,
377 aMediaDescr, aObjDescr ), uno::UNO_QUERY );
379 // insert object into my list
380 AddEmbeddedObject( xObj, rName );
382 catch (uno::Exception const& e)
384 SAL_WARN("comphelper.container", "EmbeddedObjectContainer::Get_Impl: exception caught: " << e.Message);
387 return xObj;
390 uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::CreateEmbeddedObject( const uno::Sequence < sal_Int8 >& rClassId,
391 const uno::Sequence < beans::PropertyValue >& rArgs, OUString& rNewName )
393 SAL_INFO( "comphelper.container", "comphelper (mv76033) comphelper::EmbeddedObjectContainer::CreateEmbeddedObject" );
395 if ( rNewName.isEmpty() )
396 rNewName = CreateUniqueObjectName();
398 SAL_WARN_IF( HasEmbeddedObject(rNewName), "comphelper.container", "Object to create already exists!");
400 // create object from classid by inserting it into storage
401 uno::Reference < embed::XEmbeddedObject > xObj;
404 uno::Reference < embed::XEmbeddedObjectCreator > xFactory = embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() );
406 uno::Sequence< beans::PropertyValue > aObjDescr( rArgs.getLength() + 1 );
407 aObjDescr[0].Name = "Parent";
408 aObjDescr[0].Value <<= pImpl->m_xModel.get();
409 ::std::copy( rArgs.getConstArray(), rArgs.getConstArray() + rArgs.getLength(), aObjDescr.getArray() + 1 );
410 xObj = uno::Reference < embed::XEmbeddedObject >( xFactory->createInstanceInitNew(
411 rClassId, OUString(), pImpl->mxStorage, rNewName,
412 aObjDescr ), uno::UNO_QUERY );
414 AddEmbeddedObject( xObj, rNewName );
416 OSL_ENSURE( !xObj.is() || xObj->getCurrentState() != embed::EmbedStates::LOADED,
417 "A freshly create object should be running always!\n" );
419 catch (uno::Exception const& e)
421 SAL_WARN("comphelper.container", "EmbeddedObjectContainer::CreateEmbeddedObject: exception caught: " << e.Message);
424 return xObj;
427 uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::CreateEmbeddedObject( const uno::Sequence < sal_Int8 >& rClassId, OUString& rNewName )
429 return CreateEmbeddedObject( rClassId, uno::Sequence < beans::PropertyValue >(), rNewName );
432 void EmbeddedObjectContainer::AddEmbeddedObject( const ::com::sun::star::uno::Reference < ::com::sun::star::embed::XEmbeddedObject >& xObj, const OUString& rName )
434 SAL_INFO( "comphelper.container", "comphelper (mv76033) comphelper::EmbeddedObjectContainer::AddEmbeddedObject" );
436 #if OSL_DEBUG_LEVEL > 1
437 SAL_WARN_IF( rName.isEmpty(), "comphelper.container", "Added object doesn't have a name!");
438 uno::Reference < container::XNameAccess > xAccess( pImpl->mxStorage, uno::UNO_QUERY );
439 uno::Reference < embed::XEmbedPersist > xEmb( xObj, uno::UNO_QUERY );
440 uno::Reference < embed::XLinkageSupport > xLink( xEmb, uno::UNO_QUERY );
441 // if the object has a persistance and the object is not a link than it must have persistence entry in the storage
442 OSL_ENSURE( !( xEmb.is() && ( !xLink.is() || !xLink->isLink() ) ) || xAccess->hasByName(rName),
443 "Added element not in storage!" );
444 #endif
446 // remember object - it needs to be in storage already
447 EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.find( rName );
448 OSL_ENSURE( aIt == pImpl->maObjectContainer.end(), "Element already inserted!" );
449 pImpl->maObjectContainer[ rName ] = xObj;
450 uno::Reference < container::XChild > xChild( xObj, uno::UNO_QUERY );
451 if ( xChild.is() && xChild->getParent() != pImpl->m_xModel.get() )
452 xChild->setParent( pImpl->m_xModel.get() );
454 // look for object in temorary container
455 if ( pImpl->mpTempObjectContainer )
457 aIt = pImpl->mpTempObjectContainer->pImpl->maObjectContainer.begin();
458 while ( aIt != pImpl->mpTempObjectContainer->pImpl->maObjectContainer.end() )
460 if ( (*aIt).second == xObj )
462 // copy replacement image from temporary container (if there is any)
463 OUString aTempName = (*aIt).first;
464 OUString aMediaType;
465 uno::Reference < io::XInputStream > xStream = pImpl->mpTempObjectContainer->GetGraphicStream( xObj, &aMediaType );
466 if ( xStream.is() )
468 InsertGraphicStream( xStream, rName, aMediaType );
469 xStream = 0;
470 pImpl->mpTempObjectContainer->RemoveGraphicStream( aTempName );
473 // remove object from storage of temporary container
474 uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
475 if ( xPersist.is() )
479 pImpl->mpTempObjectContainer->pImpl->mxStorage->removeElement( aTempName );
481 catch (const uno::Exception&)
486 // temp. container needs to forget the object
487 pImpl->mpTempObjectContainer->pImpl->maObjectContainer.erase( aIt );
488 break;
490 else
491 ++aIt;
496 sal_Bool EmbeddedObjectContainer::StoreEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj, OUString& rName, sal_Bool bCopy )
498 SAL_INFO( "comphelper.container", "comphelper (mv76033) comphelper::EmbeddedObjectContainer::StoreEmbeddedObject" );
500 uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
501 if ( rName.isEmpty() )
502 rName = CreateUniqueObjectName();
504 #if OSL_DEBUG_LEVEL > 1
505 uno::Reference < container::XNameAccess > xAccess( pImpl->mxStorage, uno::UNO_QUERY );
506 OSL_ENSURE( !xPersist.is() || !xAccess->hasByName(rName), "Inserting element already present in storage!" );
507 OSL_ENSURE( xPersist.is() || xObj->getCurrentState() == embed::EmbedStates::RUNNING, "Non persistent object inserted!");
508 #endif
510 // insert objects' storage into the container storage (if object has one)
513 if ( xPersist.is() )
515 uno::Sequence < beans::PropertyValue > aSeq;
516 if ( bCopy )
517 xPersist->storeToEntry( pImpl->mxStorage, rName, aSeq, aSeq );
518 else
520 //TODO/LATER: possible optimisation, don't store immediately
521 //xPersist->setPersistentEntry( pImpl->mxStorage, rName, embed::EntryInitModes::ENTRY_NO_INIT, aSeq, aSeq );
522 xPersist->storeAsEntry( pImpl->mxStorage, rName, aSeq, aSeq );
523 xPersist->saveCompleted( sal_True );
527 catch (uno::Exception const& e)
529 SAL_WARN("comphelper.container", "EmbeddedObjectContainer::StoreEmbeddedObject: exception caught: " << e.Message);
530 // TODO/LATER: better error recovery should keep storage intact
531 return sal_False;
534 return sal_True;
537 sal_Bool EmbeddedObjectContainer::InsertEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj, OUString& rName )
539 SAL_INFO( "comphelper.container", "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertEmbeddedObject( Object )" );
540 // store it into the container storage
541 if ( StoreEmbeddedObject( xObj, rName, sal_False ) )
543 // remember object
544 AddEmbeddedObject( xObj, rName );
545 return sal_True;
547 else
548 return sal_False;
551 uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::InsertEmbeddedObject( const uno::Reference < io::XInputStream >& xStm, OUString& rNewName )
553 SAL_INFO( "comphelper.container", "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertEmbeddedObject( InputStream )" );
555 if ( rNewName.isEmpty() )
556 rNewName = CreateUniqueObjectName();
558 // store it into the container storage
559 sal_Bool bIsStorage = sal_False;
562 // first try storage persistence
563 uno::Reference < embed::XStorage > xStore = ::comphelper::OStorageHelper::GetStorageFromInputStream( xStm );
565 // storage was created from stream successfully
566 bIsStorage = sal_True;
568 uno::Reference < embed::XStorage > xNewStore = pImpl->mxStorage->openStorageElement( rNewName, embed::ElementModes::READWRITE );
569 xStore->copyToStorage( xNewStore );
571 catch (const uno::Exception&)
573 if ( bIsStorage )
574 // it is storage persistence, but opening of new substorage or copying to it failed
575 return uno::Reference < embed::XEmbeddedObject >();
577 // stream didn't contain a storage, now try stream persistence
580 uno::Reference < io::XStream > xNewStream = pImpl->mxStorage->openStreamElement( rNewName, embed::ElementModes::READWRITE );
581 ::comphelper::OStorageHelper::CopyInputToOutput( xStm, xNewStream->getOutputStream() );
583 // No mediatype is provided so the default for OLE objects value is used
584 // it is correct so for now, but what if somebody introduces a new stream based embedded object?
585 // Probably introducing of such an object must be restricted ( a storage must be used! ).
586 uno::Reference< beans::XPropertySet > xProps( xNewStream, uno::UNO_QUERY_THROW );
587 xProps->setPropertyValue( OUString( "MediaType" ),
588 uno::makeAny( OUString( "application/vnd.sun.star.oleobject" ) ) );
590 catch (uno::Exception const& e)
592 // complete disaster!
593 SAL_WARN("comphelper.container", "EmbeddedObjectContainer::InsertEmbeddedObject: exception caught: " << e.Message);
594 return uno::Reference < embed::XEmbeddedObject >();
598 // stream was copied into the container storage in either way, now try to open something form it
599 uno::Reference < embed::XEmbeddedObject > xRet = GetEmbeddedObject( rNewName );
602 if ( !xRet.is() )
603 // no object could be created, so withdraw insertion
604 pImpl->mxStorage->removeElement( rNewName );
606 catch (const uno::Exception&)
610 return xRet;
613 uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::InsertEmbeddedObject( const ::com::sun::star::uno::Sequence < ::com::sun::star::beans::PropertyValue >& aMedium, OUString& rNewName )
615 SAL_INFO( "comphelper.container", "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertEmbeddedObject( MediaDescriptor )" );
617 if ( rNewName.isEmpty() )
618 rNewName = CreateUniqueObjectName();
620 uno::Reference < embed::XEmbeddedObject > xObj;
623 uno::Reference < embed::XEmbeddedObjectCreator > xFactory = embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() );
624 uno::Sequence< beans::PropertyValue > aObjDescr( 1 );
625 aObjDescr[0].Name = "Parent";
626 aObjDescr[0].Value <<= pImpl->m_xModel.get();
627 xObj = uno::Reference < embed::XEmbeddedObject >( xFactory->createInstanceInitFromMediaDescriptor(
628 pImpl->mxStorage, rNewName, aMedium, aObjDescr ), uno::UNO_QUERY );
629 uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
631 OSL_ENSURE( !xObj.is() || xObj->getCurrentState() != embed::EmbedStates::LOADED,
632 "A freshly create object should be running always!\n" );
634 // possible optimization: store later!
635 if ( xPersist.is())
636 xPersist->storeOwn();
638 AddEmbeddedObject( xObj, rNewName );
640 catch (const uno::Exception&)
644 return xObj;
647 uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::InsertEmbeddedLink( const ::com::sun::star::uno::Sequence < ::com::sun::star::beans::PropertyValue >& aMedium, OUString& rNewName )
649 SAL_INFO( "comphelper.container", "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertEmbeddedLink" );
651 if ( rNewName.isEmpty() )
652 rNewName = CreateUniqueObjectName();
654 uno::Reference < embed::XEmbeddedObject > xObj;
657 uno::Reference < embed::XEmbeddedObjectCreator > xFactory = embed::EmbeddedObjectCreator::create(::comphelper::getProcessComponentContext());
658 uno::Sequence< beans::PropertyValue > aObjDescr( 1 );
659 aObjDescr[0].Name = "Parent";
660 aObjDescr[0].Value <<= pImpl->m_xModel.get();
661 xObj = uno::Reference < embed::XEmbeddedObject >( xFactory->createInstanceLink(
662 pImpl->mxStorage, rNewName, aMedium, aObjDescr ), uno::UNO_QUERY );
664 uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
666 OSL_ENSURE( !xObj.is() || xObj->getCurrentState() != embed::EmbedStates::LOADED,
667 "A freshly create object should be running always!\n" );
669 // possible optimization: store later!
670 if ( xPersist.is())
671 xPersist->storeOwn();
673 AddEmbeddedObject( xObj, rNewName );
675 catch (uno::Exception const& e)
677 SAL_WARN("comphelper", "EmbeddedObjectContainer::InsertEmbeddedLink: "
678 "exception caught: " << e.Message);
681 return xObj;
684 sal_Bool EmbeddedObjectContainer::TryToCopyGraphReplacement( EmbeddedObjectContainer& rSrc,
685 const OUString& aOrigName,
686 const OUString& aTargetName )
688 SAL_INFO( "comphelper.container", "comphelper (mv76033) comphelper::EmbeddedObjectContainer::TryToCopyGraphReplacement" );
690 sal_Bool bResult = sal_False;
692 if ( ( &rSrc != this || !aOrigName.equals( aTargetName ) ) && !aOrigName.isEmpty() && !aTargetName.isEmpty() )
694 OUString aMediaType;
695 uno::Reference < io::XInputStream > xGrStream = rSrc.GetGraphicStream( aOrigName, &aMediaType );
696 if ( xGrStream.is() )
697 bResult = InsertGraphicStream( xGrStream, aTargetName, aMediaType );
700 return bResult;
703 uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::CopyAndGetEmbeddedObject( EmbeddedObjectContainer& rSrc, const uno::Reference < embed::XEmbeddedObject >& xObj, OUString& rName )
705 SAL_INFO( "comphelper.container", "comphelper (mv76033) comphelper::EmbeddedObjectContainer::CopyAndGetEmbeddedObject" );
707 uno::Reference< embed::XEmbeddedObject > xResult;
709 // TODO/LATER: For now only objects that implement XEmbedPersist have a replacement image, it might change in future
710 // do an incompatible change so that object name is provided in all the move and copy methods
711 OUString aOrigName;
714 uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY_THROW );
715 aOrigName = xPersist->getEntryName();
717 catch (const uno::Exception&)
721 if ( rName.isEmpty() )
722 rName = CreateUniqueObjectName();
724 // objects without persistance are not really stored by the method
725 if ( xObj.is() && StoreEmbeddedObject( xObj, rName, sal_True ) )
727 xResult = Get_Impl( rName, xObj);
728 if ( !xResult.is() )
730 // this is a case when object has no real persistence
731 // in such cases a new object should be explicitly created and initialized with the data of the old one
734 uno::Reference< embed::XLinkageSupport > xOrigLinkage( xObj, uno::UNO_QUERY );
735 if ( xOrigLinkage.is() && xOrigLinkage->isLink() )
737 // this is a OOo link, it has no persistence
738 OUString aURL = xOrigLinkage->getLinkURL();
739 if ( aURL.isEmpty() )
740 throw uno::RuntimeException();
742 // create new linked object from the URL the link is based on
743 uno::Reference < embed::XEmbeddedObjectCreator > xCreator =
744 embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() );
746 uno::Sequence< beans::PropertyValue > aMediaDescr( 1 );
747 aMediaDescr[0].Name = "URL";
748 aMediaDescr[0].Value <<= aURL;
749 uno::Sequence< beans::PropertyValue > aObjDescr( 1 );
750 aObjDescr[0].Name = "Parent";
751 aObjDescr[0].Value <<= pImpl->m_xModel.get();
752 xResult = uno::Reference < embed::XEmbeddedObject >(
753 xCreator->createInstanceLink(
754 pImpl->mxStorage,
755 rName,
756 aMediaDescr,
757 aObjDescr ),
758 uno::UNO_QUERY_THROW );
760 else
762 // the component is required for copying of this object
763 if ( xObj->getCurrentState() == embed::EmbedStates::LOADED )
764 xObj->changeState( embed::EmbedStates::RUNNING );
766 // this must be an object based on properties, otherwise we can not copy it currently
767 uno::Reference< beans::XPropertySet > xOrigProps( xObj->getComponent(), uno::UNO_QUERY_THROW );
769 // use object class ID to create a new one and tranfer all the properties
770 uno::Reference < embed::XEmbeddedObjectCreator > xCreator =
771 embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() );
773 uno::Sequence< beans::PropertyValue > aObjDescr( 1 );
774 aObjDescr[0].Name = "Parent";
775 aObjDescr[0].Value <<= pImpl->m_xModel.get();
776 xResult = uno::Reference < embed::XEmbeddedObject >(
777 xCreator->createInstanceInitNew(
778 xObj->getClassID(),
779 xObj->getClassName(),
780 pImpl->mxStorage,
781 rName,
782 aObjDescr ),
783 uno::UNO_QUERY_THROW );
785 if ( xResult->getCurrentState() == embed::EmbedStates::LOADED )
786 xResult->changeState( embed::EmbedStates::RUNNING );
788 uno::Reference< beans::XPropertySet > xTargetProps( xResult->getComponent(), uno::UNO_QUERY_THROW );
790 // copy all the properties from xOrigProps to xTargetProps
791 uno::Reference< beans::XPropertySetInfo > xOrigInfo = xOrigProps->getPropertySetInfo();
792 if ( !xOrigInfo.is() )
793 throw uno::RuntimeException();
795 uno::Sequence< beans::Property > aPropertiesList = xOrigInfo->getProperties();
796 for ( sal_Int32 nInd = 0; nInd < aPropertiesList.getLength(); nInd++ )
800 xTargetProps->setPropertyValue(
801 aPropertiesList[nInd].Name,
802 xOrigProps->getPropertyValue( aPropertiesList[nInd].Name ) );
804 catch (const beans::PropertyVetoException&)
806 // impossibility to copy readonly property is not treated as an error for now
807 // but the assertion is helpful to detect such scenarios and review them
808 SAL_WARN( "comphelper.container", "Could not copy readonly property!\n" );
813 if ( xResult.is() )
814 AddEmbeddedObject( xResult, rName );
816 catch (const uno::Exception&)
818 if ( xResult.is() )
822 xResult->close( sal_True );
824 catch (const uno::Exception&)
827 xResult = uno::Reference< embed::XEmbeddedObject >();
833 SAL_WARN_IF( !xResult.is(), "comphelper.container", "Can not copy embedded object that has no persistance!\n" );
835 if ( xResult.is() )
837 // the object is successfully copied, try to copy graphical replacement
838 if ( !aOrigName.isEmpty() )
839 TryToCopyGraphReplacement( rSrc, aOrigName, rName );
841 // the object might need the size to be set
844 if ( xResult->getStatus( embed::Aspects::MSOLE_CONTENT ) & embed::EmbedMisc::EMBED_NEEDSSIZEONLOAD )
845 xResult->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT,
846 xObj->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT ) );
848 catch (const uno::Exception&)
853 return xResult;
856 sal_Bool EmbeddedObjectContainer::MoveEmbeddedObject( EmbeddedObjectContainer& rSrc, const uno::Reference < embed::XEmbeddedObject >& xObj, OUString& rName )
858 SAL_INFO( "comphelper.container", "comphelper (mv76033) comphelper::EmbeddedObjectContainer::MoveEmbeddedObject( Object )" );
860 // get the object name before(!) it is assigned to a new storage
861 uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
862 OUString aName;
863 if ( xPersist.is() )
864 aName = xPersist->getEntryName();
866 // now move the object to the new container; the returned name is the new persist name in this container
867 sal_Bool bRet;
871 bRet = InsertEmbeddedObject( xObj, rName );
872 if ( bRet )
873 TryToCopyGraphReplacement( rSrc, aName, rName );
875 catch (const uno::Exception&)
877 SAL_WARN( "comphelper.container", "Failed to insert embedded object into storage!" );
878 bRet = sal_False;
881 if ( bRet )
883 // now remove the object from the former container
884 bRet = sal_False;
885 EmbeddedObjectContainerNameMap::iterator aIt = rSrc.pImpl->maObjectContainer.begin();
886 while ( aIt != rSrc.pImpl->maObjectContainer.end() )
888 if ( (*aIt).second == xObj )
890 rSrc.pImpl->maObjectContainer.erase( aIt );
891 bRet = sal_True;
892 break;
895 ++aIt;
898 SAL_WARN_IF( !bRet, "comphelper.container", "Object not found for removal!" );
899 if ( xPersist.is() )
901 // now it's time to remove the storage from the container storage
904 if ( xPersist.is() )
905 rSrc.pImpl->mxStorage->removeElement( aName );
907 catch (const uno::Exception&)
909 SAL_WARN( "comphelper.container", "Failed to remove object from storage!" );
910 bRet = sal_False;
914 // rSrc.RemoveGraphicStream( aName );
917 return bRet;
920 // #i119941, bKeepToTempStorage: use to specify whether store the removed object to temporary storage+
921 sal_Bool EmbeddedObjectContainer::RemoveEmbeddedObject( const OUString& rName, sal_Bool bClose, sal_Bool bKeepToTempStorage )
923 SAL_INFO( "comphelper.container", "comphelper (mv76033) comphelper::EmbeddedObjectContainer::RemoveEmbeddedObject( Name )" );
925 uno::Reference < embed::XEmbeddedObject > xObj = GetEmbeddedObject( rName );
926 if ( xObj.is() )
927 //return RemoveEmbeddedObject( xObj, bClose );
928 return RemoveEmbeddedObject( xObj, bClose, bKeepToTempStorage );
929 else
930 return sal_False;
933 sal_Bool EmbeddedObjectContainer::MoveEmbeddedObject( const OUString& rName, EmbeddedObjectContainer& rCnt )
935 SAL_INFO( "comphelper.container", "comphelper (mv76033) comphelper::EmbeddedObjectContainer::MoveEmbeddedObject( Name )" );
937 // find object entry
938 EmbeddedObjectContainerNameMap::iterator aIt2 = rCnt.pImpl->maObjectContainer.find( rName );
939 OSL_ENSURE( aIt2 == rCnt.pImpl->maObjectContainer.end(), "Object does already exist in target container!" );
941 if ( aIt2 != rCnt.pImpl->maObjectContainer.end() )
942 return sal_False;
944 uno::Reference < embed::XEmbeddedObject > xObj;
945 EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.find( rName );
946 if ( aIt != pImpl->maObjectContainer.end() )
948 xObj = (*aIt).second;
951 if ( xObj.is() )
953 // move object
954 OUString aName( rName );
955 rCnt.InsertEmbeddedObject( xObj, aName );
956 pImpl->maObjectContainer.erase( aIt );
957 uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
958 if ( xPersist.is() )
959 pImpl->mxStorage->removeElement( rName );
961 else
963 // copy storages; object *must* have persistence!
964 uno::Reference < embed::XStorage > xOld = pImpl->mxStorage->openStorageElement( rName, embed::ElementModes::READ );
965 uno::Reference < embed::XStorage > xNew = rCnt.pImpl->mxStorage->openStorageElement( rName, embed::ElementModes::READWRITE );
966 xOld->copyToStorage( xNew );
969 rCnt.TryToCopyGraphReplacement( *this, rName, rName );
970 // RemoveGraphicStream( rName );
972 return sal_True;
974 catch (const uno::Exception&)
976 SAL_WARN( "comphelper.container", "Could not move object!");
977 return sal_False;
981 else
982 SAL_WARN( "comphelper.container", "Unknown object!");
983 return sal_False;
986 //sal_Bool EmbeddedObjectContainer::RemoveEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj, sal_Bool bClose )
987 // #i119941, bKeepToTempStorage: use to specify whether store the removed object to temporary storage+
988 sal_Bool EmbeddedObjectContainer::RemoveEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj, sal_Bool bClose, sal_Bool bKeepToTempStorage )
990 SAL_INFO( "comphelper.container", "comphelper (mv76033) comphelper::EmbeddedObjectContainer::RemoveEmbeddedObject( Object )" );
992 uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
993 OUString aName;
994 if ( xPersist.is() )
995 aName = xPersist->getEntryName();
997 #if OSL_DEBUG_LEVEL > 1
998 uno::Reference < container::XNameAccess > xAccess( pImpl->mxStorage, uno::UNO_QUERY );
999 uno::Reference < embed::XLinkageSupport > xLink( xPersist, uno::UNO_QUERY );
1000 sal_Bool bIsNotEmbedded = !xPersist.is() || ( xLink.is() && xLink->isLink() );
1002 // if the object has a persistance and the object is not a link than it must have persistence entry in the storage
1003 OSL_ENSURE( bIsNotEmbedded || xAccess->hasByName(aName), "Removing element not present in storage!" );
1004 #endif
1006 // try to close it if permitted
1007 if ( bClose )
1009 uno::Reference < ::util::XCloseable > xClose( xObj, uno::UNO_QUERY );
1012 xClose->close( sal_True );
1014 catch (const util::CloseVetoException&)
1016 bClose = sal_False;
1020 if ( !bClose )
1022 // somebody still needs the object, so we must assign a temporary persistence
1025 // if ( xPersist.is() )
1026 if ( xPersist.is() && bKeepToTempStorage ) // #i119941
1029 //TODO/LATER: needs storage handling! Why not letting the object do it?!
1030 if ( !pImpl->mxTempStorage.is() )
1031 pImpl->mxTempStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
1032 uno::Sequence < beans::PropertyValue > aSeq;
1034 OUString aTmpPersistName = "Object ";
1035 aTmpPersistName += OUString::valueOf( (sal_Int32) pImpl->maTempObjectContainer.size() );
1037 xPersist->storeAsEntry( pImpl->mxTempStorage, aTmpPersistName, aSeq, aSeq );
1038 xPersist->saveCompleted( sal_True );
1040 pImpl->maTempObjectContainer[ aTmpPersistName ] = uno::Reference < embed::XEmbeddedObject >();
1043 if ( !pImpl->mpTempObjectContainer )
1045 pImpl->mpTempObjectContainer = new EmbeddedObjectContainer();
1048 // TODO/LATER: in future probably the temporary container will have two storages ( of two formats )
1049 // the media type will be provided with object insertion
1050 OUString aOrigStorMediaType;
1051 uno::Reference< beans::XPropertySet > xStorProps( pImpl->mxStorage, uno::UNO_QUERY_THROW );
1052 static const OUString s_sMediaType("MediaType");
1053 xStorProps->getPropertyValue( s_sMediaType ) >>= aOrigStorMediaType;
1055 SAL_WARN_IF( aOrigStorMediaType.isEmpty(), "comphelper.container", "No valuable media type in the storage!\n" );
1057 uno::Reference< beans::XPropertySet > xTargetStorProps(
1058 pImpl->mpTempObjectContainer->pImpl->mxStorage,
1059 uno::UNO_QUERY_THROW );
1060 xTargetStorProps->setPropertyValue( s_sMediaType,uno::makeAny( aOrigStorMediaType ) );
1062 catch (const uno::Exception&)
1064 SAL_WARN( "comphelper.container", "Can not set the new media type to a storage!\n" );
1068 OUString aTempName, aMediaType;
1069 pImpl->mpTempObjectContainer->InsertEmbeddedObject( xObj, aTempName );
1071 uno::Reference < io::XInputStream > xStream = GetGraphicStream( xObj, &aMediaType );
1072 if ( xStream.is() )
1073 pImpl->mpTempObjectContainer->InsertGraphicStream( xStream, aTempName, aMediaType );
1075 // object is stored, so at least it can be set to loaded state
1076 xObj->changeState( embed::EmbedStates::LOADED );
1078 else
1079 // objects without persistence need to stay in running state if they shall not be closed
1080 xObj->changeState( embed::EmbedStates::RUNNING );
1082 catch (const uno::Exception&)
1084 return sal_False;
1088 sal_Bool bFound = sal_False;
1089 EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin();
1090 while ( aIt != pImpl->maObjectContainer.end() )
1092 if ( (*aIt).second == xObj )
1094 pImpl->maObjectContainer.erase( aIt );
1095 bFound = sal_True;
1096 uno::Reference < container::XChild > xChild( xObj, uno::UNO_QUERY );
1097 if ( xChild.is() )
1098 xChild->setParent( uno::Reference < uno::XInterface >() );
1099 break;
1102 ++aIt;
1105 SAL_WARN_IF( !bFound,"comphelper.container", "Object not found for removal!" );
1106 (void)bFound;
1107 if ( xPersist.is() && bKeepToTempStorage ) // #i119941#
1109 // remove replacement image (if there is one)
1110 RemoveGraphicStream( aName );
1112 // now it's time to remove the storage from the container storage
1115 #if OSL_DEBUG_LEVEL > 1
1116 // if the object has a persistance and the object is not a link than it must have persistence entry in storage
1117 OSL_ENSURE( bIsNotEmbedded || pImpl->mxStorage->hasByName( aName ), "The object has no persistence entry in the storage!" );
1118 #endif
1119 if ( xPersist.is() && pImpl->mxStorage->hasByName( aName ) )
1120 pImpl->mxStorage->removeElement( aName );
1122 catch (const uno::Exception&)
1124 SAL_WARN( "comphelper.container", "Failed to remove object from storage!" );
1125 return sal_False;
1129 return sal_True;
1132 sal_Bool EmbeddedObjectContainer::CloseEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj )
1134 SAL_INFO( "comphelper.container", "comphelper (mv76033) comphelper::EmbeddedObjectContainer::CloseEmbeddedObject" );
1136 // disconnect the object from the container and close it if possible
1138 sal_Bool bFound = sal_False;
1139 EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin();
1140 while ( aIt != pImpl->maObjectContainer.end() )
1142 if ( (*aIt).second == xObj )
1144 pImpl->maObjectContainer.erase( aIt );
1145 bFound = sal_True;
1146 break;
1149 ++aIt;
1152 if ( bFound )
1154 uno::Reference < ::util::XCloseable > xClose( xObj, uno::UNO_QUERY );
1157 xClose->close( sal_True );
1159 catch (const uno::Exception&)
1161 // it is no problem if the object is already closed
1162 // TODO/LATER: what if the object can not be closed?
1166 return bFound;
1169 uno::Reference < io::XInputStream > EmbeddedObjectContainer::GetGraphicStream( const OUString& aName, OUString* pMediaType )
1171 SAL_INFO( "comphelper.container", "comphelper (mv76033) comphelper::EmbeddedObjectContainer::GetGraphicStream( Name )" );
1173 uno::Reference < io::XInputStream > xStream;
1175 SAL_WARN_IF( aName.isEmpty(), "comphelper.container", "Retrieving graphic for unknown object!" );
1176 if ( !aName.isEmpty() )
1180 uno::Reference < embed::XStorage > xReplacements = pImpl->GetReplacements();
1181 uno::Reference < io::XStream > xGraphicStream = xReplacements->openStreamElement( aName, embed::ElementModes::READ );
1182 xStream = xGraphicStream->getInputStream();
1183 if ( pMediaType )
1185 uno::Reference < beans::XPropertySet > xSet( xStream, uno::UNO_QUERY );
1186 if ( xSet.is() )
1188 uno::Any aAny = xSet->getPropertyValue( OUString("MediaType") );
1189 aAny >>= *pMediaType;
1193 catch (const uno::Exception&)
1198 return xStream;
1201 uno::Reference < io::XInputStream > EmbeddedObjectContainer::GetGraphicStream( const ::com::sun::star::uno::Reference < ::com::sun::star::embed::XEmbeddedObject >& xObj, OUString* pMediaType )
1203 SAL_INFO( "comphelper.container", "comphelper (mv76033) comphelper::EmbeddedObjectContainer::GetGraphicStream( Object )" );
1205 // get the object name
1206 OUString aName;
1207 EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin();
1208 while ( aIt != pImpl->maObjectContainer.end() )
1210 if ( (*aIt).second == xObj )
1212 aName = (*aIt).first;
1213 break;
1216 ++aIt;
1219 // try to load it from the container storage
1220 return GetGraphicStream( aName, pMediaType );
1223 sal_Bool EmbeddedObjectContainer::InsertGraphicStream( const com::sun::star::uno::Reference < com::sun::star::io::XInputStream >& rStream, const OUString& rObjectName, const OUString& rMediaType )
1225 SAL_INFO( "comphelper.container", "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertGraphicStream" );
1229 uno::Reference < embed::XStorage > xReplacements = pImpl->GetReplacements();
1231 // store it into the subfolder
1232 uno::Reference < io::XOutputStream > xOutStream;
1233 uno::Reference < io::XStream > xGraphicStream = xReplacements->openStreamElement( rObjectName,
1234 embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE );
1235 xOutStream = xGraphicStream->getOutputStream();
1236 ::comphelper::OStorageHelper::CopyInputToOutput( rStream, xOutStream );
1237 xOutStream->flush();
1239 uno::Reference< beans::XPropertySet > xPropSet( xGraphicStream, uno::UNO_QUERY );
1240 if ( !xPropSet.is() )
1241 throw uno::RuntimeException();
1243 xPropSet->setPropertyValue( OUString("UseCommonStoragePasswordEncryption"),
1244 uno::makeAny( (sal_Bool)sal_True ) );
1245 uno::Any aAny;
1246 aAny <<= rMediaType;
1247 xPropSet->setPropertyValue( OUString("MediaType"), aAny );
1249 xPropSet->setPropertyValue( OUString("Compressed"),
1250 uno::makeAny( (sal_Bool)sal_True ) );
1252 catch (const uno::Exception&)
1254 return sal_False;
1257 return sal_True;
1260 sal_Bool EmbeddedObjectContainer::InsertGraphicStreamDirectly( const com::sun::star::uno::Reference < com::sun::star::io::XInputStream >& rStream, const OUString& rObjectName, const OUString& rMediaType )
1262 SAL_INFO( "comphelper.container", "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertGraphicStreamDirectly" );
1266 uno::Reference < embed::XStorage > xReplacement = pImpl->GetReplacements();
1267 uno::Reference < embed::XOptimizedStorage > xOptRepl( xReplacement, uno::UNO_QUERY_THROW );
1269 // store it into the subfolder
1270 uno::Sequence< beans::PropertyValue > aProps( 3 );
1271 aProps[0].Name = "MediaType";
1272 aProps[0].Value <<= rMediaType;
1273 aProps[1].Name = "UseCommonStoragePasswordEncryption";
1274 aProps[1].Value <<= (sal_Bool)sal_True;
1275 aProps[2].Name = "Compressed";
1276 aProps[2].Value <<= (sal_Bool)sal_True;
1278 if ( xReplacement->hasByName( rObjectName ) )
1279 xReplacement->removeElement( rObjectName );
1281 xOptRepl->insertStreamElementDirect( rObjectName, rStream, aProps );
1283 catch (const uno::Exception&)
1285 return sal_False;
1288 return sal_True;
1292 sal_Bool EmbeddedObjectContainer::RemoveGraphicStream( const OUString& rObjectName )
1294 SAL_INFO( "comphelper.container", "comphelper (mv76033) comphelper::EmbeddedObjectContainer::RemoveGraphicStream" );
1298 uno::Reference < embed::XStorage > xReplacements = pImpl->GetReplacements();
1299 xReplacements->removeElement( rObjectName );
1301 catch (const uno::Exception&)
1303 return sal_False;
1306 return sal_True;
1308 namespace {
1309 void InsertStreamIntoPicturesStorage_Impl( const uno::Reference< embed::XStorage >& xDocStor,
1310 const uno::Reference< io::XInputStream >& xInStream,
1311 const OUString& aStreamName )
1313 OSL_ENSURE( !aStreamName.isEmpty() && xInStream.is() && xDocStor.is(), "Misuse of the method!\n" );
1317 uno::Reference< embed::XStorage > xPictures = xDocStor->openStorageElement(
1318 OUString( "Pictures" ),
1319 embed::ElementModes::READWRITE );
1320 uno::Reference< io::XStream > xObjReplStr = xPictures->openStreamElement(
1321 aStreamName,
1322 embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE );
1323 uno::Reference< io::XOutputStream > xOutStream(
1324 xObjReplStr->getInputStream(), uno::UNO_QUERY_THROW );
1326 ::comphelper::OStorageHelper::CopyInputToOutput( xInStream, xOutStream );
1327 xOutStream->closeOutput();
1329 uno::Reference< embed::XTransactedObject > xTransact( xPictures, uno::UNO_QUERY );
1330 if ( xTransact.is() )
1331 xTransact->commit();
1333 catch (const uno::Exception&)
1335 SAL_WARN( "comphelper.container", "The pictures storage is not available!\n" );
1340 // -----------------------------------------------------------------------------
1341 sal_Bool EmbeddedObjectContainer::StoreAsChildren(sal_Bool _bOasisFormat,sal_Bool _bCreateEmbedded,const uno::Reference < embed::XStorage >& _xStorage)
1343 sal_Bool bResult = sal_False;
1346 comphelper::EmbeddedObjectContainer aCnt( _xStorage );
1347 const uno::Sequence < OUString > aNames = GetObjectNames();
1348 const OUString* pIter = aNames.getConstArray();
1349 const OUString* pEnd = pIter + aNames.getLength();
1350 for(;pIter != pEnd;++pIter)
1352 uno::Reference < embed::XEmbeddedObject > xObj = GetEmbeddedObject( *pIter );
1353 SAL_WARN_IF( !xObj.is(), "comphelper.container", "An empty entry in the embedded objects list!\n" );
1354 if ( xObj.is() )
1356 sal_Bool bSwitchBackToLoaded = sal_False;
1357 uno::Reference< embed::XLinkageSupport > xLink( xObj, uno::UNO_QUERY );
1359 uno::Reference < io::XInputStream > xStream;
1360 OUString aMediaType;
1362 sal_Int32 nCurState = xObj->getCurrentState();
1363 if ( nCurState == embed::EmbedStates::LOADED || nCurState == embed::EmbedStates::RUNNING )
1365 // means that the object is not active
1366 // copy replacement image from old to new container
1367 xStream = GetGraphicStream( xObj, &aMediaType );
1370 if ( !xStream.is() )
1372 // the image must be regenerated
1373 // TODO/LATER: another aspect could be used
1374 if ( xObj->getCurrentState() == embed::EmbedStates::LOADED )
1375 bSwitchBackToLoaded = sal_True;
1377 xStream = GetGraphicReplacementStream(
1378 embed::Aspects::MSOLE_CONTENT,
1379 xObj,
1380 &aMediaType );
1383 if ( _bOasisFormat || (xLink.is() && xLink->isLink()) )
1385 if ( xStream.is() )
1387 if ( _bOasisFormat )
1389 // if it is an embedded object or the optimized inserting fails the normal inserting should be done
1390 if ( _bCreateEmbedded
1391 || !aCnt.InsertGraphicStreamDirectly( xStream, *pIter, aMediaType ) )
1392 aCnt.InsertGraphicStream( xStream, *pIter, aMediaType );
1394 else
1396 // it is a linked object exported into SO7 format
1397 InsertStreamIntoPicturesStorage_Impl( _xStorage, xStream, *pIter );
1402 uno::Reference< embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
1403 if ( xPersist.is() )
1405 uno::Sequence< beans::PropertyValue > aArgs( _bOasisFormat ? 2 : 3 );
1406 aArgs[0].Name = "StoreVisualReplacement";
1407 aArgs[0].Value <<= (sal_Bool)( !_bOasisFormat );
1409 // if it is an embedded object or the optimized inserting fails the normal inserting should be done
1410 aArgs[1].Name = "CanTryOptimization";
1411 aArgs[1].Value <<= !_bCreateEmbedded;
1412 if ( !_bOasisFormat )
1414 // if object has no cached replacement it will use this one
1415 aArgs[2].Name = "VisualReplacement";
1416 aArgs[2].Value <<= xStream;
1421 xPersist->storeAsEntry( _xStorage, xPersist->getEntryName(), uno::Sequence< beans::PropertyValue >(), aArgs );
1423 catch (const embed::WrongStateException&)
1425 SAL_WARN("comphelper.container", "failed to store '" << *pIter << "'");
1429 if ( bSwitchBackToLoaded )
1430 // switch back to loaded state; that way we have a minimum cache confusion
1431 xObj->changeState( embed::EmbedStates::LOADED );
1435 bResult = aCnt.CommitImageSubStorage();
1438 catch (const uno::Exception& e)
1440 // TODO/LATER: error handling
1441 bResult = sal_False;
1442 SAL_WARN("comphelper.container", "failed. Message: " << e.Message);
1445 // the old SO6 format does not store graphical replacements
1446 if ( !_bOasisFormat && bResult )
1450 // the substorage still can not be locked by the embedded object conteiner
1451 OUString aObjReplElement( "ObjectReplacements" );
1452 if ( _xStorage->hasByName( aObjReplElement ) && _xStorage->isStorageElement( aObjReplElement ) )
1453 _xStorage->removeElement( aObjReplElement );
1455 catch (const uno::Exception&)
1457 // TODO/LATER: error handling;
1458 bResult = sal_False;
1461 return bResult;
1463 // -----------------------------------------------------------------------------
1464 sal_Bool EmbeddedObjectContainer::StoreChildren(sal_Bool _bOasisFormat,sal_Bool _bObjectsOnly)
1466 sal_Bool bResult = sal_True;
1467 const uno::Sequence < OUString > aNames = GetObjectNames();
1468 const OUString* pIter = aNames.getConstArray();
1469 const OUString* pEnd = pIter + aNames.getLength();
1470 for(;pIter != pEnd;++pIter)
1472 uno::Reference < embed::XEmbeddedObject > xObj = GetEmbeddedObject( *pIter );
1473 SAL_WARN_IF( !xObj.is(), "comphelper.container", "An empty entry in the embedded objects list!\n" );
1474 if ( xObj.is() )
1476 sal_Int32 nCurState = xObj->getCurrentState();
1477 if ( _bOasisFormat && nCurState != embed::EmbedStates::LOADED && nCurState != embed::EmbedStates::RUNNING )
1479 // means that the object is active
1480 // the image must be regenerated
1481 OUString aMediaType;
1483 // TODO/LATER: another aspect could be used
1484 uno::Reference < io::XInputStream > xStream =
1485 GetGraphicReplacementStream(
1486 embed::Aspects::MSOLE_CONTENT,
1487 xObj,
1488 &aMediaType );
1489 if ( xStream.is() )
1491 if ( !InsertGraphicStreamDirectly( xStream, *pIter, aMediaType ) )
1492 InsertGraphicStream( xStream, *pIter, aMediaType );
1496 // TODO/LATER: currently the object by default does not cache replacement image
1497 // that means that if somebody loads SO7 document and store its objects using
1498 // this method the images might be lost.
1499 // Currently this method is only used on storing to alien formats, that means
1500 // that SO7 documents storing does not use it, and all other filters are
1501 // based on OASIS format. But if it changes the method must be fixed. The fix
1502 // must be done only on demand since it can affect performance.
1504 uno::Reference< embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
1505 if ( xPersist.is() )
1509 //TODO/LATER: only storing if changed!
1510 //xPersist->storeOwn(); //commented, i120168
1512 // begin:all charts will be persited as xml format on disk when saving, which is time consuming.
1513 // '_bObjectsOnly' mean we are storing to alien formats.
1514 // 'isStorageElement' mean current object is NOT an MS OLE format. (may also include in future), i120168
1515 if (_bObjectsOnly && (nCurState == embed::EmbedStates::LOADED || nCurState == embed::EmbedStates::RUNNING)
1516 && (pImpl->mxStorage->isStorageElement( *pIter ) ))
1518 uno::Reference< util::XModifiable > xModifiable( xObj->getComponent(), uno::UNO_QUERY );
1519 if ( xModifiable.is() && xModifiable->isModified())
1521 xPersist->storeOwn();
1523 else
1525 //do nothing.embeded model is not modified, no need to persist.
1528 else //the embeded object is in active status, always store back it.
1530 xPersist->storeOwn();
1532 //end i120168
1534 catch (const uno::Exception&)
1536 // TODO/LATER: error handling
1537 bResult = sal_False;
1538 break;
1542 if ( !_bOasisFormat && !_bObjectsOnly )
1544 // copy replacement images for linked objects
1547 uno::Reference< embed::XLinkageSupport > xLink( xObj, uno::UNO_QUERY );
1548 if ( xLink.is() && xLink->isLink() )
1550 OUString aMediaType;
1551 uno::Reference < io::XInputStream > xInStream = GetGraphicStream( xObj, &aMediaType );
1552 if ( xInStream.is() )
1553 InsertStreamIntoPicturesStorage_Impl( pImpl->mxStorage, xInStream, *pIter );
1556 catch (const uno::Exception&)
1563 if ( bResult && _bOasisFormat )
1564 bResult = CommitImageSubStorage();
1566 if ( bResult && !_bObjectsOnly )
1570 ReleaseImageSubStorage();
1571 OUString aObjReplElement( "ObjectReplacements" );
1572 if ( !_bOasisFormat && pImpl->mxStorage->hasByName( aObjReplElement ) && pImpl->mxStorage->isStorageElement( aObjReplElement ) )
1573 pImpl->mxStorage->removeElement( aObjReplElement );
1575 catch (const uno::Exception&)
1577 // TODO/LATER: error handling
1578 bResult = sal_False;
1581 return bResult;
1583 // -----------------------------------------------------------------------------
1584 uno::Reference< io::XInputStream > EmbeddedObjectContainer::GetGraphicReplacementStream(
1585 sal_Int64 nViewAspect,
1586 const uno::Reference< embed::XEmbeddedObject >& xObj,
1587 OUString* pMediaType )
1589 uno::Reference< io::XInputStream > xInStream;
1590 if ( xObj.is() )
1594 // retrieving of the visual representation can switch object to running state
1595 embed::VisualRepresentation aRep = xObj->getPreferredVisualRepresentation( nViewAspect );
1596 if ( pMediaType )
1597 *pMediaType = aRep.Flavor.MimeType;
1599 uno::Sequence < sal_Int8 > aSeq;
1600 aRep.Data >>= aSeq;
1601 xInStream = new ::comphelper::SequenceInputStream( aSeq );
1603 catch (const uno::Exception&)
1608 return xInStream;
1610 // -----------------------------------------------------------------------------
1611 sal_Bool EmbeddedObjectContainer::SetPersistentEntries(const uno::Reference< embed::XStorage >& _xStorage,bool _bClearModifedFlag)
1613 sal_Bool bError = sal_False;
1614 const uno::Sequence < OUString > aNames = GetObjectNames();
1615 const OUString* pIter = aNames.getConstArray();
1616 const OUString* pEnd = pIter + aNames.getLength();
1617 for(;pIter != pEnd;++pIter)
1619 uno::Reference < embed::XEmbeddedObject > xObj = GetEmbeddedObject( *pIter );
1620 SAL_WARN_IF( !xObj.is(), "comphelper.container", "An empty entry in the embedded objects list!\n" );
1621 if ( xObj.is() )
1623 uno::Reference< embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
1624 if ( xPersist.is() )
1628 xPersist->setPersistentEntry( _xStorage,
1629 *pIter,
1630 embed::EntryInitModes::NO_INIT,
1631 uno::Sequence< beans::PropertyValue >(),
1632 uno::Sequence< beans::PropertyValue >() );
1635 catch (const uno::Exception&)
1637 // TODO/LATER: error handling
1638 bError = sal_True;
1639 break;
1642 if ( _bClearModifedFlag )
1644 // if this method is used as part of SaveCompleted the object must stay unmodified after execution
1647 uno::Reference< util::XModifiable > xModif( xObj->getComponent(), uno::UNO_QUERY_THROW );
1648 if ( xModif->isModified() )
1649 xModif->setModified( sal_False );
1651 catch (const uno::Exception&)
1657 return bError;
1661 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */