/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_comphelper.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::com::sun::star; namespace comphelper { struct hashObjectName_Impl { size_t operator()(const ::rtl::OUString Str) const { return (size_t)Str.hashCode(); } }; struct eqObjectName_Impl { sal_Bool operator()(const ::rtl::OUString Str1, const ::rtl::OUString Str2) const { return ( Str1 == Str2 ); } }; typedef std::hash_map < ::rtl::OUString, ::com::sun::star::uno::Reference < com::sun::star::embed::XEmbeddedObject >, hashObjectName_Impl, eqObjectName_Impl > EmbeddedObjectContainerNameMap; struct EmbedImpl { // TODO/LATER: remove objects from temp. Container storage when object is disposed EmbeddedObjectContainerNameMap maObjectContainer; uno::Reference < embed::XStorage > mxStorage; EmbeddedObjectContainer* mpTempObjectContainer; uno::Reference < embed::XStorage > mxImageStorage; uno::WeakReference < uno::XInterface > m_xModel; //EmbeddedObjectContainerNameMap maTempObjectContainer; //uno::Reference < embed::XStorage > mxTempStorage; /// bitfield bool mbOwnsStorage : 1; bool mbUserAllowsLinkUpdate : 1; const uno::Reference < embed::XStorage >& GetReplacements(); }; const uno::Reference < embed::XStorage >& EmbedImpl::GetReplacements() { if ( !mxImageStorage.is() ) { try { mxImageStorage = mxStorage->openStorageElement( ::rtl::OUString::createFromAscii( "ObjectReplacements" ), embed::ElementModes::READWRITE ); } catch ( uno::Exception& ) { mxImageStorage = mxStorage->openStorageElement( ::rtl::OUString::createFromAscii( "ObjectReplacements" ), embed::ElementModes::READ ); } } if ( !mxImageStorage.is() ) throw io::IOException(); return mxImageStorage; } EmbeddedObjectContainer::EmbeddedObjectContainer() { pImpl = new EmbedImpl; pImpl->mxStorage = ::comphelper::OStorageHelper::GetTemporaryStorage(); pImpl->mbOwnsStorage = true; pImpl->mbUserAllowsLinkUpdate = true; pImpl->mpTempObjectContainer = 0; } EmbeddedObjectContainer::EmbeddedObjectContainer( const uno::Reference < embed::XStorage >& rStor ) { pImpl = new EmbedImpl; pImpl->mxStorage = rStor; pImpl->mbOwnsStorage = false; pImpl->mbUserAllowsLinkUpdate = true; pImpl->mpTempObjectContainer = 0; } EmbeddedObjectContainer::EmbeddedObjectContainer( const uno::Reference < embed::XStorage >& rStor, const uno::Reference < uno::XInterface >& xModel ) { pImpl = new EmbedImpl; pImpl->mxStorage = rStor; pImpl->mbOwnsStorage = false; pImpl->mbUserAllowsLinkUpdate = true; pImpl->mpTempObjectContainer = 0; pImpl->m_xModel = xModel; } void EmbeddedObjectContainer::SwitchPersistence( const uno::Reference < embed::XStorage >& rStor ) { ReleaseImageSubStorage(); if ( pImpl->mbOwnsStorage ) pImpl->mxStorage->dispose(); pImpl->mxStorage = rStor; pImpl->mbOwnsStorage = false; } sal_Bool EmbeddedObjectContainer::CommitImageSubStorage() { if ( pImpl->mxImageStorage.is() ) { try { sal_Bool bReadOnlyMode = sal_True; uno::Reference < beans::XPropertySet > xSet(pImpl->mxImageStorage,uno::UNO_QUERY); if ( xSet.is() ) { // get the open mode from the parent storage sal_Int32 nMode = 0; uno::Any aAny = xSet->getPropertyValue( ::rtl::OUString::createFromAscii("OpenMode") ); if ( aAny >>= nMode ) bReadOnlyMode = !(nMode & embed::ElementModes::WRITE ); } // if ( xSet.is() ) if ( !bReadOnlyMode ) { uno::Reference< embed::XTransactedObject > xTransact( pImpl->mxImageStorage, uno::UNO_QUERY_THROW ); xTransact->commit(); } } catch( uno::Exception& ) { return sal_False; } } return sal_True; } void EmbeddedObjectContainer::ReleaseImageSubStorage() { CommitImageSubStorage(); if ( pImpl->mxImageStorage.is() ) { try { pImpl->mxImageStorage->dispose(); pImpl->mxImageStorage = uno::Reference< embed::XStorage >(); } catch( uno::Exception& ) { OSL_ASSERT( "Problems releasing image substorage!\n" ); } } } EmbeddedObjectContainer::~EmbeddedObjectContainer() { ReleaseImageSubStorage(); if ( pImpl->mbOwnsStorage ) pImpl->mxStorage->dispose(); delete pImpl->mpTempObjectContainer; delete pImpl; } void EmbeddedObjectContainer::CloseEmbeddedObjects() { EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin(); while ( aIt != pImpl->maObjectContainer.end() ) { uno::Reference < util::XCloseable > xClose( (*aIt).second, uno::UNO_QUERY ); if ( xClose.is() ) { try { xClose->close( sal_True ); } catch ( uno::Exception& ) { } } aIt++; } } ::rtl::OUString EmbeddedObjectContainer::CreateUniqueObjectName() { ::rtl::OUString aPersistName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Object ") ); ::rtl::OUString aStr; sal_Int32 i=1; do { aStr = aPersistName; aStr += ::rtl::OUString::valueOf( i++ ); } while( HasEmbeddedObject( aStr ) ); // TODO/LATER: should we consider deleted objects? return aStr; } uno::Sequence < ::rtl::OUString > EmbeddedObjectContainer::GetObjectNames() { uno::Sequence < ::rtl::OUString > aSeq( pImpl->maObjectContainer.size() ); EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin(); sal_Int32 nIdx=0; while ( aIt != pImpl->maObjectContainer.end() ) aSeq[nIdx++] = (*aIt++).first; return aSeq; } sal_Bool EmbeddedObjectContainer::HasEmbeddedObjects() { return pImpl->maObjectContainer.size() != 0; } sal_Bool EmbeddedObjectContainer::HasEmbeddedObject( const ::rtl::OUString& rName ) { EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.find( rName ); if ( aIt == pImpl->maObjectContainer.end() ) { uno::Reference < container::XNameAccess > xAccess( pImpl->mxStorage, uno::UNO_QUERY ); return xAccess->hasByName(rName); } else return sal_True; } sal_Bool EmbeddedObjectContainer::HasEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj ) { EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin(); while ( aIt != pImpl->maObjectContainer.end() ) { if ( (*aIt).second == xObj ) return sal_True; else aIt++; } return sal_False; } sal_Bool EmbeddedObjectContainer::HasInstantiatedEmbeddedObject( const ::rtl::OUString& rName ) { // allows to detect whether the object was already instantiated // currently the filter instantiate it on loading, so this method allows // to avoid objects pointing to the same persistence EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.find( rName ); return ( aIt != pImpl->maObjectContainer.end() ); } ::rtl::OUString EmbeddedObjectContainer::GetEmbeddedObjectName( const ::com::sun::star::uno::Reference < ::com::sun::star::embed::XEmbeddedObject >& xObj ) { EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin(); while ( aIt != pImpl->maObjectContainer.end() ) { if ( (*aIt).second == xObj ) return (*aIt).first; else aIt++; } OSL_ENSURE( 0, "Unknown object!" ); return ::rtl::OUString(); } uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::GetEmbeddedObject( const ::rtl::OUString& rName ) { RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::GetEmbeddedObject" ); OSL_ENSURE( !rName.isEmpty(), "Empty object name!"); uno::Reference < embed::XEmbeddedObject > xObj; EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.find( rName ); #if OSL_DEBUG_LEVEL > 1 uno::Reference < container::XNameAccess > xAccess( pImpl->mxStorage, uno::UNO_QUERY ); uno::Sequence< ::rtl::OUString> aSeq = xAccess->getElementNames(); const ::rtl::OUString* pIter = aSeq.getConstArray(); const ::rtl::OUString* pEnd = pIter + aSeq.getLength(); for(;pIter != pEnd;++pIter) { (void)*pIter; } OSL_ENSURE( aIt != pImpl->maObjectContainer.end() || xAccess->hasByName(rName), "Could not return object!" ); #endif // check if object was already created if ( aIt != pImpl->maObjectContainer.end() ) xObj = (*aIt).second; else xObj = Get_Impl( rName, uno::Reference < embed::XEmbeddedObject >() ); return xObj; } uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::Get_Impl( const ::rtl::OUString& rName, const uno::Reference < embed::XEmbeddedObject >& xCopy ) { uno::Reference < embed::XEmbeddedObject > xObj; try { // create the object from the storage uno::Reference < beans::XPropertySet > xSet( pImpl->mxStorage, uno::UNO_QUERY ); sal_Bool bReadOnlyMode = sal_True; if ( xSet.is() ) { // get the open mode from the parent storage sal_Int32 nMode = 0; uno::Any aAny = xSet->getPropertyValue( ::rtl::OUString::createFromAscii("OpenMode") ); if ( aAny >>= nMode ) bReadOnlyMode = !(nMode & embed::ElementModes::WRITE ); } // object was not added until now - should happen only by calling this method from "inside" //TODO/LATER: it would be good to detect an error when an object should be created already, but isn't (not an "inside" call) uno::Reference < embed::XEmbedObjectCreator > xFactory( ::comphelper::getProcessServiceFactory()->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.embed.EmbeddedObjectCreator")) ), uno::UNO_QUERY ); uno::Sequence< beans::PropertyValue > aObjDescr( xCopy.is() ? 2 : 1 ); aObjDescr[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Parent" ) ); aObjDescr[0].Value <<= pImpl->m_xModel.get(); if ( xCopy.is() ) { aObjDescr[1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CloneFrom" ) ); aObjDescr[1].Value <<= xCopy; } uno::Sequence< beans::PropertyValue > aMediaDescr( 1 ); aMediaDescr[0].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ReadOnly")); aMediaDescr[0].Value <<= bReadOnlyMode; xObj = uno::Reference < embed::XEmbeddedObject >( xFactory->createInstanceInitFromEntry( pImpl->mxStorage, rName, aMediaDescr, aObjDescr ), uno::UNO_QUERY ); // insert object into my list AddEmbeddedObject( xObj, rName ); } catch ( uno::Exception& ) { } return xObj; } uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::CreateEmbeddedObject( const uno::Sequence < sal_Int8 >& rClassId, const uno::Sequence < beans::PropertyValue >& rArgs, ::rtl::OUString& rNewName ) { RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::CreateEmbeddedObject" ); if ( rNewName.isEmpty() ) rNewName = CreateUniqueObjectName(); OSL_ENSURE( !HasEmbeddedObject(rNewName), "Object to create already exists!"); // create object from classid by inserting it into storage uno::Reference < embed::XEmbeddedObject > xObj; try { uno::Reference < embed::XEmbedObjectCreator > xFactory( ::comphelper::getProcessServiceFactory()->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.embed.EmbeddedObjectCreator")) ), uno::UNO_QUERY ); uno::Sequence< beans::PropertyValue > aObjDescr( rArgs.getLength() + 1 ); aObjDescr[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Parent" ) ); aObjDescr[0].Value <<= pImpl->m_xModel.get(); ::std::copy( rArgs.getConstArray(), rArgs.getConstArray() + rArgs.getLength(), aObjDescr.getArray() + 1 ); xObj = uno::Reference < embed::XEmbeddedObject >( xFactory->createInstanceInitNew( rClassId, ::rtl::OUString(), pImpl->mxStorage, rNewName, aObjDescr ), uno::UNO_QUERY ); AddEmbeddedObject( xObj, rNewName ); OSL_ENSURE( !xObj.is() || xObj->getCurrentState() != embed::EmbedStates::LOADED, "A freshly create object should be running always!\n" ); } catch ( uno::Exception& ) { } return xObj; } uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::CreateEmbeddedObject( const uno::Sequence < sal_Int8 >& rClassId, ::rtl::OUString& rNewName ) { return CreateEmbeddedObject( rClassId, uno::Sequence < beans::PropertyValue >(), rNewName ); } void EmbeddedObjectContainer::AddEmbeddedObject( const ::com::sun::star::uno::Reference < ::com::sun::star::embed::XEmbeddedObject >& xObj, const ::rtl::OUString& rName ) { RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::AddEmbeddedObject" ); #if OSL_DEBUG_LEVEL > 1 OSL_ENSURE( !rName.isEmpty(), "Added object doesn't have a name!"); uno::Reference < container::XNameAccess > xAccess( pImpl->mxStorage, uno::UNO_QUERY ); uno::Reference < embed::XEmbedPersist > xEmb( xObj, uno::UNO_QUERY ); uno::Reference < embed::XLinkageSupport > xLink( xEmb, uno::UNO_QUERY ); // if the object has a persistence and the object is not a link than it must have persistence entry in the storage OSL_ENSURE( !( xEmb.is() && ( !xLink.is() || !xLink->isLink() ) ) || xAccess->hasByName(rName), "Added element not in storage!" ); #endif // remember object - it needs to be in storage already EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.find( rName ); OSL_ENSURE( aIt == pImpl->maObjectContainer.end(), "Element already inserted!" ); pImpl->maObjectContainer[ rName ] = xObj; uno::Reference < container::XChild > xChild( xObj, uno::UNO_QUERY ); if ( xChild.is() && xChild->getParent() != pImpl->m_xModel.get() ) xChild->setParent( pImpl->m_xModel.get() ); // look for object in temorary container if ( pImpl->mpTempObjectContainer ) { aIt = pImpl->mpTempObjectContainer->pImpl->maObjectContainer.begin(); while ( aIt != pImpl->mpTempObjectContainer->pImpl->maObjectContainer.end() ) { if ( (*aIt).second == xObj ) { // copy replacement image from temporary container (if there is any) ::rtl::OUString aTempName = (*aIt).first; ::rtl::OUString aMediaType; uno::Reference < io::XInputStream > xStream = pImpl->mpTempObjectContainer->GetGraphicStream( xObj, &aMediaType ); if ( xStream.is() ) { InsertGraphicStream( xStream, rName, aMediaType ); xStream = 0; pImpl->mpTempObjectContainer->RemoveGraphicStream( aTempName ); } // remove object from storage of temporary container uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); if ( xPersist.is() ) { try { pImpl->mpTempObjectContainer->pImpl->mxStorage->removeElement( aTempName ); } catch ( uno::Exception& ) { } } // temp. container needs to forget the object pImpl->mpTempObjectContainer->pImpl->maObjectContainer.erase( aIt ); break; } else aIt++; } } } sal_Bool EmbeddedObjectContainer::StoreEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj, ::rtl::OUString& rName, sal_Bool bCopy ) { RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::StoreEmbeddedObject" ); uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); if ( rName.isEmpty() ) rName = CreateUniqueObjectName(); #if OSL_DEBUG_LEVEL > 1 uno::Reference < container::XNameAccess > xAccess( pImpl->mxStorage, uno::UNO_QUERY ); OSL_ENSURE( !xPersist.is() || !xAccess->hasByName(rName), "Inserting element already present in storage!" ); OSL_ENSURE( xPersist.is() || xObj->getCurrentState() == embed::EmbedStates::RUNNING, "Non persistent object inserted!"); #endif // insert objects' storage into the container storage (if object has one) try { if ( xPersist.is() ) { uno::Sequence < beans::PropertyValue > aSeq; if ( bCopy ) xPersist->storeToEntry( pImpl->mxStorage, rName, aSeq, aSeq ); else { // TODO/LATER: possible optimisation, don't store immediately //xPersist->setPersistentEntry( pImpl->mxStorage, rName, embed::EntryInitModes::ENTRY_NO_INIT, aSeq, aSeq ); xPersist->storeAsEntry( pImpl->mxStorage, rName, aSeq, aSeq ); xPersist->saveCompleted( sal_True ); } } } catch ( uno::Exception& ) { // TODO/LATER: better error recovery should keep storage intact return sal_False; } return sal_True; } sal_Bool EmbeddedObjectContainer::InsertEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj, ::rtl::OUString& rName ) { RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertEmbeddedObject( Object )" ); // store it into the container storage if ( StoreEmbeddedObject( xObj, rName, sal_False ) ) { // remember object AddEmbeddedObject( xObj, rName ); return sal_True; } else return sal_False; } uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::InsertEmbeddedObject( const uno::Reference < io::XInputStream >& xStm, ::rtl::OUString& rNewName ) { RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertEmbeddedObject( InputStream )" ); if ( rNewName.isEmpty() ) rNewName = CreateUniqueObjectName(); // store it into the container storage sal_Bool bIsStorage = sal_False; try { // first try storage persistence uno::Reference < embed::XStorage > xStore = ::comphelper::OStorageHelper::GetStorageFromInputStream( xStm ); // storage was created from stream successfully bIsStorage = sal_True; uno::Reference < embed::XStorage > xNewStore = pImpl->mxStorage->openStorageElement( rNewName, embed::ElementModes::READWRITE ); xStore->copyToStorage( xNewStore ); } catch ( uno::Exception& ) { if ( bIsStorage ) // it is storage persistence, but opening of new substorage or copying to it failed return uno::Reference < embed::XEmbeddedObject >(); // stream didn't contain a storage, now try stream persistence try { uno::Reference < io::XStream > xNewStream = pImpl->mxStorage->openStreamElement( rNewName, embed::ElementModes::READWRITE ); ::comphelper::OStorageHelper::CopyInputToOutput( xStm, xNewStream->getOutputStream() ); // No mediatype is provided so the default for OLE objects value is used // it is correct so for now, but what if somebody introduces a new stream based embedded object? // Probably introducing of such an object must be restricted ( a storage must be used! ). uno::Reference< beans::XPropertySet > xProps( xNewStream, uno::UNO_QUERY_THROW ); xProps->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ), uno::makeAny( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "application/vnd.sun.star.oleobject" ) ) ) ); } catch ( uno::Exception& ) { // complete disaster! return uno::Reference < embed::XEmbeddedObject >(); } } // stream was copied into the container storage in either way, now try to open something form it uno::Reference < embed::XEmbeddedObject > xRet = GetEmbeddedObject( rNewName ); try { if ( !xRet.is() ) // no object could be created, so withdraw insertion pImpl->mxStorage->removeElement( rNewName ); } catch ( uno::Exception& ) { } return xRet; } uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::InsertEmbeddedObject( const ::com::sun::star::uno::Sequence < ::com::sun::star::beans::PropertyValue >& aMedium, ::rtl::OUString& rNewName ) { RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertEmbeddedObject( MediaDescriptor )" ); if ( rNewName.isEmpty() ) rNewName = CreateUniqueObjectName(); uno::Reference < embed::XEmbeddedObject > xObj; try { uno::Reference < embed::XEmbedObjectCreator > xFactory( ::comphelper::getProcessServiceFactory()->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.embed.EmbeddedObjectCreator")) ), uno::UNO_QUERY ); uno::Sequence< beans::PropertyValue > aObjDescr( 1 ); aObjDescr[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Parent" ) ); aObjDescr[0].Value <<= pImpl->m_xModel.get(); xObj = uno::Reference < embed::XEmbeddedObject >( xFactory->createInstanceInitFromMediaDescriptor( pImpl->mxStorage, rNewName, aMedium, aObjDescr ), uno::UNO_QUERY ); uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); OSL_ENSURE( !xObj.is() || xObj->getCurrentState() != embed::EmbedStates::LOADED, "A freshly create object should be running always!\n" ); // possible optimization: store later! if ( xPersist.is()) xPersist->storeOwn(); AddEmbeddedObject( xObj, rNewName ); } catch ( uno::Exception& ) { } return xObj; } uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::InsertEmbeddedLink( const ::com::sun::star::uno::Sequence < ::com::sun::star::beans::PropertyValue >& aMedium, ::rtl::OUString& rNewName ) { RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertEmbeddedLink" ); if ( rNewName.isEmpty() ) rNewName = CreateUniqueObjectName(); uno::Reference < embed::XEmbeddedObject > xObj; try { uno::Reference < embed::XLinkCreator > xFactory( ::comphelper::getProcessServiceFactory()->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.embed.EmbeddedObjectCreator")) ), uno::UNO_QUERY ); uno::Sequence< beans::PropertyValue > aObjDescr( 1 ); aObjDescr[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Parent" ) ); aObjDescr[0].Value <<= pImpl->m_xModel.get(); xObj = uno::Reference < embed::XEmbeddedObject >( xFactory->createInstanceLink( pImpl->mxStorage, rNewName, aMedium, aObjDescr ), uno::UNO_QUERY ); uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); OSL_ENSURE( !xObj.is() || xObj->getCurrentState() != embed::EmbedStates::LOADED, "A freshly create object should be running always!\n" ); // possible optimization: store later! if ( xPersist.is()) xPersist->storeOwn(); AddEmbeddedObject( xObj, rNewName ); } catch ( uno::Exception& ) { } return xObj; } sal_Bool EmbeddedObjectContainer::TryToCopyGraphReplacement( EmbeddedObjectContainer& rSrc, const ::rtl::OUString& aOrigName, const ::rtl::OUString& aTargetName ) { RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::TryToCopyGraphReplacement" ); sal_Bool bResult = sal_False; if ( ( &rSrc != this || !aOrigName.equals( aTargetName ) ) && !aOrigName.isEmpty() && !aTargetName.isEmpty() ) { ::rtl::OUString aMediaType; uno::Reference < io::XInputStream > xGrStream = rSrc.GetGraphicStream( aOrigName, &aMediaType ); if ( xGrStream.is() ) bResult = InsertGraphicStream( xGrStream, aTargetName, aMediaType ); } return bResult; } sal_Bool EmbeddedObjectContainer::CopyEmbeddedObject( EmbeddedObjectContainer& rSrc, const uno::Reference < embed::XEmbeddedObject >& xObj, ::rtl::OUString& rName ) { RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::CopyEmbeddedObject" ); OSL_ENSURE( sal_False, "This method is depricated! Use EmbeddedObjectContainer::CopyAndGetEmbeddedObject() to copy object!\n" ); // get the object name before(!) it is assigned to a new storage ::rtl::OUString aOrigName; uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); if ( xPersist.is() ) aOrigName = xPersist->getEntryName(); if ( rName.isEmpty() ) rName = CreateUniqueObjectName(); if ( StoreEmbeddedObject( xObj, rName, sal_True ) ) { TryToCopyGraphReplacement( rSrc, aOrigName, rName ); return sal_True; } return sal_False; } uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::CopyAndGetEmbeddedObject( EmbeddedObjectContainer& rSrc, const uno::Reference < embed::XEmbeddedObject >& xObj, ::rtl::OUString& rName ) { RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::CopyAndGetEmbeddedObject" ); uno::Reference< embed::XEmbeddedObject > xResult; // TODO/LATER: For now only objects that implement XEmbedPersist have a replacement image, it might change in future // do an incompatible change so that object name is provided in all the move and copy methods ::rtl::OUString aOrigName; try { uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY_THROW ); aOrigName = xPersist->getEntryName(); } catch( uno::Exception& ) {} if ( rName.isEmpty() ) rName = CreateUniqueObjectName(); // objects without persistence are not really stored by the method if ( xObj.is() && StoreEmbeddedObject( xObj, rName, sal_True ) ) { xResult = Get_Impl( rName, xObj); if ( !xResult.is() ) { // this is a case when object has no real persistence // in such cases a new object should be explicitly created and initialized with the data of the old one try { uno::Reference< embed::XLinkageSupport > xOrigLinkage( xObj, uno::UNO_QUERY ); if ( xOrigLinkage.is() && xOrigLinkage->isLink() ) { // this is a OOo link, it has no persistence ::rtl::OUString aURL = xOrigLinkage->getLinkURL(); if ( aURL.isEmpty() ) throw uno::RuntimeException(); // create new linked object from the URL the link is based on uno::Reference < embed::XLinkCreator > xCreator( ::comphelper::getProcessServiceFactory()->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.embed.EmbeddedObjectCreator") ) ), uno::UNO_QUERY_THROW ); uno::Sequence< beans::PropertyValue > aMediaDescr( 1 ); aMediaDescr[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "URL" ) ); aMediaDescr[0].Value <<= aURL; uno::Sequence< beans::PropertyValue > aObjDescr( 1 ); aObjDescr[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Parent" ) ); aObjDescr[0].Value <<= pImpl->m_xModel.get(); xResult = uno::Reference < embed::XEmbeddedObject >( xCreator->createInstanceLink( pImpl->mxStorage, rName, aMediaDescr, aObjDescr ), uno::UNO_QUERY_THROW ); } else { // the component is required for copying of this object if ( xObj->getCurrentState() == embed::EmbedStates::LOADED ) xObj->changeState( embed::EmbedStates::RUNNING ); // this must be an object based on properties, otherwise we can not copy it currently uno::Reference< beans::XPropertySet > xOrigProps( xObj->getComponent(), uno::UNO_QUERY_THROW ); // use object class ID to create a new one and transfer all the properties uno::Reference < embed::XEmbedObjectCreator > xCreator( ::comphelper::getProcessServiceFactory()->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.embed.EmbeddedObjectCreator") ) ), uno::UNO_QUERY_THROW ); uno::Sequence< beans::PropertyValue > aObjDescr( 1 ); aObjDescr[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Parent" ) ); aObjDescr[0].Value <<= pImpl->m_xModel.get(); xResult = uno::Reference < embed::XEmbeddedObject >( xCreator->createInstanceInitNew( xObj->getClassID(), xObj->getClassName(), pImpl->mxStorage, rName, aObjDescr ), uno::UNO_QUERY_THROW ); if ( xResult->getCurrentState() == embed::EmbedStates::LOADED ) xResult->changeState( embed::EmbedStates::RUNNING ); uno::Reference< beans::XPropertySet > xTargetProps( xResult->getComponent(), uno::UNO_QUERY_THROW ); // copy all the properties from xOrigProps to xTargetProps uno::Reference< beans::XPropertySetInfo > xOrigInfo = xOrigProps->getPropertySetInfo(); if ( !xOrigInfo.is() ) throw uno::RuntimeException(); uno::Sequence< beans::Property > aPropertiesList = xOrigInfo->getProperties(); for ( sal_Int32 nInd = 0; nInd < aPropertiesList.getLength(); nInd++ ) { try { xTargetProps->setPropertyValue( aPropertiesList[nInd].Name, xOrigProps->getPropertyValue( aPropertiesList[nInd].Name ) ); } catch( beans::PropertyVetoException& ) { // impossibility to copy readonly property is not treated as an error for now // but the assertion is helpful to detect such scenarios and review them OSL_ENSURE( sal_False, "Could not copy readonly property!\n" ); } } } if ( xResult.is() ) AddEmbeddedObject( xResult, rName ); } catch( uno::Exception& ) { if ( xResult.is() ) { try { xResult->close( sal_True ); } catch( uno::Exception& ) {} xResult = uno::Reference< embed::XEmbeddedObject >(); } } } } OSL_ENSURE( xResult.is(), "Can not copy embedded object that has no persistence!\n" ); if ( xResult.is() ) { // the object is successfully copied, try to copy graphical replacement if ( !aOrigName.isEmpty() ) TryToCopyGraphReplacement( rSrc, aOrigName, rName ); // the object might need the size to be set try { if ( xResult->getStatus( embed::Aspects::MSOLE_CONTENT ) & embed::EmbedMisc::EMBED_NEEDSSIZEONLOAD ) xResult->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT, xObj->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT ) ); } catch( uno::Exception& ) {} } return xResult; } sal_Bool EmbeddedObjectContainer::MoveEmbeddedObject( EmbeddedObjectContainer& rSrc, const uno::Reference < embed::XEmbeddedObject >& xObj, ::rtl::OUString& rName ) { RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::MoveEmbeddedObject( Object )" ); // get the object name before(!) it is assigned to a new storage uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); ::rtl::OUString aName; if ( xPersist.is() ) aName = xPersist->getEntryName(); // now move the object to the new container; the returned name is the new persist name in this container sal_Bool bRet; try { bRet = InsertEmbeddedObject( xObj, rName ); if ( bRet ) TryToCopyGraphReplacement( rSrc, aName, rName ); } catch ( uno::Exception& e ) { (void)e; OSL_ENSURE( sal_False, "Failed to insert embedded object into storage!" ); bRet = sal_False; } if ( bRet ) { // now remove the object from the former container bRet = sal_False; EmbeddedObjectContainerNameMap::iterator aIt = rSrc.pImpl->maObjectContainer.begin(); while ( aIt != rSrc.pImpl->maObjectContainer.end() ) { if ( (*aIt).second == xObj ) { rSrc.pImpl->maObjectContainer.erase( aIt ); bRet = sal_True; break; } aIt++; } OSL_ENSURE( bRet, "Object not found for removal!" ); if ( xPersist.is() ) { // now it's time to remove the storage from the container storage try { if ( xPersist.is() ) rSrc.pImpl->mxStorage->removeElement( aName ); } catch ( uno::Exception& ) { OSL_ENSURE( sal_False, "Failed to remove object from storage!" ); bRet = sal_False; } } // rSrc.RemoveGraphicStream( aName ); } return bRet; } //sal_Bool EmbeddedObjectContainer::RemoveEmbeddedObject( const ::rtl::OUString& rName, sal_Bool bClose ) // #i119941, bKeepToTempStorage: use to specify whether store the removed object to temporary storage+ sal_Bool EmbeddedObjectContainer::RemoveEmbeddedObject( const ::rtl::OUString& rName, sal_Bool bClose, sal_Bool bKeepToTempStorage ) { RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::RemoveEmbeddedObject( Name )" ); uno::Reference < embed::XEmbeddedObject > xObj = GetEmbeddedObject( rName ); if ( xObj.is() ) //return RemoveEmbeddedObject( xObj, bClose ); return RemoveEmbeddedObject( xObj, bClose, bKeepToTempStorage ); else return sal_False; } sal_Bool EmbeddedObjectContainer::MoveEmbeddedObject( const ::rtl::OUString& rName, EmbeddedObjectContainer& rCnt ) { RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::MoveEmbeddedObject( Name )" ); // find object entry EmbeddedObjectContainerNameMap::iterator aIt2 = rCnt.pImpl->maObjectContainer.find( rName ); OSL_ENSURE( aIt2 == rCnt.pImpl->maObjectContainer.end(), "Object does already exist in target container!" ); if ( aIt2 != rCnt.pImpl->maObjectContainer.end() ) return sal_False; uno::Reference < embed::XEmbeddedObject > xObj; EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.find( rName ); if ( aIt != pImpl->maObjectContainer.end() ) { xObj = (*aIt).second; try { if ( xObj.is() ) { // move object ::rtl::OUString aName( rName ); rCnt.InsertEmbeddedObject( xObj, aName ); pImpl->maObjectContainer.erase( aIt ); uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); if ( xPersist.is() ) pImpl->mxStorage->removeElement( rName ); } else { // copy storages; object *must* have persistence! uno::Reference < embed::XStorage > xOld = pImpl->mxStorage->openStorageElement( rName, embed::ElementModes::READ ); uno::Reference < embed::XStorage > xNew = rCnt.pImpl->mxStorage->openStorageElement( rName, embed::ElementModes::READWRITE ); xOld->copyToStorage( xNew ); } rCnt.TryToCopyGraphReplacement( *this, rName, rName ); // RemoveGraphicStream( rName ); return sal_True; } catch ( uno::Exception& ) { OSL_ENSURE(0,"Could not move object!"); return sal_False; } } else OSL_ENSURE(0,"Unknown object!"); return sal_False; } //sal_Bool EmbeddedObjectContainer::RemoveEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj, sal_Bool bClose ) // #i119941, bKeepToTempStorage: use to specify whether store the removed object to temporary storage+ sal_Bool EmbeddedObjectContainer::RemoveEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj, sal_Bool bClose, sal_Bool bKeepToTempStorage ) { RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::RemoveEmbeddedObject( Object )" ); uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); ::rtl::OUString aName; if ( xPersist.is() ) aName = xPersist->getEntryName(); #if OSL_DEBUG_LEVEL > 1 uno::Reference < container::XNameAccess > xAccess( pImpl->mxStorage, uno::UNO_QUERY ); uno::Reference < embed::XLinkageSupport > xLink( xPersist, uno::UNO_QUERY ); sal_Bool bIsNotEmbedded = !xPersist.is() || xLink.is() && xLink->isLink(); // if the object has a persistence and the object is not a link than it must have persistence entry in the storage OSL_ENSURE( bIsNotEmbedded || xAccess->hasByName(aName), "Removing element not present in storage!" ); #endif // try to close it if permitted if ( bClose ) { uno::Reference < ::util::XCloseable > xClose( xObj, uno::UNO_QUERY ); try { xClose->close( sal_True ); } catch ( util::CloseVetoException& ) { bClose = sal_False; } } if ( !bClose ) { // somebody still needs the object, so we must assign a temporary persistence try { // if ( xPersist.is() ) if ( xPersist.is() && bKeepToTempStorage ) // #i119941 { /* // TODO/LATER: needs storage handling! Why not letting the object do it?! if ( !pImpl->mxTempStorage.is() ) pImpl->mxTempStorage = ::comphelper::OStorageHelper::GetTemporaryStorage(); uno::Sequence < beans::PropertyValue > aSeq; ::rtl::OUString aTmpPersistName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Object ") ); aTmpPersistName += ::rtl::OUString::valueOf( (sal_Int32) pImpl->maTempObjectContainer.size() ); xPersist->storeAsEntry( pImpl->mxTempStorage, aTmpPersistName, aSeq, aSeq ); xPersist->saveCompleted( sal_True ); pImpl->maTempObjectContainer[ aTmpPersistName ] = uno::Reference < embed::XEmbeddedObject >(); */ if ( !pImpl->mpTempObjectContainer ) { pImpl->mpTempObjectContainer = new EmbeddedObjectContainer(); try { // TODO/LATER: in future probably the temporary container will have two storages ( of two formats ) // the media type will be provided with object insertion ::rtl::OUString aOrigStorMediaType; uno::Reference< beans::XPropertySet > xStorProps( pImpl->mxStorage, uno::UNO_QUERY_THROW ); static const ::rtl::OUString s_sMediaType(RTL_CONSTASCII_USTRINGPARAM("MediaType")); xStorProps->getPropertyValue( s_sMediaType ) >>= aOrigStorMediaType; OSL_ENSURE( !aOrigStorMediaType.isEmpty(), "No valuable media type in the storage!\n" ); uno::Reference< beans::XPropertySet > xTargetStorProps( pImpl->mpTempObjectContainer->pImpl->mxStorage, uno::UNO_QUERY_THROW ); xTargetStorProps->setPropertyValue( s_sMediaType,uno::makeAny( aOrigStorMediaType ) ); } catch( uno::Exception& ) { OSL_ENSURE( sal_False, "Can not set the new media type to a storage!\n" ); } } ::rtl::OUString aTempName, aMediaType; pImpl->mpTempObjectContainer->InsertEmbeddedObject( xObj, aTempName ); uno::Reference < io::XInputStream > xStream = GetGraphicStream( xObj, &aMediaType ); if ( xStream.is() ) pImpl->mpTempObjectContainer->InsertGraphicStream( xStream, aTempName, aMediaType ); // object is stored, so at least it can be set to loaded state xObj->changeState( embed::EmbedStates::LOADED ); } else // objects without persistence need to stay in running state if they shall not be closed xObj->changeState( embed::EmbedStates::RUNNING ); } catch ( uno::Exception& ) { return sal_False; } } sal_Bool bFound = sal_False; EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin(); while ( aIt != pImpl->maObjectContainer.end() ) { if ( (*aIt).second == xObj ) { pImpl->maObjectContainer.erase( aIt ); bFound = sal_True; uno::Reference < container::XChild > xChild( xObj, uno::UNO_QUERY ); if ( xChild.is() ) xChild->setParent( uno::Reference < uno::XInterface >() ); break; } aIt++; } OSL_ENSURE( bFound, "Object not found for removal!" ); // if ( xPersist.is() ) if ( xPersist.is() && bKeepToTempStorage ) // #i119941 { // remove replacement image (if there is one) RemoveGraphicStream( aName ); // now it's time to remove the storage from the container storage try { #if OSL_DEBUG_LEVEL > 1 // if the object has a persistence and the object is not a link than it must have persistence entry in storage OSL_ENSURE( bIsNotEmbedded || pImpl->mxStorage->hasByName( aName ), "The object has no persistence entry in the storage!" ); #endif if ( xPersist.is() && pImpl->mxStorage->hasByName( aName ) ) pImpl->mxStorage->removeElement( aName ); } catch ( uno::Exception& ) { OSL_ENSURE( sal_False, "Failed to remove object from storage!" ); return sal_False; } } return sal_True; } sal_Bool EmbeddedObjectContainer::CloseEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj ) { RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::CloseEmbeddedObject" ); // disconnect the object from the container and close it if possible sal_Bool bFound = sal_False; EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin(); while ( aIt != pImpl->maObjectContainer.end() ) { if ( (*aIt).second == xObj ) { pImpl->maObjectContainer.erase( aIt ); bFound = sal_True; break; } aIt++; } if ( bFound ) { uno::Reference < ::util::XCloseable > xClose( xObj, uno::UNO_QUERY ); try { xClose->close( sal_True ); } catch ( uno::Exception& ) { // it is no problem if the object is already closed // TODO/LATER: what if the object can not be closed? } } return bFound; } uno::Reference < io::XInputStream > EmbeddedObjectContainer::GetGraphicStream( const ::rtl::OUString& aName, rtl::OUString* pMediaType ) { RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::GetGraphicStream( Name )" ); uno::Reference < io::XInputStream > xStream; OSL_ENSURE( !aName.isEmpty(), "Retrieving graphic for unknown object!" ); if ( !aName.isEmpty() ) { try { uno::Reference < embed::XStorage > xReplacements = pImpl->GetReplacements(); uno::Reference < io::XStream > xGraphicStream = xReplacements->openStreamElement( aName, embed::ElementModes::READ ); xStream = xGraphicStream->getInputStream(); if ( pMediaType ) { uno::Reference < beans::XPropertySet > xSet( xStream, uno::UNO_QUERY ); if ( xSet.is() ) { uno::Any aAny = xSet->getPropertyValue( ::rtl::OUString::createFromAscii("MediaType") ); aAny >>= *pMediaType; } } } catch ( uno::Exception& ) { } } return xStream; } uno::Reference < io::XInputStream > EmbeddedObjectContainer::GetGraphicStream( const ::com::sun::star::uno::Reference < ::com::sun::star::embed::XEmbeddedObject >& xObj, rtl::OUString* pMediaType ) { RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::GetGraphicStream( Object )" ); // get the object name ::rtl::OUString aName; EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin(); while ( aIt != pImpl->maObjectContainer.end() ) { if ( (*aIt).second == xObj ) { aName = (*aIt).first; break; } aIt++; } // try to load it from the container storage return GetGraphicStream( aName, pMediaType ); } sal_Bool EmbeddedObjectContainer::InsertGraphicStream( const com::sun::star::uno::Reference < com::sun::star::io::XInputStream >& rStream, const ::rtl::OUString& rObjectName, const rtl::OUString& rMediaType ) { RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertGraphicStream" ); try { uno::Reference < embed::XStorage > xReplacements = pImpl->GetReplacements(); // store it into the subfolder uno::Reference < io::XOutputStream > xOutStream; uno::Reference < io::XStream > xGraphicStream = xReplacements->openStreamElement( rObjectName, embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE ); xOutStream = xGraphicStream->getOutputStream(); ::comphelper::OStorageHelper::CopyInputToOutput( rStream, xOutStream ); xOutStream->flush(); uno::Reference< beans::XPropertySet > xPropSet( xGraphicStream, uno::UNO_QUERY ); if ( !xPropSet.is() ) throw uno::RuntimeException(); xPropSet->setPropertyValue( ::rtl::OUString::createFromAscii( "UseCommonStoragePasswordEncryption" ), uno::makeAny( (sal_Bool)sal_True ) ); uno::Any aAny; aAny <<= rMediaType; xPropSet->setPropertyValue( ::rtl::OUString::createFromAscii("MediaType"), aAny ); xPropSet->setPropertyValue( ::rtl::OUString::createFromAscii( "Compressed" ), uno::makeAny( (sal_Bool)sal_True ) ); } catch( uno::Exception& ) { return sal_False; } return sal_True; } sal_Bool EmbeddedObjectContainer::InsertGraphicStreamDirectly( const com::sun::star::uno::Reference < com::sun::star::io::XInputStream >& rStream, const ::rtl::OUString& rObjectName, const rtl::OUString& rMediaType ) { RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertGraphicStreamDirectly" ); try { uno::Reference < embed::XStorage > xReplacement = pImpl->GetReplacements(); uno::Reference < embed::XOptimizedStorage > xOptRepl( xReplacement, uno::UNO_QUERY_THROW ); // store it into the subfolder uno::Sequence< beans::PropertyValue > aProps( 3 ); aProps[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ); aProps[0].Value <<= rMediaType; aProps[1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UseCommonStoragePasswordEncryption" ) ); aProps[1].Value <<= (sal_Bool)sal_True; aProps[2].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Compressed" ) ); aProps[2].Value <<= (sal_Bool)sal_True; if ( xReplacement->hasByName( rObjectName ) ) xReplacement->removeElement( rObjectName ); xOptRepl->insertStreamElementDirect( rObjectName, rStream, aProps ); } catch( uno::Exception& ) { return sal_False; } return sal_True; } sal_Bool EmbeddedObjectContainer::RemoveGraphicStream( const ::rtl::OUString& rObjectName ) { RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::RemoveGraphicStream" ); try { uno::Reference < embed::XStorage > xReplacements = pImpl->GetReplacements(); xReplacements->removeElement( rObjectName ); } catch( uno::Exception& ) { return sal_False; } return sal_True; } namespace { void InsertStreamIntoPicturesStorage_Impl( const uno::Reference< embed::XStorage >& xDocStor, const uno::Reference< io::XInputStream >& xInStream, const ::rtl::OUString& aStreamName ) { OSL_ENSURE( !aStreamName.isEmpty() && xInStream.is() && xDocStor.is(), "Misuse of the method!\n" ); try { uno::Reference< embed::XStorage > xPictures = xDocStor->openStorageElement( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Pictures" ) ), embed::ElementModes::READWRITE ); uno::Reference< io::XStream > xObjReplStr = xPictures->openStreamElement( aStreamName, embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE ); uno::Reference< io::XOutputStream > xOutStream( xObjReplStr->getInputStream(), uno::UNO_QUERY_THROW ); ::comphelper::OStorageHelper::CopyInputToOutput( xInStream, xOutStream ); xOutStream->closeOutput(); uno::Reference< embed::XTransactedObject > xTransact( xPictures, uno::UNO_QUERY ); if ( xTransact.is() ) xTransact->commit(); } catch( uno::Exception& ) { OSL_ENSURE( sal_False, "The pictures storage is not available!\n" ); } } } // ----------------------------------------------------------------------------- sal_Bool EmbeddedObjectContainer::StoreAsChildren(sal_Bool _bOasisFormat,sal_Bool _bCreateEmbedded,const uno::Reference < embed::XStorage >& _xStorage) { sal_Bool bResult = sal_False; try { comphelper::EmbeddedObjectContainer aCnt( _xStorage ); const uno::Sequence < ::rtl::OUString > aNames = GetObjectNames(); const ::rtl::OUString* pIter = aNames.getConstArray(); const ::rtl::OUString* pEnd = pIter + aNames.getLength(); for(;pIter != pEnd;++pIter) { uno::Reference < embed::XEmbeddedObject > xObj = GetEmbeddedObject( *pIter ); OSL_ENSURE( xObj.is(), "An empty entry in the embedded objects list!\n" ); if ( xObj.is() ) { sal_Bool bSwitchBackToLoaded = sal_False; uno::Reference< embed::XLinkageSupport > xLink( xObj, uno::UNO_QUERY ); uno::Reference < io::XInputStream > xStream; ::rtl::OUString aMediaType; sal_Int32 nCurState = xObj->getCurrentState(); if ( nCurState == embed::EmbedStates::LOADED || nCurState == embed::EmbedStates::RUNNING ) { // means that the object is not active // copy replacement image from old to new container xStream = GetGraphicStream( xObj, &aMediaType ); } if ( !xStream.is() && getUserAllowsLinkUpdate() ) { // the image must be regenerated // TODO/LATER: another aspect could be used if ( xObj->getCurrentState() == embed::EmbedStates::LOADED ) bSwitchBackToLoaded = sal_True; xStream = GetGraphicReplacementStream( embed::Aspects::MSOLE_CONTENT, xObj, &aMediaType ); } if ( _bOasisFormat || (xLink.is() && xLink->isLink()) ) { if ( xStream.is() ) { if ( _bOasisFormat ) { // if it is an embedded object or the optimized inserting fails the normal inserting should be done if ( _bCreateEmbedded || !aCnt.InsertGraphicStreamDirectly( xStream, *pIter, aMediaType ) ) aCnt.InsertGraphicStream( xStream, *pIter, aMediaType ); } else { // it is a linked object exported into SO7 format InsertStreamIntoPicturesStorage_Impl( _xStorage, xStream, *pIter ); } } } uno::Reference< embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); if ( xPersist.is() ) { uno::Sequence< beans::PropertyValue > aArgs( _bOasisFormat ? 2 : 3 ); aArgs[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StoreVisualReplacement" ) ); aArgs[0].Value <<= (sal_Bool)( !_bOasisFormat ); // if it is an embedded object or the optimized inserting fails the normal inserting should be done aArgs[1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CanTryOptimization" ) ); aArgs[1].Value <<= !_bCreateEmbedded; if ( !_bOasisFormat ) { // if object has no cached replacement it will use this one aArgs[2].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VisualReplacement" ) ); aArgs[2].Value <<= xStream; } xPersist->storeAsEntry( _xStorage, xPersist->getEntryName(), uno::Sequence< beans::PropertyValue >(), aArgs ); } if ( bSwitchBackToLoaded ) // switch back to loaded state; that way we have a minimum cache confusion xObj->changeState( embed::EmbedStates::LOADED ); } } bResult = aCnt.CommitImageSubStorage(); } catch ( uno::Exception& ) { // TODO/LATER: error handling bResult = sal_False; } // the old SO6 format does not store graphical replacements if ( !_bOasisFormat && bResult ) { try { // the substorage still can not be locked by the embedded object conteiner ::rtl::OUString aObjReplElement( RTL_CONSTASCII_USTRINGPARAM( "ObjectReplacements" ) ); if ( _xStorage->hasByName( aObjReplElement ) && _xStorage->isStorageElement( aObjReplElement ) ) _xStorage->removeElement( aObjReplElement ); } catch ( uno::Exception& ) { // TODO/LATER: error handling; bResult = sal_False; } } return bResult; } // ----------------------------------------------------------------------------- sal_Bool EmbeddedObjectContainer::StoreChildren(sal_Bool _bOasisFormat,sal_Bool _bObjectsOnly) { sal_Bool bResult = sal_True; const uno::Sequence < ::rtl::OUString > aNames = GetObjectNames(); const ::rtl::OUString* pIter = aNames.getConstArray(); const ::rtl::OUString* pEnd = pIter + aNames.getLength(); for(;pIter != pEnd;++pIter) { uno::Reference < embed::XEmbeddedObject > xObj = GetEmbeddedObject( *pIter ); OSL_ENSURE( xObj.is(), "An empty entry in the embedded objects list!\n" ); if ( xObj.is() ) { sal_Int32 nCurState = xObj->getCurrentState(); if ( _bOasisFormat && nCurState != embed::EmbedStates::LOADED && nCurState != embed::EmbedStates::RUNNING ) { // means that the object is active // the image must be regenerated ::rtl::OUString aMediaType; // TODO/LATER: another aspect could be used uno::Reference < io::XInputStream > xStream = GetGraphicReplacementStream( embed::Aspects::MSOLE_CONTENT, xObj, &aMediaType ); if ( xStream.is() ) { if ( !InsertGraphicStreamDirectly( xStream, *pIter, aMediaType ) ) InsertGraphicStream( xStream, *pIter, aMediaType ); } } // TODO/LATER: currently the object by default does not cache replacement image // that means that if somebody loads SO7 document and store its objects using // this method the images might be lost. // Currently this method is only used on storing to alien formats, that means // that SO7 documents storing does not use it, and all other filters are // based on OASIS format. But if it changes the method must be fixed. The fix // must be done only on demand since it can affect performance. uno::Reference< embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); if ( xPersist.is() ) { try { // TODO/LATER: only storing if changed! //xPersist->storeOwn(); //commented, i120168 // begin:all charts will be persisted as xml format on disk when saving, which is time consuming. // '_bObjectsOnly' mean we are storing to alien formats. // 'isStorageElement' mean current object is NOT an MS OLE format. (may also include in future), i120168 if (_bObjectsOnly && (nCurState == embed::EmbedStates::LOADED || nCurState == embed::EmbedStates::RUNNING) && (pImpl->mxStorage->isStorageElement( *pIter ) )) { uno::Reference< util::XModifiable > xModifiable( xObj->getComponent(), uno::UNO_QUERY ); if ( xModifiable.is() && xModifiable->isModified()) { xPersist->storeOwn(); } else { // do nothing. Embedded model is not modified, no need to persist. } } else // the embedded object is in active status, always store back it. { xPersist->storeOwn(); } // end i120168 } catch( uno::Exception& ) { // TODO/LATER: error handling bResult = sal_False; break; } } if ( !_bOasisFormat && !_bObjectsOnly ) { // copy replacement images for linked objects try { uno::Reference< embed::XLinkageSupport > xLink( xObj, uno::UNO_QUERY ); if ( xLink.is() && xLink->isLink() ) { ::rtl::OUString aMediaType; uno::Reference < io::XInputStream > xInStream = GetGraphicStream( xObj, &aMediaType ); if ( xInStream.is() ) InsertStreamIntoPicturesStorage_Impl( pImpl->mxStorage, xInStream, *pIter ); } } catch( uno::Exception& ) { } } } } if ( bResult && _bOasisFormat ) bResult = CommitImageSubStorage(); if ( bResult && !_bObjectsOnly ) { try { ReleaseImageSubStorage(); ::rtl::OUString aObjReplElement( RTL_CONSTASCII_USTRINGPARAM( "ObjectReplacements" ) ); if ( !_bOasisFormat && pImpl->mxStorage->hasByName( aObjReplElement ) && pImpl->mxStorage->isStorageElement( aObjReplElement ) ) pImpl->mxStorage->removeElement( aObjReplElement ); } catch( uno::Exception& ) { // TODO/LATER: error handling bResult = sal_False; } } return bResult; } // ----------------------------------------------------------------------------- uno::Reference< io::XInputStream > EmbeddedObjectContainer::GetGraphicReplacementStream( sal_Int64 nViewAspect, const uno::Reference< embed::XEmbeddedObject >& xObj, ::rtl::OUString* pMediaType ) { uno::Reference< io::XInputStream > xInStream; if ( xObj.is() ) { try { // retrieving of the visual representation can switch object to running state embed::VisualRepresentation aRep = xObj->getPreferredVisualRepresentation( nViewAspect ); if ( pMediaType ) *pMediaType = aRep.Flavor.MimeType; uno::Sequence < sal_Int8 > aSeq; aRep.Data >>= aSeq; xInStream = new ::comphelper::SequenceInputStream( aSeq ); } catch ( uno::Exception& ) { } } return xInStream; } // ----------------------------------------------------------------------------- sal_Bool EmbeddedObjectContainer::SetPersistentEntries(const uno::Reference< embed::XStorage >& _xStorage,bool _bClearModifedFlag) { sal_Bool bError = sal_False; const uno::Sequence < ::rtl::OUString > aNames = GetObjectNames(); const ::rtl::OUString* pIter = aNames.getConstArray(); const ::rtl::OUString* pEnd = pIter + aNames.getLength(); for(;pIter != pEnd;++pIter) { uno::Reference < embed::XEmbeddedObject > xObj = GetEmbeddedObject( *pIter ); OSL_ENSURE( xObj.is(), "An empty entry in the embedded objects list!\n" ); if ( xObj.is() ) { uno::Reference< embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); if ( xPersist.is() ) { try { xPersist->setPersistentEntry( _xStorage, *pIter, embed::EntryInitModes::NO_INIT, uno::Sequence< beans::PropertyValue >(), uno::Sequence< beans::PropertyValue >() ); } catch( uno::Exception& ) { // TODO/LATER: error handling bError = sal_True; break; } } if ( _bClearModifedFlag ) { // if this method is used as part of SaveCompleted the object must stay unmodified after execution try { uno::Reference< util::XModifiable > xModif( xObj->getComponent(), uno::UNO_QUERY_THROW ); if ( xModif->isModified() ) xModif->setModified( sal_False ); } catch( uno::Exception& ) { } } } } return bError; } bool EmbeddedObjectContainer::getUserAllowsLinkUpdate() const { return pImpl->mbUserAllowsLinkUpdate; } void EmbeddedObjectContainer::setUserAllowsLinkUpdate(bool bNew) { if(pImpl->mbUserAllowsLinkUpdate != bNew) { pImpl->mbUserAllowsLinkUpdate = bNew; } } }