CWS-TOOLING: integrate CWS os146
[LibreOffice.git] / comphelper / source / container / embeddedobjectcontainer.cxx
blob17740e7ef09bf8700ae8352d1b1e7452b4b99143
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_comphelper.hxx"
30 #include <com/sun/star/container/XChild.hpp>
31 #include <com/sun/star/container/XNameAccess.hpp>
32 #include <com/sun/star/embed/XEmbedObjectCreator.hpp>
33 #include <com/sun/star/embed/XLinkCreator.hpp>
34 #include <com/sun/star/embed/XEmbedPersist.hpp>
35 #include <com/sun/star/embed/XLinkageSupport.hpp>
36 #include <com/sun/star/embed/XTransactedObject.hpp>
37 #include <com/sun/star/embed/XOptimizedStorage.hpp>
38 #include <com/sun/star/embed/EntryInitModes.hpp>
39 #include <com/sun/star/util/XCloseable.hpp>
40 #include <com/sun/star/util/XModifiable.hpp>
41 #include <com/sun/star/embed/EmbedStates.hpp>
42 #include <com/sun/star/datatransfer/XTransferable.hpp>
43 #include <com/sun/star/beans/XPropertySetInfo.hpp>
44 #include <com/sun/star/beans/XPropertySet.hpp>
45 #include <com/sun/star/embed/Aspects.hpp>
46 #include <com/sun/star/embed/EmbedMisc.hpp>
48 #include <comphelper/seqstream.hxx>
49 #include <comphelper/processfactory.hxx>
50 #include <comphelper/storagehelper.hxx>
51 #include <comphelper/embeddedobjectcontainer.hxx>
52 #include <comphelper/sequence.hxx>
53 #include <cppuhelper/weakref.hxx>
54 #include <hash_map>
55 #include <algorithm>
57 #include <rtl/logfile.hxx>
59 using namespace ::com::sun::star;
61 namespace comphelper
64 struct hashObjectName_Impl
66 size_t operator()(const ::rtl::OUString Str) const
68 return (size_t)Str.hashCode();
72 struct eqObjectName_Impl
74 sal_Bool operator()(const ::rtl::OUString Str1, const ::rtl::OUString Str2) const
76 return ( Str1 == Str2 );
80 typedef std::hash_map
82 ::rtl::OUString,
83 ::com::sun::star::uno::Reference < com::sun::star::embed::XEmbeddedObject >,
84 hashObjectName_Impl,
85 eqObjectName_Impl
87 EmbeddedObjectContainerNameMap;
89 struct EmbedImpl
91 // TODO/LATER: remove objects from temp. Container storage when object is disposed
92 EmbeddedObjectContainerNameMap maObjectContainer;
93 uno::Reference < embed::XStorage > mxStorage;
94 EmbeddedObjectContainer* mpTempObjectContainer;
95 uno::Reference < embed::XStorage > mxImageStorage;
96 uno::WeakReference < uno::XInterface > m_xModel;
97 //EmbeddedObjectContainerNameMap maTempObjectContainer;
98 //uno::Reference < embed::XStorage > mxTempStorage;
99 sal_Bool bOwnsStorage;
101 const uno::Reference < embed::XStorage >& GetReplacements();
104 const uno::Reference < embed::XStorage >& EmbedImpl::GetReplacements()
106 if ( !mxImageStorage.is() )
110 mxImageStorage = mxStorage->openStorageElement(
111 ::rtl::OUString::createFromAscii( "ObjectReplacements" ), embed::ElementModes::READWRITE );
113 catch ( uno::Exception& )
115 mxImageStorage = mxStorage->openStorageElement(
116 ::rtl::OUString::createFromAscii( "ObjectReplacements" ), embed::ElementModes::READ );
120 if ( !mxImageStorage.is() )
121 throw io::IOException();
123 return mxImageStorage;
126 EmbeddedObjectContainer::EmbeddedObjectContainer()
128 pImpl = new EmbedImpl;
129 pImpl->mxStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
130 pImpl->bOwnsStorage = sal_True;
131 pImpl->mpTempObjectContainer = 0;
134 EmbeddedObjectContainer::EmbeddedObjectContainer( const uno::Reference < embed::XStorage >& rStor )
136 pImpl = new EmbedImpl;
137 pImpl->mxStorage = rStor;
138 pImpl->bOwnsStorage = sal_False;
139 pImpl->mpTempObjectContainer = 0;
142 EmbeddedObjectContainer::EmbeddedObjectContainer( const uno::Reference < embed::XStorage >& rStor, const uno::Reference < uno::XInterface >& xModel )
144 pImpl = new EmbedImpl;
145 pImpl->mxStorage = rStor;
146 pImpl->bOwnsStorage = sal_False;
147 pImpl->mpTempObjectContainer = 0;
148 pImpl->m_xModel = xModel;
151 void EmbeddedObjectContainer::SwitchPersistence( const uno::Reference < embed::XStorage >& rStor )
153 ReleaseImageSubStorage();
155 if ( pImpl->bOwnsStorage )
156 pImpl->mxStorage->dispose();
158 pImpl->mxStorage = rStor;
159 pImpl->bOwnsStorage = sal_False;
162 sal_Bool EmbeddedObjectContainer::CommitImageSubStorage()
164 if ( pImpl->mxImageStorage.is() )
168 sal_Bool bReadOnlyMode = sal_True;
169 uno::Reference < beans::XPropertySet > xSet(pImpl->mxImageStorage,uno::UNO_QUERY);
170 if ( xSet.is() )
172 // get the open mode from the parent storage
173 sal_Int32 nMode = 0;
174 uno::Any aAny = xSet->getPropertyValue( ::rtl::OUString::createFromAscii("OpenMode") );
175 if ( aAny >>= nMode )
176 bReadOnlyMode = !(nMode & embed::ElementModes::WRITE );
177 } // if ( xSet.is() )
178 if ( !bReadOnlyMode )
180 uno::Reference< embed::XTransactedObject > xTransact( pImpl->mxImageStorage, uno::UNO_QUERY_THROW );
181 xTransact->commit();
184 catch( uno::Exception& )
186 return sal_False;
190 return sal_True;
193 void EmbeddedObjectContainer::ReleaseImageSubStorage()
195 CommitImageSubStorage();
197 if ( pImpl->mxImageStorage.is() )
201 pImpl->mxImageStorage->dispose();
202 pImpl->mxImageStorage = uno::Reference< embed::XStorage >();
204 catch( uno::Exception& )
206 OSL_ASSERT( "Problems releasing image substorage!\n" );
211 EmbeddedObjectContainer::~EmbeddedObjectContainer()
213 ReleaseImageSubStorage();
215 if ( pImpl->bOwnsStorage )
216 pImpl->mxStorage->dispose();
218 delete pImpl->mpTempObjectContainer;
219 delete pImpl;
222 void EmbeddedObjectContainer::CloseEmbeddedObjects()
224 EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin();
225 while ( aIt != pImpl->maObjectContainer.end() )
227 uno::Reference < util::XCloseable > xClose( (*aIt).second, uno::UNO_QUERY );
228 if ( xClose.is() )
232 xClose->close( sal_True );
234 catch ( uno::Exception& )
239 aIt++;
243 ::rtl::OUString EmbeddedObjectContainer::CreateUniqueObjectName()
245 ::rtl::OUString aPersistName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Object ") );
246 ::rtl::OUString aStr;
247 sal_Int32 i=1;
250 aStr = aPersistName;
251 aStr += ::rtl::OUString::valueOf( i++ );
253 while( HasEmbeddedObject( aStr ) );
254 // TODO/LATER: should we consider deleted objects?
256 return aStr;
259 uno::Sequence < ::rtl::OUString > EmbeddedObjectContainer::GetObjectNames()
261 uno::Sequence < ::rtl::OUString > aSeq( pImpl->maObjectContainer.size() );
262 EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin();
263 sal_Int32 nIdx=0;
264 while ( aIt != pImpl->maObjectContainer.end() )
265 aSeq[nIdx++] = (*aIt++).first;
266 return aSeq;
269 sal_Bool EmbeddedObjectContainer::HasEmbeddedObjects()
271 return pImpl->maObjectContainer.size() != 0;
274 sal_Bool EmbeddedObjectContainer::HasEmbeddedObject( const ::rtl::OUString& rName )
276 EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.find( rName );
277 if ( aIt == pImpl->maObjectContainer.end() )
279 uno::Reference < container::XNameAccess > xAccess( pImpl->mxStorage, uno::UNO_QUERY );
280 return xAccess->hasByName(rName);
282 else
283 return sal_True;
286 sal_Bool EmbeddedObjectContainer::HasEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj )
288 EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin();
289 while ( aIt != pImpl->maObjectContainer.end() )
291 if ( (*aIt).second == xObj )
292 return sal_True;
293 else
294 aIt++;
297 return sal_False;
300 sal_Bool EmbeddedObjectContainer::HasInstantiatedEmbeddedObject( const ::rtl::OUString& rName )
302 // allows to detect whether the object was already instantiated
303 // currently the filter instantiate it on loading, so this method allows
304 // to avoid objects pointing to the same persistence
305 EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.find( rName );
306 return ( aIt != pImpl->maObjectContainer.end() );
309 ::rtl::OUString EmbeddedObjectContainer::GetEmbeddedObjectName( const ::com::sun::star::uno::Reference < ::com::sun::star::embed::XEmbeddedObject >& xObj )
311 EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin();
312 while ( aIt != pImpl->maObjectContainer.end() )
314 if ( (*aIt).second == xObj )
315 return (*aIt).first;
316 else
317 aIt++;
320 OSL_ENSURE( 0, "Unknown object!" );
321 return ::rtl::OUString();
324 uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::GetEmbeddedObject( const ::rtl::OUString& rName )
326 RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::GetEmbeddedObject" );
328 OSL_ENSURE( rName.getLength(), "Empty object name!");
330 uno::Reference < embed::XEmbeddedObject > xObj;
331 EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.find( rName );
333 #if OSL_DEBUG_LEVEL > 1
334 uno::Reference < container::XNameAccess > xAccess( pImpl->mxStorage, uno::UNO_QUERY );
335 uno::Sequence< ::rtl::OUString> aSeq = xAccess->getElementNames();
336 const ::rtl::OUString* pIter = aSeq.getConstArray();
337 const ::rtl::OUString* pEnd = pIter + aSeq.getLength();
338 for(;pIter != pEnd;++pIter)
340 (void)*pIter;
342 OSL_ENSURE( aIt != pImpl->maObjectContainer.end() || xAccess->hasByName(rName), "Could not return object!" );
343 #endif
345 // check if object was already created
346 if ( aIt != pImpl->maObjectContainer.end() )
347 xObj = (*aIt).second;
348 else
349 xObj = Get_Impl( rName, uno::Reference < embed::XEmbeddedObject >() );
351 return xObj;
354 uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::Get_Impl( const ::rtl::OUString& rName, const uno::Reference < embed::XEmbeddedObject >& xCopy )
356 uno::Reference < embed::XEmbeddedObject > xObj;
359 // create the object from the storage
360 uno::Reference < beans::XPropertySet > xSet( pImpl->mxStorage, uno::UNO_QUERY );
361 sal_Bool bReadOnlyMode = sal_True;
362 if ( xSet.is() )
364 // get the open mode from the parent storage
365 sal_Int32 nMode = 0;
366 uno::Any aAny = xSet->getPropertyValue( ::rtl::OUString::createFromAscii("OpenMode") );
367 if ( aAny >>= nMode )
368 bReadOnlyMode = !(nMode & embed::ElementModes::WRITE );
371 // object was not added until now - should happen only by calling this method from "inside"
372 //TODO/LATER: it would be good to detect an error when an object should be created already, but isn't (not an "inside" call)
373 uno::Reference < embed::XEmbedObjectCreator > xFactory( ::comphelper::getProcessServiceFactory()->createInstance(
374 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.embed.EmbeddedObjectCreator")) ), uno::UNO_QUERY );
375 uno::Sequence< beans::PropertyValue > aObjDescr( xCopy.is() ? 2 : 1 );
376 aObjDescr[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Parent" ) );
377 aObjDescr[0].Value <<= pImpl->m_xModel.get();
378 if ( xCopy.is() )
380 aObjDescr[1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CloneFrom" ) );
381 aObjDescr[1].Value <<= xCopy;
384 uno::Sequence< beans::PropertyValue > aMediaDescr( 1 );
385 aMediaDescr[0].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ReadOnly"));
386 aMediaDescr[0].Value <<= bReadOnlyMode;
387 xObj = uno::Reference < embed::XEmbeddedObject >( xFactory->createInstanceInitFromEntry(
388 pImpl->mxStorage, rName,
389 aMediaDescr, aObjDescr ), uno::UNO_QUERY );
391 // insert object into my list
392 AddEmbeddedObject( xObj, rName );
394 catch ( uno::Exception& )
398 return xObj;
401 uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::CreateEmbeddedObject( const uno::Sequence < sal_Int8 >& rClassId,
402 const uno::Sequence < beans::PropertyValue >& rArgs, ::rtl::OUString& rNewName )
404 RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::CreateEmbeddedObject" );
406 if ( !rNewName.getLength() )
407 rNewName = CreateUniqueObjectName();
409 OSL_ENSURE( !HasEmbeddedObject(rNewName), "Object to create already exists!");
411 // create object from classid by inserting it into storage
412 uno::Reference < embed::XEmbeddedObject > xObj;
415 uno::Reference < embed::XEmbedObjectCreator > xFactory( ::comphelper::getProcessServiceFactory()->createInstance(
416 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.embed.EmbeddedObjectCreator")) ), uno::UNO_QUERY );
418 uno::Sequence< beans::PropertyValue > aObjDescr( rArgs.getLength() + 1 );
419 aObjDescr[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Parent" ) );
420 aObjDescr[0].Value <<= pImpl->m_xModel.get();
421 ::std::copy( rArgs.getConstArray(), rArgs.getConstArray() + rArgs.getLength(), aObjDescr.getArray() + 1 );
422 xObj = uno::Reference < embed::XEmbeddedObject >( xFactory->createInstanceInitNew(
423 rClassId, ::rtl::OUString(), pImpl->mxStorage, rNewName,
424 aObjDescr ), uno::UNO_QUERY );
426 AddEmbeddedObject( xObj, rNewName );
428 OSL_ENSURE( !xObj.is() || xObj->getCurrentState() != embed::EmbedStates::LOADED,
429 "A freshly create object should be running always!\n" );
431 catch ( uno::Exception& )
435 return xObj;
438 uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::CreateEmbeddedObject( const uno::Sequence < sal_Int8 >& rClassId, ::rtl::OUString& rNewName )
440 return CreateEmbeddedObject( rClassId, uno::Sequence < beans::PropertyValue >(), rNewName );
443 void EmbeddedObjectContainer::AddEmbeddedObject( const ::com::sun::star::uno::Reference < ::com::sun::star::embed::XEmbeddedObject >& xObj, const ::rtl::OUString& rName )
445 RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::AddEmbeddedObject" );
447 #if OSL_DEBUG_LEVEL > 1
448 OSL_ENSURE( rName.getLength(), "Added object doesn't have a name!");
449 uno::Reference < container::XNameAccess > xAccess( pImpl->mxStorage, uno::UNO_QUERY );
450 uno::Reference < embed::XEmbedPersist > xEmb( xObj, uno::UNO_QUERY );
451 uno::Reference < embed::XLinkageSupport > xLink( xEmb, uno::UNO_QUERY );
452 // if the object has a persistance and the object is not a link than it must have persistence entry in the storage
453 OSL_ENSURE( !( xEmb.is() && ( !xLink.is() || !xLink->isLink() ) ) || xAccess->hasByName(rName),
454 "Added element not in storage!" );
455 #endif
457 // remember object - it needs to be in storage already
458 EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.find( rName );
459 OSL_ENSURE( aIt == pImpl->maObjectContainer.end(), "Element already inserted!" );
460 pImpl->maObjectContainer[ rName ] = xObj;
461 uno::Reference < container::XChild > xChild( xObj, uno::UNO_QUERY );
462 if ( xChild.is() && xChild->getParent() != pImpl->m_xModel.get() )
463 xChild->setParent( pImpl->m_xModel.get() );
465 // look for object in temorary container
466 if ( pImpl->mpTempObjectContainer )
468 aIt = pImpl->mpTempObjectContainer->pImpl->maObjectContainer.begin();
469 while ( aIt != pImpl->mpTempObjectContainer->pImpl->maObjectContainer.end() )
471 if ( (*aIt).second == xObj )
473 // copy replacement image from temporary container (if there is any)
474 ::rtl::OUString aTempName = (*aIt).first;
475 ::rtl::OUString aMediaType;
476 uno::Reference < io::XInputStream > xStream = pImpl->mpTempObjectContainer->GetGraphicStream( xObj, &aMediaType );
477 if ( xStream.is() )
479 InsertGraphicStream( xStream, rName, aMediaType );
480 xStream = 0;
481 pImpl->mpTempObjectContainer->RemoveGraphicStream( aTempName );
484 // remove object from storage of temporary container
485 uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
486 if ( xPersist.is() )
490 pImpl->mpTempObjectContainer->pImpl->mxStorage->removeElement( aTempName );
492 catch ( uno::Exception& )
497 // temp. container needs to forget the object
498 pImpl->mpTempObjectContainer->pImpl->maObjectContainer.erase( aIt );
499 break;
501 else
502 aIt++;
507 sal_Bool EmbeddedObjectContainer::StoreEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj, ::rtl::OUString& rName, sal_Bool bCopy )
509 RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::StoreEmbeddedObject" );
511 uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
512 if ( !rName.getLength() )
513 rName = CreateUniqueObjectName();
515 #if OSL_DEBUG_LEVEL > 1
516 uno::Reference < container::XNameAccess > xAccess( pImpl->mxStorage, uno::UNO_QUERY );
517 OSL_ENSURE( !xPersist.is() || !xAccess->hasByName(rName), "Inserting element already present in storage!" );
518 OSL_ENSURE( xPersist.is() || xObj->getCurrentState() == embed::EmbedStates::RUNNING, "Non persistent object inserted!");
519 #endif
521 // insert objects' storage into the container storage (if object has one)
524 if ( xPersist.is() )
526 uno::Sequence < beans::PropertyValue > aSeq;
527 if ( bCopy )
528 xPersist->storeToEntry( pImpl->mxStorage, rName, aSeq, aSeq );
529 else
531 //TODO/LATER: possible optimisation, don't store immediately
532 //xPersist->setPersistentEntry( pImpl->mxStorage, rName, embed::EntryInitModes::ENTRY_NO_INIT, aSeq, aSeq );
533 xPersist->storeAsEntry( pImpl->mxStorage, rName, aSeq, aSeq );
534 xPersist->saveCompleted( sal_True );
538 catch ( uno::Exception& )
540 // TODO/LATER: better error recovery should keep storage intact
541 return sal_False;
544 return sal_True;
547 sal_Bool EmbeddedObjectContainer::InsertEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj, ::rtl::OUString& rName )
549 RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertEmbeddedObject( Object )" );
550 // store it into the container storage
551 if ( StoreEmbeddedObject( xObj, rName, sal_False ) )
553 // remember object
554 AddEmbeddedObject( xObj, rName );
555 return sal_True;
557 else
558 return sal_False;
561 uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::InsertEmbeddedObject( const uno::Reference < io::XInputStream >& xStm, ::rtl::OUString& rNewName )
563 RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertEmbeddedObject( InputStream )" );
565 if ( !rNewName.getLength() )
566 rNewName = CreateUniqueObjectName();
568 // store it into the container storage
569 sal_Bool bIsStorage = sal_False;
572 // first try storage persistence
573 uno::Reference < embed::XStorage > xStore = ::comphelper::OStorageHelper::GetStorageFromInputStream( xStm );
575 // storage was created from stream successfully
576 bIsStorage = sal_True;
578 uno::Reference < embed::XStorage > xNewStore = pImpl->mxStorage->openStorageElement( rNewName, embed::ElementModes::READWRITE );
579 xStore->copyToStorage( xNewStore );
581 catch ( uno::Exception& )
583 if ( bIsStorage )
584 // it is storage persistence, but opening of new substorage or copying to it failed
585 return uno::Reference < embed::XEmbeddedObject >();
587 // stream didn't contain a storage, now try stream persistence
590 uno::Reference < io::XStream > xNewStream = pImpl->mxStorage->openStreamElement( rNewName, embed::ElementModes::READWRITE );
591 ::comphelper::OStorageHelper::CopyInputToOutput( xStm, xNewStream->getOutputStream() );
593 // No mediatype is provided so the default for OLE objects value is used
594 // it is correct so for now, but what if somebody introduces a new stream based embedded object?
595 // Probably introducing of such an object must be restricted ( a storage must be used! ).
596 uno::Reference< beans::XPropertySet > xProps( xNewStream, uno::UNO_QUERY_THROW );
597 xProps->setPropertyValue(
598 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ),
599 uno::makeAny( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "application/vnd.sun.star.oleobject" ) ) ) );
601 catch ( uno::Exception& )
603 // complete disaster!
604 return uno::Reference < embed::XEmbeddedObject >();
608 // stream was copied into the container storage in either way, now try to open something form it
609 uno::Reference < embed::XEmbeddedObject > xRet = GetEmbeddedObject( rNewName );
612 if ( !xRet.is() )
613 // no object could be created, so withdraw insertion
614 pImpl->mxStorage->removeElement( rNewName );
616 catch ( uno::Exception& )
620 return xRet;
623 uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::InsertEmbeddedObject( const ::com::sun::star::uno::Sequence < ::com::sun::star::beans::PropertyValue >& aMedium, ::rtl::OUString& rNewName )
625 RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertEmbeddedObject( MediaDescriptor )" );
627 if ( !rNewName.getLength() )
628 rNewName = CreateUniqueObjectName();
630 uno::Reference < embed::XEmbeddedObject > xObj;
633 uno::Reference < embed::XEmbedObjectCreator > xFactory( ::comphelper::getProcessServiceFactory()->createInstance(
634 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.embed.EmbeddedObjectCreator")) ), uno::UNO_QUERY );
635 uno::Sequence< beans::PropertyValue > aObjDescr( 1 );
636 aObjDescr[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Parent" ) );
637 aObjDescr[0].Value <<= pImpl->m_xModel.get();
638 xObj = uno::Reference < embed::XEmbeddedObject >( xFactory->createInstanceInitFromMediaDescriptor(
639 pImpl->mxStorage, rNewName, aMedium, aObjDescr ), uno::UNO_QUERY );
640 uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
642 OSL_ENSURE( !xObj.is() || xObj->getCurrentState() != embed::EmbedStates::LOADED,
643 "A freshly create object should be running always!\n" );
645 // possible optimization: store later!
646 if ( xPersist.is())
647 xPersist->storeOwn();
649 AddEmbeddedObject( xObj, rNewName );
651 catch ( uno::Exception& )
655 return xObj;
658 uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::InsertEmbeddedLink( const ::com::sun::star::uno::Sequence < ::com::sun::star::beans::PropertyValue >& aMedium, ::rtl::OUString& rNewName )
660 RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertEmbeddedLink" );
662 if ( !rNewName.getLength() )
663 rNewName = CreateUniqueObjectName();
665 uno::Reference < embed::XEmbeddedObject > xObj;
668 uno::Reference < embed::XLinkCreator > xFactory( ::comphelper::getProcessServiceFactory()->createInstance(
669 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.embed.EmbeddedObjectCreator")) ), uno::UNO_QUERY );
670 uno::Sequence< beans::PropertyValue > aObjDescr( 1 );
671 aObjDescr[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Parent" ) );
672 aObjDescr[0].Value <<= pImpl->m_xModel.get();
673 xObj = uno::Reference < embed::XEmbeddedObject >( xFactory->createInstanceLink(
674 pImpl->mxStorage, rNewName, aMedium, aObjDescr ), uno::UNO_QUERY );
676 uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
678 OSL_ENSURE( !xObj.is() || xObj->getCurrentState() != embed::EmbedStates::LOADED,
679 "A freshly create object should be running always!\n" );
681 // possible optimization: store later!
682 if ( xPersist.is())
683 xPersist->storeOwn();
685 AddEmbeddedObject( xObj, rNewName );
687 catch ( uno::Exception& )
691 return xObj;
694 sal_Bool EmbeddedObjectContainer::TryToCopyGraphReplacement( EmbeddedObjectContainer& rSrc,
695 const ::rtl::OUString& aOrigName,
696 const ::rtl::OUString& aTargetName )
698 RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::TryToCopyGraphReplacement" );
700 sal_Bool bResult = sal_False;
702 if ( ( &rSrc != this || !aOrigName.equals( aTargetName ) ) && aOrigName.getLength() && aTargetName.getLength() )
704 ::rtl::OUString aMediaType;
705 uno::Reference < io::XInputStream > xGrStream = rSrc.GetGraphicStream( aOrigName, &aMediaType );
706 if ( xGrStream.is() )
707 bResult = InsertGraphicStream( xGrStream, aTargetName, aMediaType );
710 return bResult;
713 sal_Bool EmbeddedObjectContainer::CopyEmbeddedObject( EmbeddedObjectContainer& rSrc, const uno::Reference < embed::XEmbeddedObject >& xObj, ::rtl::OUString& rName )
715 RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::CopyEmbeddedObject" );
717 OSL_ENSURE( sal_False,
718 "This method is depricated! Use EmbeddedObjectContainer::CopyAndGetEmbeddedObject() to copy object!\n" );
720 // get the object name before(!) it is assigned to a new storage
721 ::rtl::OUString aOrigName;
722 uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
723 if ( xPersist.is() )
724 aOrigName = xPersist->getEntryName();
726 if ( !rName.getLength() )
727 rName = CreateUniqueObjectName();
729 if ( StoreEmbeddedObject( xObj, rName, sal_True ) )
731 TryToCopyGraphReplacement( rSrc, aOrigName, rName );
732 return sal_True;
735 return sal_False;
738 uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::CopyAndGetEmbeddedObject( EmbeddedObjectContainer& rSrc, const uno::Reference < embed::XEmbeddedObject >& xObj, ::rtl::OUString& rName )
740 RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::CopyAndGetEmbeddedObject" );
742 uno::Reference< embed::XEmbeddedObject > xResult;
744 // TODO/LATER: For now only objects that implement XEmbedPersist have a replacement image, it might change in future
745 // do an incompatible change so that object name is provided in all the move and copy methods
746 ::rtl::OUString aOrigName;
749 uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY_THROW );
750 aOrigName = xPersist->getEntryName();
752 catch( uno::Exception& )
755 if ( !rName.getLength() )
756 rName = CreateUniqueObjectName();
758 // objects without persistance are not really stored by the method
759 if ( xObj.is() && StoreEmbeddedObject( xObj, rName, sal_True ) )
761 xResult = Get_Impl( rName, xObj);
762 if ( !xResult.is() )
764 // this is a case when object has no real persistence
765 // in such cases a new object should be explicitly created and initialized with the data of the old one
768 uno::Reference< embed::XLinkageSupport > xOrigLinkage( xObj, uno::UNO_QUERY );
769 if ( xOrigLinkage.is() && xOrigLinkage->isLink() )
771 // this is a OOo link, it has no persistence
772 ::rtl::OUString aURL = xOrigLinkage->getLinkURL();
773 if ( !aURL.getLength() )
774 throw uno::RuntimeException();
776 // create new linked object from the URL the link is based on
777 uno::Reference < embed::XLinkCreator > xCreator(
778 ::comphelper::getProcessServiceFactory()->createInstance(
779 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.embed.EmbeddedObjectCreator") ) ),
780 uno::UNO_QUERY_THROW );
782 uno::Sequence< beans::PropertyValue > aMediaDescr( 1 );
783 aMediaDescr[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "URL" ) );
784 aMediaDescr[0].Value <<= aURL;
785 uno::Sequence< beans::PropertyValue > aObjDescr( 1 );
786 aObjDescr[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Parent" ) );
787 aObjDescr[0].Value <<= pImpl->m_xModel.get();
788 xResult = uno::Reference < embed::XEmbeddedObject >(
789 xCreator->createInstanceLink(
790 pImpl->mxStorage,
791 rName,
792 aMediaDescr,
793 aObjDescr ),
794 uno::UNO_QUERY_THROW );
796 else
798 // the component is required for copying of this object
799 if ( xObj->getCurrentState() == embed::EmbedStates::LOADED )
800 xObj->changeState( embed::EmbedStates::RUNNING );
802 // this must be an object based on properties, otherwise we can not copy it currently
803 uno::Reference< beans::XPropertySet > xOrigProps( xObj->getComponent(), uno::UNO_QUERY_THROW );
805 // use object class ID to create a new one and tranfer all the properties
806 uno::Reference < embed::XEmbedObjectCreator > xCreator(
807 ::comphelper::getProcessServiceFactory()->createInstance(
808 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.embed.EmbeddedObjectCreator") ) ),
809 uno::UNO_QUERY_THROW );
811 uno::Sequence< beans::PropertyValue > aObjDescr( 1 );
812 aObjDescr[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Parent" ) );
813 aObjDescr[0].Value <<= pImpl->m_xModel.get();
814 xResult = uno::Reference < embed::XEmbeddedObject >(
815 xCreator->createInstanceInitNew(
816 xObj->getClassID(),
817 xObj->getClassName(),
818 pImpl->mxStorage,
819 rName,
820 aObjDescr ),
821 uno::UNO_QUERY_THROW );
823 if ( xResult->getCurrentState() == embed::EmbedStates::LOADED )
824 xResult->changeState( embed::EmbedStates::RUNNING );
826 uno::Reference< beans::XPropertySet > xTargetProps( xResult->getComponent(), uno::UNO_QUERY_THROW );
828 // copy all the properties from xOrigProps to xTargetProps
829 uno::Reference< beans::XPropertySetInfo > xOrigInfo = xOrigProps->getPropertySetInfo();
830 if ( !xOrigInfo.is() )
831 throw uno::RuntimeException();
833 uno::Sequence< beans::Property > aPropertiesList = xOrigInfo->getProperties();
834 for ( sal_Int32 nInd = 0; nInd < aPropertiesList.getLength(); nInd++ )
838 xTargetProps->setPropertyValue(
839 aPropertiesList[nInd].Name,
840 xOrigProps->getPropertyValue( aPropertiesList[nInd].Name ) );
842 catch( beans::PropertyVetoException& )
844 // impossibility to copy readonly property is not treated as an error for now
845 // but the assertion is helpful to detect such scenarios and review them
846 OSL_ENSURE( sal_False, "Could not copy readonly property!\n" );
851 if ( xResult.is() )
852 AddEmbeddedObject( xResult, rName );
854 catch( uno::Exception& )
856 if ( xResult.is() )
860 xResult->close( sal_True );
862 catch( uno::Exception& )
864 xResult = uno::Reference< embed::XEmbeddedObject >();
870 OSL_ENSURE( xResult.is(), "Can not copy embedded object that has no persistance!\n" );
872 if ( xResult.is() )
874 // the object is successfully copied, try to copy graphical replacement
875 if ( aOrigName.getLength() )
876 TryToCopyGraphReplacement( rSrc, aOrigName, rName );
878 // the object might need the size to be set
881 if ( xResult->getStatus( embed::Aspects::MSOLE_CONTENT ) & embed::EmbedMisc::EMBED_NEEDSSIZEONLOAD )
882 xResult->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT,
883 xObj->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT ) );
885 catch( uno::Exception& )
889 return xResult;
892 sal_Bool EmbeddedObjectContainer::MoveEmbeddedObject( EmbeddedObjectContainer& rSrc, const uno::Reference < embed::XEmbeddedObject >& xObj, ::rtl::OUString& rName )
894 RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::MoveEmbeddedObject( Object )" );
896 // get the object name before(!) it is assigned to a new storage
897 uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
898 ::rtl::OUString aName;
899 if ( xPersist.is() )
900 aName = xPersist->getEntryName();
902 // now move the object to the new container; the returned name is the new persist name in this container
903 sal_Bool bRet;
907 bRet = InsertEmbeddedObject( xObj, rName );
908 if ( bRet )
909 TryToCopyGraphReplacement( rSrc, aName, rName );
911 catch ( uno::Exception& e )
913 (void)e;
914 OSL_ENSURE( sal_False, "Failed to insert embedded object into storage!" );
915 bRet = sal_False;
918 if ( bRet )
920 // now remove the object from the former container
921 bRet = sal_False;
922 EmbeddedObjectContainerNameMap::iterator aIt = rSrc.pImpl->maObjectContainer.begin();
923 while ( aIt != rSrc.pImpl->maObjectContainer.end() )
925 if ( (*aIt).second == xObj )
927 rSrc.pImpl->maObjectContainer.erase( aIt );
928 bRet = sal_True;
929 break;
932 aIt++;
935 OSL_ENSURE( bRet, "Object not found for removal!" );
936 if ( xPersist.is() )
938 // now it's time to remove the storage from the container storage
941 if ( xPersist.is() )
942 rSrc.pImpl->mxStorage->removeElement( aName );
944 catch ( uno::Exception& )
946 OSL_ENSURE( sal_False, "Failed to remove object from storage!" );
947 bRet = sal_False;
951 // rSrc.RemoveGraphicStream( aName );
954 return bRet;
957 sal_Bool EmbeddedObjectContainer::RemoveEmbeddedObject( const ::rtl::OUString& rName, sal_Bool bClose )
959 RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::RemoveEmbeddedObject( Name )" );
961 uno::Reference < embed::XEmbeddedObject > xObj = GetEmbeddedObject( rName );
962 if ( xObj.is() )
963 return RemoveEmbeddedObject( xObj, bClose );
964 else
965 return sal_False;
968 sal_Bool EmbeddedObjectContainer::MoveEmbeddedObject( const ::rtl::OUString& rName, EmbeddedObjectContainer& rCnt )
970 RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::MoveEmbeddedObject( Name )" );
972 // find object entry
973 EmbeddedObjectContainerNameMap::iterator aIt2 = rCnt.pImpl->maObjectContainer.find( rName );
974 OSL_ENSURE( aIt2 == rCnt.pImpl->maObjectContainer.end(), "Object does already exist in target container!" );
976 if ( aIt2 != rCnt.pImpl->maObjectContainer.end() )
977 return sal_False;
979 uno::Reference < embed::XEmbeddedObject > xObj;
980 EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.find( rName );
981 if ( aIt != pImpl->maObjectContainer.end() )
983 xObj = (*aIt).second;
986 if ( xObj.is() )
988 // move object
989 ::rtl::OUString aName( rName );
990 rCnt.InsertEmbeddedObject( xObj, aName );
991 pImpl->maObjectContainer.erase( aIt );
992 uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
993 if ( xPersist.is() )
994 pImpl->mxStorage->removeElement( rName );
996 else
998 // copy storages; object *must* have persistence!
999 uno::Reference < embed::XStorage > xOld = pImpl->mxStorage->openStorageElement( rName, embed::ElementModes::READ );
1000 uno::Reference < embed::XStorage > xNew = rCnt.pImpl->mxStorage->openStorageElement( rName, embed::ElementModes::READWRITE );
1001 xOld->copyToStorage( xNew );
1004 rCnt.TryToCopyGraphReplacement( *this, rName, rName );
1005 // RemoveGraphicStream( rName );
1007 return sal_True;
1009 catch ( uno::Exception& )
1011 OSL_ENSURE(0,"Could not move object!");
1012 return sal_False;
1016 else
1017 OSL_ENSURE(0,"Unknown object!");
1018 return sal_False;
1021 sal_Bool EmbeddedObjectContainer::RemoveEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj, sal_Bool bClose )
1023 RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::RemoveEmbeddedObject( Object )" );
1025 uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
1026 ::rtl::OUString aName;
1027 if ( xPersist.is() )
1028 aName = xPersist->getEntryName();
1030 #if OSL_DEBUG_LEVEL > 1
1031 uno::Reference < container::XNameAccess > xAccess( pImpl->mxStorage, uno::UNO_QUERY );
1032 uno::Reference < embed::XLinkageSupport > xLink( xPersist, uno::UNO_QUERY );
1033 sal_Bool bIsNotEmbedded = !xPersist.is() || xLink.is() && xLink->isLink();
1035 // if the object has a persistance and the object is not a link than it must have persistence entry in the storage
1036 OSL_ENSURE( bIsNotEmbedded || xAccess->hasByName(aName), "Removing element not present in storage!" );
1037 #endif
1039 // try to close it if permitted
1040 if ( bClose )
1042 uno::Reference < ::util::XCloseable > xClose( xObj, uno::UNO_QUERY );
1045 xClose->close( sal_True );
1047 catch ( util::CloseVetoException& )
1049 bClose = sal_False;
1053 if ( !bClose )
1055 // somebody still needs the object, so we must assign a temporary persistence
1058 if ( xPersist.is() )
1061 //TODO/LATER: needs storage handling! Why not letting the object do it?!
1062 if ( !pImpl->mxTempStorage.is() )
1063 pImpl->mxTempStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
1064 uno::Sequence < beans::PropertyValue > aSeq;
1066 ::rtl::OUString aTmpPersistName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Object ") );
1067 aTmpPersistName += ::rtl::OUString::valueOf( (sal_Int32) pImpl->maTempObjectContainer.size() );
1069 xPersist->storeAsEntry( pImpl->mxTempStorage, aTmpPersistName, aSeq, aSeq );
1070 xPersist->saveCompleted( sal_True );
1072 pImpl->maTempObjectContainer[ aTmpPersistName ] = uno::Reference < embed::XEmbeddedObject >();
1075 if ( !pImpl->mpTempObjectContainer )
1077 pImpl->mpTempObjectContainer = new EmbeddedObjectContainer();
1080 // TODO/LATER: in future probably the temporary container will have two storages ( of two formats )
1081 // the media type will be provided with object insertion
1082 ::rtl::OUString aOrigStorMediaType;
1083 uno::Reference< beans::XPropertySet > xStorProps( pImpl->mxStorage, uno::UNO_QUERY_THROW );
1084 static const ::rtl::OUString s_sMediaType(RTL_CONSTASCII_USTRINGPARAM("MediaType"));
1085 xStorProps->getPropertyValue( s_sMediaType ) >>= aOrigStorMediaType;
1087 OSL_ENSURE( aOrigStorMediaType.getLength(), "No valuable media type in the storage!\n" );
1089 uno::Reference< beans::XPropertySet > xTargetStorProps(
1090 pImpl->mpTempObjectContainer->pImpl->mxStorage,
1091 uno::UNO_QUERY_THROW );
1092 xTargetStorProps->setPropertyValue( s_sMediaType,uno::makeAny( aOrigStorMediaType ) );
1094 catch( uno::Exception& )
1096 OSL_ENSURE( sal_False, "Can not set the new media type to a storage!\n" );
1100 ::rtl::OUString aTempName, aMediaType;
1101 pImpl->mpTempObjectContainer->InsertEmbeddedObject( xObj, aTempName );
1103 uno::Reference < io::XInputStream > xStream = GetGraphicStream( xObj, &aMediaType );
1104 if ( xStream.is() )
1105 pImpl->mpTempObjectContainer->InsertGraphicStream( xStream, aTempName, aMediaType );
1107 // object is stored, so at least it can be set to loaded state
1108 xObj->changeState( embed::EmbedStates::LOADED );
1110 else
1111 // objects without persistence need to stay in running state if they shall not be closed
1112 xObj->changeState( embed::EmbedStates::RUNNING );
1114 catch ( uno::Exception& )
1116 return sal_False;
1120 sal_Bool bFound = sal_False;
1121 EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin();
1122 while ( aIt != pImpl->maObjectContainer.end() )
1124 if ( (*aIt).second == xObj )
1126 pImpl->maObjectContainer.erase( aIt );
1127 bFound = sal_True;
1128 uno::Reference < container::XChild > xChild( xObj, uno::UNO_QUERY );
1129 if ( xChild.is() )
1130 xChild->setParent( uno::Reference < uno::XInterface >() );
1131 break;
1134 aIt++;
1137 OSL_ENSURE( bFound, "Object not found for removal!" );
1138 if ( xPersist.is() )
1140 // remove replacement image (if there is one)
1141 RemoveGraphicStream( aName );
1143 // now it's time to remove the storage from the container storage
1146 #if OSL_DEBUG_LEVEL > 1
1147 // if the object has a persistance and the object is not a link than it must have persistence entry in storage
1148 OSL_ENSURE( bIsNotEmbedded || pImpl->mxStorage->hasByName( aName ), "The object has no persistence entry in the storage!" );
1149 #endif
1150 if ( xPersist.is() && pImpl->mxStorage->hasByName( aName ) )
1151 pImpl->mxStorage->removeElement( aName );
1153 catch ( uno::Exception& )
1155 OSL_ENSURE( sal_False, "Failed to remove object from storage!" );
1156 return sal_False;
1160 return sal_True;
1163 sal_Bool EmbeddedObjectContainer::CloseEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj )
1165 RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::CloseEmbeddedObject" );
1167 // disconnect the object from the container and close it if possible
1169 sal_Bool bFound = sal_False;
1170 EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin();
1171 while ( aIt != pImpl->maObjectContainer.end() )
1173 if ( (*aIt).second == xObj )
1175 pImpl->maObjectContainer.erase( aIt );
1176 bFound = sal_True;
1177 break;
1180 aIt++;
1183 if ( bFound )
1185 uno::Reference < ::util::XCloseable > xClose( xObj, uno::UNO_QUERY );
1188 xClose->close( sal_True );
1190 catch ( uno::Exception& )
1192 // it is no problem if the object is already closed
1193 // TODO/LATER: what if the object can not be closed?
1197 return bFound;
1200 uno::Reference < io::XInputStream > EmbeddedObjectContainer::GetGraphicStream( const ::rtl::OUString& aName, rtl::OUString* pMediaType )
1202 RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::GetGraphicStream( Name )" );
1204 uno::Reference < io::XInputStream > xStream;
1206 OSL_ENSURE( aName.getLength(), "Retrieving graphic for unknown object!" );
1207 if ( aName.getLength() )
1211 uno::Reference < embed::XStorage > xReplacements = pImpl->GetReplacements();
1212 uno::Reference < io::XStream > xGraphicStream = xReplacements->openStreamElement( aName, embed::ElementModes::READ );
1213 xStream = xGraphicStream->getInputStream();
1214 if ( pMediaType )
1216 uno::Reference < beans::XPropertySet > xSet( xStream, uno::UNO_QUERY );
1217 if ( xSet.is() )
1219 uno::Any aAny = xSet->getPropertyValue( ::rtl::OUString::createFromAscii("MediaType") );
1220 aAny >>= *pMediaType;
1224 catch ( uno::Exception& )
1229 return xStream;
1232 uno::Reference < io::XInputStream > EmbeddedObjectContainer::GetGraphicStream( const ::com::sun::star::uno::Reference < ::com::sun::star::embed::XEmbeddedObject >& xObj, rtl::OUString* pMediaType )
1234 RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::GetGraphicStream( Object )" );
1236 // get the object name
1237 ::rtl::OUString aName;
1238 EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin();
1239 while ( aIt != pImpl->maObjectContainer.end() )
1241 if ( (*aIt).second == xObj )
1243 aName = (*aIt).first;
1244 break;
1247 aIt++;
1250 // try to load it from the container storage
1251 return GetGraphicStream( aName, pMediaType );
1254 sal_Bool EmbeddedObjectContainer::InsertGraphicStream( const com::sun::star::uno::Reference < com::sun::star::io::XInputStream >& rStream, const ::rtl::OUString& rObjectName, const rtl::OUString& rMediaType )
1256 RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertGraphicStream" );
1260 uno::Reference < embed::XStorage > xReplacements = pImpl->GetReplacements();
1262 // store it into the subfolder
1263 uno::Reference < io::XOutputStream > xOutStream;
1264 uno::Reference < io::XStream > xGraphicStream = xReplacements->openStreamElement( rObjectName,
1265 embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE );
1266 xOutStream = xGraphicStream->getOutputStream();
1267 ::comphelper::OStorageHelper::CopyInputToOutput( rStream, xOutStream );
1268 xOutStream->flush();
1270 uno::Reference< beans::XPropertySet > xPropSet( xGraphicStream, uno::UNO_QUERY );
1271 if ( !xPropSet.is() )
1272 throw uno::RuntimeException();
1274 xPropSet->setPropertyValue( ::rtl::OUString::createFromAscii( "UseCommonStoragePasswordEncryption" ),
1275 uno::makeAny( (sal_Bool)sal_True ) );
1276 uno::Any aAny;
1277 aAny <<= rMediaType;
1278 xPropSet->setPropertyValue( ::rtl::OUString::createFromAscii("MediaType"), aAny );
1280 xPropSet->setPropertyValue( ::rtl::OUString::createFromAscii( "Compressed" ),
1281 uno::makeAny( (sal_Bool)sal_True ) );
1283 catch( uno::Exception& )
1285 return sal_False;
1288 return sal_True;
1291 sal_Bool EmbeddedObjectContainer::InsertGraphicStreamDirectly( const com::sun::star::uno::Reference < com::sun::star::io::XInputStream >& rStream, const ::rtl::OUString& rObjectName, const rtl::OUString& rMediaType )
1293 RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertGraphicStreamDirectly" );
1297 uno::Reference < embed::XStorage > xReplacement = pImpl->GetReplacements();
1298 uno::Reference < embed::XOptimizedStorage > xOptRepl( xReplacement, uno::UNO_QUERY_THROW );
1300 // store it into the subfolder
1301 uno::Sequence< beans::PropertyValue > aProps( 3 );
1302 aProps[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) );
1303 aProps[0].Value <<= rMediaType;
1304 aProps[1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UseCommonStoragePasswordEncryption" ) );
1305 aProps[1].Value <<= (sal_Bool)sal_True;
1306 aProps[2].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Compressed" ) );
1307 aProps[2].Value <<= (sal_Bool)sal_True;
1309 if ( xReplacement->hasByName( rObjectName ) )
1310 xReplacement->removeElement( rObjectName );
1312 xOptRepl->insertStreamElementDirect( rObjectName, rStream, aProps );
1314 catch( uno::Exception& )
1316 return sal_False;
1319 return sal_True;
1323 sal_Bool EmbeddedObjectContainer::RemoveGraphicStream( const ::rtl::OUString& rObjectName )
1325 RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::RemoveGraphicStream" );
1329 uno::Reference < embed::XStorage > xReplacements = pImpl->GetReplacements();
1330 xReplacements->removeElement( rObjectName );
1332 catch( uno::Exception& )
1334 return sal_False;
1337 return sal_True;
1339 namespace {
1340 void InsertStreamIntoPicturesStorage_Impl( const uno::Reference< embed::XStorage >& xDocStor,
1341 const uno::Reference< io::XInputStream >& xInStream,
1342 const ::rtl::OUString& aStreamName )
1344 OSL_ENSURE( aStreamName.getLength() && xInStream.is() && xDocStor.is(), "Misuse of the method!\n" );
1348 uno::Reference< embed::XStorage > xPictures = xDocStor->openStorageElement(
1349 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Pictures" ) ),
1350 embed::ElementModes::READWRITE );
1351 uno::Reference< io::XStream > xObjReplStr = xPictures->openStreamElement(
1352 aStreamName,
1353 embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE );
1354 uno::Reference< io::XOutputStream > xOutStream(
1355 xObjReplStr->getInputStream(), uno::UNO_QUERY_THROW );
1357 ::comphelper::OStorageHelper::CopyInputToOutput( xInStream, xOutStream );
1358 xOutStream->closeOutput();
1360 uno::Reference< embed::XTransactedObject > xTransact( xPictures, uno::UNO_QUERY );
1361 if ( xTransact.is() )
1362 xTransact->commit();
1364 catch( uno::Exception& )
1366 OSL_ENSURE( sal_False, "The pictures storage is not available!\n" );
1371 // -----------------------------------------------------------------------------
1372 sal_Bool EmbeddedObjectContainer::StoreAsChildren(sal_Bool _bOasisFormat,sal_Bool _bCreateEmbedded,const uno::Reference < embed::XStorage >& _xStorage)
1374 sal_Bool bResult = sal_False;
1377 comphelper::EmbeddedObjectContainer aCnt( _xStorage );
1378 const uno::Sequence < ::rtl::OUString > aNames = GetObjectNames();
1379 const ::rtl::OUString* pIter = aNames.getConstArray();
1380 const ::rtl::OUString* pEnd = pIter + aNames.getLength();
1381 for(;pIter != pEnd;++pIter)
1383 uno::Reference < embed::XEmbeddedObject > xObj = GetEmbeddedObject( *pIter );
1384 OSL_ENSURE( xObj.is(), "An empty entry in the embedded objects list!\n" );
1385 if ( xObj.is() )
1387 sal_Bool bSwitchBackToLoaded = sal_False;
1388 uno::Reference< embed::XLinkageSupport > xLink( xObj, uno::UNO_QUERY );
1390 uno::Reference < io::XInputStream > xStream;
1391 ::rtl::OUString aMediaType;
1393 sal_Int32 nCurState = xObj->getCurrentState();
1394 if ( nCurState == embed::EmbedStates::LOADED || nCurState == embed::EmbedStates::RUNNING )
1396 // means that the object is not active
1397 // copy replacement image from old to new container
1398 xStream = GetGraphicStream( xObj, &aMediaType );
1401 if ( !xStream.is() )
1403 // the image must be regenerated
1404 // TODO/LATER: another aspect could be used
1405 if ( xObj->getCurrentState() == embed::EmbedStates::LOADED )
1406 bSwitchBackToLoaded = sal_True;
1408 xStream = GetGraphicReplacementStream(
1409 embed::Aspects::MSOLE_CONTENT,
1410 xObj,
1411 &aMediaType );
1414 if ( _bOasisFormat || (xLink.is() && xLink->isLink()) )
1416 if ( xStream.is() )
1418 if ( _bOasisFormat )
1420 // if it is an embedded object or the optimized inserting fails the normal inserting should be done
1421 if ( _bCreateEmbedded
1422 || !aCnt.InsertGraphicStreamDirectly( xStream, *pIter, aMediaType ) )
1423 aCnt.InsertGraphicStream( xStream, *pIter, aMediaType );
1425 else
1427 // it is a linked object exported into SO7 format
1428 InsertStreamIntoPicturesStorage_Impl( _xStorage, xStream, *pIter );
1433 uno::Reference< embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
1434 if ( xPersist.is() )
1436 uno::Sequence< beans::PropertyValue > aArgs( _bOasisFormat ? 2 : 3 );
1437 aArgs[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StoreVisualReplacement" ) );
1438 aArgs[0].Value <<= (sal_Bool)( !_bOasisFormat );
1440 // if it is an embedded object or the optimized inserting fails the normal inserting should be done
1441 aArgs[1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CanTryOptimization" ) );
1442 aArgs[1].Value <<= !_bCreateEmbedded;
1443 if ( !_bOasisFormat )
1445 // if object has no cached replacement it will use this one
1446 aArgs[2].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VisualReplacement" ) );
1447 aArgs[2].Value <<= xStream;
1450 xPersist->storeAsEntry( _xStorage,
1451 xPersist->getEntryName(),
1452 uno::Sequence< beans::PropertyValue >(),
1453 aArgs );
1456 if ( bSwitchBackToLoaded )
1457 // switch back to loaded state; that way we have a minimum cache confusion
1458 xObj->changeState( embed::EmbedStates::LOADED );
1462 bResult = aCnt.CommitImageSubStorage();
1465 catch ( uno::Exception& )
1467 // TODO/LATER: error handling
1468 bResult = sal_False;
1471 // the old SO6 format does not store graphical replacements
1472 if ( !_bOasisFormat && bResult )
1476 // the substorage still can not be locked by the embedded object conteiner
1477 ::rtl::OUString aObjReplElement( RTL_CONSTASCII_USTRINGPARAM( "ObjectReplacements" ) );
1478 if ( _xStorage->hasByName( aObjReplElement ) && _xStorage->isStorageElement( aObjReplElement ) )
1479 _xStorage->removeElement( aObjReplElement );
1481 catch ( uno::Exception& )
1483 // TODO/LATER: error handling;
1484 bResult = sal_False;
1487 return bResult;
1489 // -----------------------------------------------------------------------------
1490 sal_Bool EmbeddedObjectContainer::StoreChildren(sal_Bool _bOasisFormat,sal_Bool _bObjectsOnly)
1492 sal_Bool bResult = sal_True;
1493 const uno::Sequence < ::rtl::OUString > aNames = GetObjectNames();
1494 const ::rtl::OUString* pIter = aNames.getConstArray();
1495 const ::rtl::OUString* pEnd = pIter + aNames.getLength();
1496 for(;pIter != pEnd;++pIter)
1498 uno::Reference < embed::XEmbeddedObject > xObj = GetEmbeddedObject( *pIter );
1499 OSL_ENSURE( xObj.is(), "An empty entry in the embedded objects list!\n" );
1500 if ( xObj.is() )
1502 sal_Int32 nCurState = xObj->getCurrentState();
1503 if ( _bOasisFormat && nCurState != embed::EmbedStates::LOADED && nCurState != embed::EmbedStates::RUNNING )
1505 // means that the object is active
1506 // the image must be regenerated
1507 ::rtl::OUString aMediaType;
1509 // TODO/LATER: another aspect could be used
1510 uno::Reference < io::XInputStream > xStream =
1511 GetGraphicReplacementStream(
1512 embed::Aspects::MSOLE_CONTENT,
1513 xObj,
1514 &aMediaType );
1515 if ( xStream.is() )
1517 if ( !InsertGraphicStreamDirectly( xStream, *pIter, aMediaType ) )
1518 InsertGraphicStream( xStream, *pIter, aMediaType );
1522 // TODO/LATER: currently the object by default does not cache replacement image
1523 // that means that if somebody loads SO7 document and store its objects using
1524 // this method the images might be lost.
1525 // Currently this method is only used on storing to alien formats, that means
1526 // that SO7 documents storing does not use it, and all other filters are
1527 // based on OASIS format. But if it changes the method must be fixed. The fix
1528 // must be done only on demand since it can affect performance.
1530 uno::Reference< embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
1531 if ( xPersist.is() )
1535 //TODO/LATER: only storing if changed!
1536 xPersist->storeOwn();
1538 catch( uno::Exception& )
1540 // TODO/LATER: error handling
1541 bResult = sal_False;
1542 break;
1546 if ( !_bOasisFormat && !_bObjectsOnly )
1548 // copy replacement images for linked objects
1551 uno::Reference< embed::XLinkageSupport > xLink( xObj, uno::UNO_QUERY );
1552 if ( xLink.is() && xLink->isLink() )
1554 ::rtl::OUString aMediaType;
1555 uno::Reference < io::XInputStream > xInStream = GetGraphicStream( xObj, &aMediaType );
1556 if ( xInStream.is() )
1557 InsertStreamIntoPicturesStorage_Impl( pImpl->mxStorage, xInStream, *pIter );
1560 catch( uno::Exception& )
1567 if ( bResult && _bOasisFormat )
1568 bResult = CommitImageSubStorage();
1570 if ( bResult && !_bObjectsOnly )
1574 ReleaseImageSubStorage();
1575 ::rtl::OUString aObjReplElement( RTL_CONSTASCII_USTRINGPARAM( "ObjectReplacements" ) );
1576 if ( !_bOasisFormat && pImpl->mxStorage->hasByName( aObjReplElement ) && pImpl->mxStorage->isStorageElement( aObjReplElement ) )
1577 pImpl->mxStorage->removeElement( aObjReplElement );
1579 catch( uno::Exception& )
1581 // TODO/LATER: error handling
1582 bResult = sal_False;
1585 return bResult;
1587 // -----------------------------------------------------------------------------
1588 uno::Reference< io::XInputStream > EmbeddedObjectContainer::GetGraphicReplacementStream(
1589 sal_Int64 nViewAspect,
1590 const uno::Reference< embed::XEmbeddedObject >& xObj,
1591 ::rtl::OUString* pMediaType )
1593 uno::Reference< io::XInputStream > xInStream;
1594 if ( xObj.is() )
1598 // retrieving of the visual representation can switch object to running state
1599 embed::VisualRepresentation aRep = xObj->getPreferredVisualRepresentation( nViewAspect );
1600 if ( pMediaType )
1601 *pMediaType = aRep.Flavor.MimeType;
1603 uno::Sequence < sal_Int8 > aSeq;
1604 aRep.Data >>= aSeq;
1605 xInStream = new ::comphelper::SequenceInputStream( aSeq );
1607 catch ( uno::Exception& )
1612 return xInStream;
1614 // -----------------------------------------------------------------------------
1615 sal_Bool EmbeddedObjectContainer::SetPersistentEntries(const uno::Reference< embed::XStorage >& _xStorage,bool _bClearModifedFlag)
1617 sal_Bool bError = sal_False;
1618 const uno::Sequence < ::rtl::OUString > aNames = GetObjectNames();
1619 const ::rtl::OUString* pIter = aNames.getConstArray();
1620 const ::rtl::OUString* pEnd = pIter + aNames.getLength();
1621 for(;pIter != pEnd;++pIter)
1623 uno::Reference < embed::XEmbeddedObject > xObj = GetEmbeddedObject( *pIter );
1624 OSL_ENSURE( xObj.is(), "An empty entry in the embedded objects list!\n" );
1625 if ( xObj.is() )
1627 uno::Reference< embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
1628 if ( xPersist.is() )
1632 xPersist->setPersistentEntry( _xStorage,
1633 *pIter,
1634 embed::EntryInitModes::NO_INIT,
1635 uno::Sequence< beans::PropertyValue >(),
1636 uno::Sequence< beans::PropertyValue >() );
1639 catch( uno::Exception& )
1641 // TODO/LATER: error handling
1642 bError = sal_True;
1643 break;
1646 if ( _bClearModifedFlag )
1648 // if this method is used as part of SaveCompleted the object must stay unmodified after execution
1651 uno::Reference< util::XModifiable > xModif( xObj->getComponent(), uno::UNO_QUERY_THROW );
1652 if ( xModif->isModified() )
1653 xModif->setModified( sal_False );
1655 catch( uno::Exception& )
1661 return bError;