summaryrefslogtreecommitdiff
path: root/comphelper/source/container/embeddedobjectcontainer.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'comphelper/source/container/embeddedobjectcontainer.cxx')
-rw-r--r--comphelper/source/container/embeddedobjectcontainer.cxx1663
1 files changed, 1663 insertions, 0 deletions
diff --git a/comphelper/source/container/embeddedobjectcontainer.cxx b/comphelper/source/container/embeddedobjectcontainer.cxx
new file mode 100644
index 000000000000..17740e7ef09b
--- /dev/null
+++ b/comphelper/source/container/embeddedobjectcontainer.cxx
@@ -0,0 +1,1663 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_comphelper.hxx"
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/embed/XEmbedObjectCreator.hpp>
+#include <com/sun/star/embed/XLinkCreator.hpp>
+#include <com/sun/star/embed/XEmbedPersist.hpp>
+#include <com/sun/star/embed/XLinkageSupport.hpp>
+#include <com/sun/star/embed/XTransactedObject.hpp>
+#include <com/sun/star/embed/XOptimizedStorage.hpp>
+#include <com/sun/star/embed/EntryInitModes.hpp>
+#include <com/sun/star/util/XCloseable.hpp>
+#include <com/sun/star/util/XModifiable.hpp>
+#include <com/sun/star/embed/EmbedStates.hpp>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/embed/Aspects.hpp>
+#include <com/sun/star/embed/EmbedMisc.hpp>
+
+#include <comphelper/seqstream.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/embeddedobjectcontainer.hxx>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/weakref.hxx>
+#include <hash_map>
+#include <algorithm>
+
+#include <rtl/logfile.hxx>
+
+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;
+ sal_Bool bOwnsStorage;
+
+ 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->bOwnsStorage = sal_True;
+ pImpl->mpTempObjectContainer = 0;
+}
+
+EmbeddedObjectContainer::EmbeddedObjectContainer( const uno::Reference < embed::XStorage >& rStor )
+{
+ pImpl = new EmbedImpl;
+ pImpl->mxStorage = rStor;
+ pImpl->bOwnsStorage = sal_False;
+ pImpl->mpTempObjectContainer = 0;
+}
+
+EmbeddedObjectContainer::EmbeddedObjectContainer( const uno::Reference < embed::XStorage >& rStor, const uno::Reference < uno::XInterface >& xModel )
+{
+ pImpl = new EmbedImpl;
+ pImpl->mxStorage = rStor;
+ pImpl->bOwnsStorage = sal_False;
+ pImpl->mpTempObjectContainer = 0;
+ pImpl->m_xModel = xModel;
+}
+
+void EmbeddedObjectContainer::SwitchPersistence( const uno::Reference < embed::XStorage >& rStor )
+{
+ ReleaseImageSubStorage();
+
+ if ( pImpl->bOwnsStorage )
+ pImpl->mxStorage->dispose();
+
+ pImpl->mxStorage = rStor;
+ pImpl->bOwnsStorage = sal_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->bOwnsStorage )
+ 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.getLength(), "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.getLength() )
+ 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.getLength(), "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 persistance 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.getLength() )
+ 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.getLength() )
+ 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.getLength() )
+ 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.getLength() )
+ 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.getLength() && aTargetName.getLength() )
+ {
+ ::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.getLength() )
+ 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.getLength() )
+ rName = CreateUniqueObjectName();
+
+ // objects without persistance 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.getLength() )
+ 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 tranfer 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 persistance!\n" );
+
+ if ( xResult.is() )
+ {
+ // the object is successfully copied, try to copy graphical replacement
+ if ( aOrigName.getLength() )
+ 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 )
+{
+ RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::RemoveEmbeddedObject( Name )" );
+
+ uno::Reference < embed::XEmbeddedObject > xObj = GetEmbeddedObject( rName );
+ if ( xObj.is() )
+ return RemoveEmbeddedObject( xObj, bClose );
+ 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 )
+{
+ 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 persistance 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() )
+ {
+ /*
+ //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.getLength(), "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() )
+ {
+ // 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 persistance 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.getLength(), "Retrieving graphic for unknown object!" );
+ if ( aName.getLength() )
+ {
+ 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.getLength() && 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() )
+ {
+ // 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();
+ }
+ 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;
+}
+}