| /************************************************************** |
| * |
| * 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_embeddedobj.hxx" |
| |
| #include <oleembobj.hxx> |
| #include <com/sun/star/embed/EmbedStates.hpp> |
| #include <com/sun/star/embed/EmbedVerbs.hpp> |
| #include <com/sun/star/embed/EntryInitModes.hpp> |
| #include <com/sun/star/embed/XStorage.hpp> |
| #include <com/sun/star/embed/ElementModes.hpp> |
| #include <com/sun/star/embed/EmbedUpdateModes.hpp> |
| #include <com/sun/star/embed/Aspects.hpp> |
| #include <com/sun/star/embed/NeedsRunningStateException.hpp> |
| #include <com/sun/star/embed/StateChangeInProgressException.hpp> |
| #include <com/sun/star/embed/EmbedMisc.hpp> |
| #include <com/sun/star/embed/XEmbedObjectCreator.hpp> |
| #include <com/sun/star/io/XSeekable.hpp> |
| #include <com/sun/star/lang/DisposedException.hpp> |
| #include <com/sun/star/beans/NamedValue.hpp> |
| #include <com/sun/star/beans/XPropertySet.hpp> |
| #include <com/sun/star/frame/XLoadable.hpp> |
| #include <com/sun/star/document/XStorageBasedDocument.hpp> |
| #include <com/sun/star/ucb/XSimpleFileAccess.hpp> |
| #include <com/sun/star/container/XNameAccess.hpp> |
| #include <com/sun/star/container/XNameContainer.hpp> |
| #include <com/sun/star/system/SystemShellExecute.hpp> |
| #include <com/sun/star/system/SystemShellExecuteFlags.hpp> |
| |
| #include <rtl/logfile.hxx> |
| #include <cppuhelper/interfacecontainer.h> |
| #include <comphelper/mimeconfighelper.hxx> |
| #include <comphelper/storagehelper.hxx> |
| #include <comphelper/processfactory.hxx> |
| |
| #include <targetstatecontrol.hxx> |
| |
| #include <olecomponent.hxx> |
| |
| #include "ownview.hxx" |
| |
| using namespace ::com::sun::star; |
| |
| #ifdef WNT |
| //---------------------------------------------- |
| void OleEmbeddedObject::SwitchComponentToRunningState_Impl() |
| { |
| if ( m_pOleComponent ) |
| { |
| try |
| { |
| m_pOleComponent->RunObject(); |
| } |
| catch( embed::UnreachableStateException& ) |
| { |
| GetRidOfComponent(); |
| throw; |
| } |
| catch( embed::WrongStateException& ) |
| { |
| GetRidOfComponent(); |
| throw; |
| } |
| } |
| else |
| { |
| throw embed::UnreachableStateException(); |
| } |
| } |
| |
| //---------------------------------------------- |
| uno::Sequence< sal_Int32 > OleEmbeddedObject::GetReachableStatesList_Impl( |
| const uno::Sequence< embed::VerbDescriptor >& aVerbList ) |
| { |
| uno::Sequence< sal_Int32 > aStates(2); |
| aStates[0] = embed::EmbedStates::LOADED; |
| aStates[1] = embed::EmbedStates::RUNNING; |
| for ( sal_Int32 nInd = 0; nInd < aVerbList.getLength(); nInd++ ) |
| if ( aVerbList[nInd].VerbID == embed::EmbedVerbs::MS_OLEVERB_OPEN ) |
| { |
| aStates.realloc(3); |
| aStates[2] = embed::EmbedStates::ACTIVE; |
| } |
| |
| return aStates; |
| } |
| |
| //---------------------------------------------- |
| uno::Sequence< sal_Int32 > OleEmbeddedObject::GetIntermediateVerbsSequence_Impl( sal_Int32 nNewState ) |
| { |
| OSL_ENSURE( m_nObjectState != embed::EmbedStates::LOADED, "Loaded object is switched to running state without verbs using!" ); |
| |
| // actually there will be only one verb |
| if ( m_nObjectState == embed::EmbedStates::RUNNING && nNewState == embed::EmbedStates::ACTIVE ) |
| { |
| uno::Sequence< sal_Int32 > aVerbs( 1 ); |
| aVerbs[0] = embed::EmbedVerbs::MS_OLEVERB_OPEN; |
| } |
| |
| return uno::Sequence< sal_Int32 >(); |
| } |
| #endif |
| //---------------------------------------------- |
| void OleEmbeddedObject::MoveListeners() |
| { |
| if ( m_pInterfaceContainer ) |
| { |
| // move state change listeners |
| { |
| ::cppu::OInterfaceContainerHelper* pStateChangeContainer = |
| m_pInterfaceContainer->getContainer( ::getCppuType( ( const uno::Reference< embed::XStateChangeListener >*) NULL ) ); |
| if ( pStateChangeContainer != NULL ) |
| { |
| uno::Reference< embed::XStateChangeBroadcaster > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY ); |
| if ( xWrappedObject.is() ) |
| { |
| ::cppu::OInterfaceIteratorHelper pIterator( *pStateChangeContainer ); |
| while ( pIterator.hasMoreElements() ) |
| { |
| try |
| { |
| xWrappedObject->addStateChangeListener( (embed::XStateChangeListener*)pIterator.next() ); |
| } |
| catch( uno::RuntimeException& ) |
| { |
| pIterator.remove(); |
| } |
| } |
| } |
| } |
| } |
| |
| // move event listeners |
| { |
| ::cppu::OInterfaceContainerHelper* pEventContainer = |
| m_pInterfaceContainer->getContainer( ::getCppuType( ( const uno::Reference< document::XEventListener >*) NULL ) ); |
| if ( pEventContainer != NULL ) |
| { |
| uno::Reference< document::XEventBroadcaster > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY ); |
| if ( xWrappedObject.is() ) |
| { |
| ::cppu::OInterfaceIteratorHelper pIterator( *pEventContainer ); |
| while ( pIterator.hasMoreElements() ) |
| { |
| try |
| { |
| xWrappedObject->addEventListener( (document::XEventListener*)pIterator.next() ); |
| } |
| catch( uno::RuntimeException& ) |
| { |
| pIterator.remove(); |
| } |
| } |
| } |
| } |
| } |
| |
| // move close listeners |
| { |
| ::cppu::OInterfaceContainerHelper* pCloseContainer = |
| m_pInterfaceContainer->getContainer( ::getCppuType( ( const uno::Reference< util::XCloseListener >*) NULL ) ); |
| if ( pCloseContainer != NULL ) |
| { |
| uno::Reference< util::XCloseBroadcaster > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY ); |
| if ( xWrappedObject.is() ) |
| { |
| ::cppu::OInterfaceIteratorHelper pIterator( *pCloseContainer ); |
| while ( pIterator.hasMoreElements() ) |
| { |
| try |
| { |
| xWrappedObject->addCloseListener( (util::XCloseListener*)pIterator.next() ); |
| } |
| catch( uno::RuntimeException& ) |
| { |
| pIterator.remove(); |
| } |
| } |
| } |
| } |
| } |
| |
| delete m_pInterfaceContainer; |
| m_pInterfaceContainer = NULL; |
| } |
| } |
| |
| //---------------------------------------------- |
| uno::Reference< embed::XStorage > OleEmbeddedObject::CreateTemporarySubstorage( ::rtl::OUString& o_aStorageName ) |
| { |
| uno::Reference< embed::XStorage > xResult; |
| |
| for ( sal_Int32 nInd = 0; nInd < 32000 && !xResult.is(); nInd++ ) |
| { |
| ::rtl::OUString aName = ::rtl::OUString::valueOf( nInd ); |
| aName += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TMPSTOR" ) ); |
| aName += m_aEntryName; |
| if ( !m_xParentStorage->hasByName( aName ) ) |
| { |
| xResult = m_xParentStorage->openStorageElement( aName, embed::ElementModes::READWRITE ); |
| o_aStorageName = aName; |
| } |
| } |
| |
| if ( !xResult.is() ) |
| { |
| o_aStorageName = ::rtl::OUString(); |
| throw uno::RuntimeException(); |
| } |
| |
| return xResult; |
| } |
| |
| //---------------------------------------------- |
| ::rtl::OUString OleEmbeddedObject::MoveToTemporarySubstream() |
| { |
| ::rtl::OUString aResult; |
| for ( sal_Int32 nInd = 0; nInd < 32000 && !aResult.getLength(); nInd++ ) |
| { |
| ::rtl::OUString aName = ::rtl::OUString::valueOf( nInd ); |
| aName += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TMPSTREAM" ) ); |
| aName += m_aEntryName; |
| if ( !m_xParentStorage->hasByName( aName ) ) |
| { |
| m_xParentStorage->renameElement( m_aEntryName, aName ); |
| aResult = aName; |
| } |
| } |
| |
| if ( !aResult.getLength() ) |
| throw uno::RuntimeException(); |
| |
| return aResult; |
| } |
| |
| //---------------------------------------------- |
| sal_Bool OleEmbeddedObject::TryToConvertToOOo() |
| { |
| sal_Bool bResult = sal_False; |
| |
| ::rtl::OUString aStorageName; |
| ::rtl::OUString aTmpStreamName; |
| sal_Int32 nStep = 0; |
| |
| if ( m_pOleComponent || m_bReadOnly ) |
| return sal_False; |
| |
| try |
| { |
| changeState( embed::EmbedStates::LOADED ); |
| |
| // the stream must be seekable |
| uno::Reference< io::XSeekable > xSeekable( m_xObjectStream, uno::UNO_QUERY_THROW ); |
| xSeekable->seek( 0 ); |
| ::rtl::OUString aFilterName = OwnView_Impl::GetFilterNameFromExtentionAndInStream( m_xFactory, ::rtl::OUString(), m_xObjectStream->getInputStream() ); |
| |
| // use the solution only for OOXML format currently |
| if ( aFilterName.getLength() |
| && ( aFilterName.equals( ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM( "Calc MS Excel 2007 XML" ) ) ) |
| || aFilterName.equals( ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM( "Impress MS PowerPoint 2007 XML" ) ) ) |
| || aFilterName.equals( ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM( "MS Word 2007 XML" ) ) ) ) ) |
| { |
| uno::Reference< container::XNameAccess > xFilterFactory( |
| m_xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.document.FilterFactory" ) ), |
| uno::UNO_QUERY_THROW ); |
| |
| ::rtl::OUString aDocServiceName; |
| uno::Any aFilterAnyData = xFilterFactory->getByName( aFilterName ); |
| uno::Sequence< beans::PropertyValue > aFilterData; |
| if ( aFilterAnyData >>= aFilterData ) |
| { |
| for ( sal_Int32 nInd = 0; nInd < aFilterData.getLength(); nInd++ ) |
| if ( aFilterData[nInd].Name.equalsAscii( "DocumentService" ) ) |
| aFilterData[nInd].Value >>= aDocServiceName; |
| } |
| |
| if ( aDocServiceName.getLength() ) |
| { |
| // create the model |
| uno::Sequence< uno::Any > aArguments(1); |
| aArguments[0] <<= beans::NamedValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "EmbeddedObject" ) ), uno::makeAny( (sal_Bool)sal_True )); |
| |
| uno::Reference< util::XCloseable > xDocument( m_xFactory->createInstanceWithArguments( aDocServiceName, aArguments ), uno::UNO_QUERY_THROW ); |
| uno::Reference< frame::XLoadable > xLoadable( xDocument, uno::UNO_QUERY_THROW ); |
| uno::Reference< document::XStorageBasedDocument > xStorDoc( xDocument, uno::UNO_QUERY_THROW ); |
| |
| // let the model behave as embedded one |
| uno::Reference< frame::XModel > xModel( xDocument, uno::UNO_QUERY_THROW ); |
| uno::Sequence< beans::PropertyValue > aSeq( 1 ); |
| aSeq[0].Name = ::rtl::OUString::createFromAscii( "SetEmbedded" ); |
| aSeq[0].Value <<= sal_True; |
| xModel->attachResource( ::rtl::OUString(), aSeq ); |
| |
| // load the model from the stream |
| uno::Sequence< beans::PropertyValue > aArgs( 5 ); |
| aArgs[0].Name = ::rtl::OUString::createFromAscii( "HierarchicalDocumentName" ); |
| aArgs[0].Value <<= m_aEntryName; |
| aArgs[1].Name = ::rtl::OUString::createFromAscii( "ReadOnly" ); |
| aArgs[1].Value <<= sal_True; |
| aArgs[2].Name = ::rtl::OUString::createFromAscii( "FilterName" ); |
| aArgs[2].Value <<= aFilterName; |
| aArgs[3].Name = ::rtl::OUString::createFromAscii( "URL" ); |
| aArgs[3].Value <<= ::rtl::OUString::createFromAscii( "private:stream" ); |
| aArgs[4].Name = ::rtl::OUString::createFromAscii( "InputStream" ); |
| aArgs[4].Value <<= m_xObjectStream->getInputStream(); |
| |
| xSeekable->seek( 0 ); |
| xLoadable->load( aArgs ); |
| |
| // the model is successfuly loaded, create a new storage and store the model to the storage |
| uno::Reference< embed::XStorage > xTmpStorage = CreateTemporarySubstorage( aStorageName ); |
| xStorDoc->storeToStorage( xTmpStorage, uno::Sequence< beans::PropertyValue >() ); |
| xDocument->close( sal_True ); |
| uno::Reference< beans::XPropertySet > xStorProps( xTmpStorage, uno::UNO_QUERY_THROW ); |
| ::rtl::OUString aMediaType; |
| xStorProps->getPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ) ) >>= aMediaType; |
| xTmpStorage->dispose(); |
| |
| // look for the related embedded object factory |
| ::comphelper::MimeConfigurationHelper aConfigHelper( m_xFactory ); |
| ::rtl::OUString aEmbedFactory; |
| if ( aMediaType.getLength() ) |
| aEmbedFactory = aConfigHelper.GetFactoryNameByMediaType( aMediaType ); |
| |
| if ( !aEmbedFactory.getLength() ) |
| throw uno::RuntimeException(); |
| |
| uno::Reference< uno::XInterface > xFact = m_xFactory->createInstance( aEmbedFactory ); |
| |
| uno::Reference< embed::XEmbedObjectCreator > xEmbCreator( xFact, uno::UNO_QUERY_THROW ); |
| |
| // now the object should be adjusted to become the wrapper |
| nStep = 1; |
| uno::Reference< lang::XComponent > xComp( m_xObjectStream, uno::UNO_QUERY_THROW ); |
| xComp->dispose(); |
| m_xObjectStream = uno::Reference< io::XStream >(); |
| m_nObjectState = -1; |
| |
| nStep = 2; |
| aTmpStreamName = MoveToTemporarySubstream(); |
| |
| nStep = 3; |
| m_xParentStorage->renameElement( aStorageName, m_aEntryName ); |
| |
| nStep = 4; |
| m_xWrappedObject.set( xEmbCreator->createInstanceInitFromEntry( m_xParentStorage, m_aEntryName, uno::Sequence< beans::PropertyValue >(), uno::Sequence< beans::PropertyValue >() ), uno::UNO_QUERY_THROW ); |
| |
| bResult = sal_True; // the change is no more revertable |
| try |
| { |
| m_xParentStorage->removeElement( aTmpStreamName ); |
| } |
| catch( uno::Exception& ) |
| { |
| // the success of the removing is not so important |
| } |
| } |
| } |
| } |
| catch( uno::Exception& ) |
| { |
| // repair the object if necessary |
| switch( nStep ) |
| { |
| case 4: |
| case 3: |
| if ( aTmpStreamName.getLength() && aTmpStreamName != m_aEntryName ) |
| try |
| { |
| if ( m_xParentStorage->hasByName( m_aEntryName ) ) |
| m_xParentStorage->removeElement( m_aEntryName ); |
| m_xParentStorage->renameElement( aTmpStreamName, m_aEntryName ); |
| } |
| catch ( uno::Exception& ) |
| { |
| try { |
| close( sal_True ); |
| } catch( uno::Exception& ) {} |
| |
| m_xParentStorage->dispose(); // ??? the storage has information loss, it should be closed without commiting! |
| throw uno::RuntimeException(); // the repairing is not possible |
| } |
| case 2: |
| try |
| { |
| m_xObjectStream = m_xParentStorage->openStreamElement( m_aEntryName, m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE ); |
| m_nObjectState = embed::EmbedStates::LOADED; |
| } |
| catch( uno::Exception& ) |
| { |
| try { |
| close( sal_True ); |
| } catch( uno::Exception& ) {} |
| |
| throw uno::RuntimeException(); // the repairing is not possible |
| } |
| // no break as designed! |
| |
| case 1: |
| case 0: |
| if ( aStorageName.getLength() ) |
| try { |
| m_xParentStorage->removeElement( aStorageName ); |
| } catch( uno::Exception& ) { OSL_ASSERT( "Can not remove temporary storage!" ); } |
| break; |
| } |
| } |
| |
| if ( bResult ) |
| { |
| // the conversion was done successfuly, now the additional initializations should happen |
| |
| MoveListeners(); |
| m_xWrappedObject->setClientSite( m_xClientSite ); |
| if ( m_xParent.is() ) |
| { |
| uno::Reference< container::XChild > xChild( m_xWrappedObject, uno::UNO_QUERY ); |
| if ( xChild.is() ) |
| xChild->setParent( m_xParent ); |
| } |
| |
| } |
| |
| return bResult; |
| } |
| |
| //---------------------------------------------- |
| void SAL_CALL OleEmbeddedObject::changeState( sal_Int32 nNewState ) |
| throw ( embed::UnreachableStateException, |
| embed::WrongStateException, |
| uno::Exception, |
| uno::RuntimeException ) |
| { |
| RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::changeState" ); |
| |
| // begin wrapping related part ==================== |
| uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject; |
| if ( xWrappedObject.is() ) |
| { |
| // the object was converted to OOo embedded object, the current implementation is now only a wrapper |
| xWrappedObject->changeState( nNewState ); |
| return; |
| } |
| // end wrapping related part ==================== |
| |
| ::osl::ResettableMutexGuard aGuard( m_aMutex ); |
| |
| if ( m_bDisposed ) |
| throw lang::DisposedException(); // TODO |
| |
| if ( m_nObjectState == -1 ) |
| throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ), |
| uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) ); |
| |
| // in case the object is already in requested state |
| if ( m_nObjectState == nNewState ) |
| return; |
| |
| #ifdef WNT |
| if ( m_pOleComponent ) |
| { |
| if ( m_nTargetState != -1 ) |
| { |
| // means that the object is currently trying to reach the target state |
| throw embed::StateChangeInProgressException( ::rtl::OUString(), |
| uno::Reference< uno::XInterface >(), |
| m_nTargetState ); |
| } |
| |
| TargetStateControl_Impl aControl( m_nTargetState, nNewState ); |
| |
| // TODO: additional verbs can be a problem, since nobody knows how the object |
| // will behave after activation |
| |
| sal_Int32 nOldState = m_nObjectState; |
| aGuard.clear(); |
| StateChangeNotification_Impl( sal_True, nOldState, nNewState ); |
| aGuard.reset(); |
| |
| try |
| { |
| if ( nNewState == embed::EmbedStates::LOADED ) |
| { |
| // This means just closing of the current object |
| // If component can not be closed the object stays in loaded state |
| // and it holds reference to "incomplete" component |
| // If the object is switched to running state later |
| // the component will become "complete" |
| |
| // the loaded state must be set before, because of notifications! |
| m_nObjectState = nNewState; |
| |
| { |
| VerbExecutionControllerGuard aVerbGuard( m_aVerbExecutionController ); |
| m_pOleComponent->CloseObject(); |
| } |
| |
| // GetRidOfComponent(); |
| aGuard.clear(); |
| StateChangeNotification_Impl( sal_False, nOldState, m_nObjectState ); |
| aGuard.reset(); |
| } |
| else if ( nNewState == embed::EmbedStates::RUNNING || nNewState == embed::EmbedStates::ACTIVE ) |
| { |
| if ( m_nObjectState == embed::EmbedStates::LOADED ) |
| { |
| // if the target object is in loaded state and a different state is specified |
| // as a new one the object first must be switched to running state. |
| |
| // the component can exist already in nonrunning state |
| // it can be created during loading to detect type of object |
| CreateOleComponentAndLoad_Impl( m_pOleComponent ); |
| |
| SwitchComponentToRunningState_Impl(); |
| m_nObjectState = embed::EmbedStates::RUNNING; |
| aGuard.clear(); |
| StateChangeNotification_Impl( sal_False, nOldState, m_nObjectState ); |
| aGuard.reset(); |
| |
| if ( m_pOleComponent && m_bHasSizeToSet ) |
| { |
| aGuard.clear(); |
| try { |
| m_pOleComponent->SetExtent( m_aSizeToSet, m_nAspectToSet ); |
| m_bHasSizeToSet = sal_False; |
| } |
| catch( uno::Exception& ) {} |
| aGuard.reset(); |
| } |
| |
| if ( m_nObjectState == nNewState ) |
| return; |
| } |
| |
| // so now the object is either switched from Active to Running state or vise versa |
| // the notification about object state change will be done asynchronously |
| if ( m_nObjectState == embed::EmbedStates::RUNNING && nNewState == embed::EmbedStates::ACTIVE ) |
| { |
| // execute OPEN verb, if object does not reach active state it is an object's problem |
| aGuard.clear(); |
| m_pOleComponent->ExecuteVerb( embed::EmbedVerbs::MS_OLEVERB_OPEN ); |
| aGuard.reset(); |
| |
| // some objects do not allow to set the size even in running state |
| if ( m_pOleComponent && m_bHasSizeToSet ) |
| { |
| aGuard.clear(); |
| try { |
| m_pOleComponent->SetExtent( m_aSizeToSet, m_nAspectToSet ); |
| m_bHasSizeToSet = sal_False; |
| } |
| catch( uno::Exception& ) {} |
| aGuard.reset(); |
| } |
| |
| m_nObjectState = nNewState; |
| } |
| else if ( m_nObjectState == embed::EmbedStates::ACTIVE && nNewState == embed::EmbedStates::RUNNING ) |
| { |
| aGuard.clear(); |
| m_pOleComponent->CloseObject(); |
| m_pOleComponent->RunObject(); // Should not fail, the object already was active |
| aGuard.reset(); |
| m_nObjectState = nNewState; |
| } |
| else |
| { |
| throw embed::UnreachableStateException(); |
| } |
| } |
| else |
| throw embed::UnreachableStateException(); |
| } |
| catch( uno::Exception& ) |
| { |
| aGuard.clear(); |
| StateChangeNotification_Impl( sal_False, nOldState, m_nObjectState ); |
| throw; |
| } |
| } |
| else |
| #endif |
| { |
| throw embed::UnreachableStateException(); |
| } |
| } |
| |
| //---------------------------------------------- |
| uno::Sequence< sal_Int32 > SAL_CALL OleEmbeddedObject::getReachableStates() |
| throw ( embed::WrongStateException, |
| uno::RuntimeException ) |
| { |
| RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::getReachableStates" ); |
| |
| // begin wrapping related part ==================== |
| uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject; |
| if ( xWrappedObject.is() ) |
| { |
| // the object was converted to OOo embedded object, the current implementation is now only a wrapper |
| return xWrappedObject->getReachableStates(); |
| } |
| // end wrapping related part ==================== |
| |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| if ( m_bDisposed ) |
| throw lang::DisposedException(); // TODO |
| |
| if ( m_nObjectState == -1 ) |
| throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ), |
| uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) ); |
| |
| #ifdef WNT |
| if ( m_pOleComponent ) |
| { |
| if ( m_nObjectState == embed::EmbedStates::LOADED ) |
| { |
| // the list of supported verbs can be retrieved only when object is in running state |
| throw embed::NeedsRunningStateException(); // TODO: |
| } |
| |
| // the list of states can only be guessed based on standard verbs, |
| // since there is no way to detect what additional verbs do |
| return GetReachableStatesList_Impl( m_pOleComponent->GetVerbList() ); |
| } |
| else |
| #endif |
| { |
| return uno::Sequence< sal_Int32 >(); |
| } |
| } |
| |
| //---------------------------------------------- |
| sal_Int32 SAL_CALL OleEmbeddedObject::getCurrentState() |
| throw ( embed::WrongStateException, |
| uno::RuntimeException ) |
| { |
| // begin wrapping related part ==================== |
| uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject; |
| if ( xWrappedObject.is() ) |
| { |
| // the object was converted to OOo embedded object, the current implementation is now only a wrapper |
| return xWrappedObject->getCurrentState(); |
| } |
| // end wrapping related part ==================== |
| |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| if ( m_bDisposed ) |
| throw lang::DisposedException(); // TODO |
| |
| if ( m_nObjectState == -1 ) |
| throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ), |
| uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) ); |
| |
| // TODO: Shouldn't we ask object? ( I guess no ) |
| return m_nObjectState; |
| } |
| |
| namespace |
| { |
| bool lcl_CopyStream(uno::Reference<io::XInputStream> xIn, uno::Reference<io::XOutputStream> xOut) |
| { |
| const sal_Int32 nChunkSize = 4096; |
| uno::Sequence< sal_Int8 > aData(nChunkSize); |
| sal_Int32 nTotalRead = 0; |
| sal_Int32 nRead; |
| do |
| { |
| nRead = xIn->readBytes(aData, nChunkSize); |
| nTotalRead += nRead; |
| xOut->writeBytes(aData); |
| } while (nRead == nChunkSize); |
| return nTotalRead != 0; |
| } |
| |
| //Dump the objects content to a tempfile, just the "CONTENTS" stream if |
| //there is one for non-compound documents, otherwise the whole content. |
| // |
| //On success a file is returned which must be removed by the caller |
| rtl::OUString lcl_ExtractObject(::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xFactory, |
| ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream > xObjectStream) |
| { |
| rtl::OUString sUrl; |
| |
| // the solution is only active for Unix systems |
| #ifndef WNT |
| uno::Reference <beans::XPropertySet> xNativeTempFile( |
| xFactory->createInstance( |
| ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.io.TempFile"))), uno::UNO_QUERY_THROW); |
| uno::Reference < io::XStream > xStream(xNativeTempFile, uno::UNO_QUERY_THROW); |
| |
| uno::Sequence< uno::Any > aArgs( 2 ); |
| aArgs[0] <<= xObjectStream; |
| aArgs[1] <<= (sal_Bool)sal_True; // do not create copy |
| uno::Reference< container::XNameContainer > xNameContainer( |
| xFactory->createInstanceWithArguments( |
| ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.embed.OLESimpleStorage")), |
| aArgs ), uno::UNO_QUERY_THROW ); |
| |
| uno::Reference< io::XStream > xCONTENTS; |
| xNameContainer->getByName(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CONTENTS"))) >>= xCONTENTS; |
| |
| sal_Bool bCopied = xCONTENTS.is() && lcl_CopyStream(xCONTENTS->getInputStream(), xStream->getOutputStream()); |
| |
| uno::Reference< io::XSeekable > xSeekableStor(xObjectStream, uno::UNO_QUERY); |
| if (xSeekableStor.is()) |
| xSeekableStor->seek(0); |
| |
| if (!bCopied) |
| bCopied = lcl_CopyStream(xObjectStream->getInputStream(), xStream->getOutputStream()); |
| |
| if (bCopied) |
| { |
| xNativeTempFile->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("RemoveFile")), |
| uno::makeAny(sal_False)); |
| uno::Any aUrl = xNativeTempFile->getPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Uri"))); |
| aUrl >>= sUrl; |
| |
| xNativeTempFile = uno::Reference<beans::XPropertySet>(); |
| |
| uno::Reference<ucb::XSimpleFileAccess> xSimpleFileAccess( |
| xFactory->createInstance( |
| ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.ucb.SimpleFileAccess"))), |
| uno::UNO_QUERY_THROW); |
| |
| xSimpleFileAccess->setReadOnly(sUrl, sal_True); |
| } |
| else |
| { |
| xNativeTempFile->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("RemoveFile")), |
| uno::makeAny(sal_True)); |
| } |
| #endif |
| return sUrl; |
| } |
| } |
| |
| //---------------------------------------------- |
| void SAL_CALL OleEmbeddedObject::doVerb( sal_Int32 nVerbID ) |
| throw ( lang::IllegalArgumentException, |
| embed::WrongStateException, |
| embed::UnreachableStateException, |
| uno::Exception, |
| uno::RuntimeException ) |
| { |
| RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::doVerb" ); |
| |
| // begin wrapping related part ==================== |
| uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject; |
| if ( xWrappedObject.is() ) |
| { |
| // the object was converted to OOo embedded object, the current implementation is now only a wrapper |
| xWrappedObject->doVerb( nVerbID ); |
| return; |
| } |
| // end wrapping related part ==================== |
| |
| ::osl::ResettableMutexGuard aGuard( m_aMutex ); |
| if ( m_bDisposed ) |
| throw lang::DisposedException(); // TODO |
| |
| if ( m_nObjectState == -1 ) |
| throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ), |
| uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) ); |
| |
| #ifdef WNT |
| if ( m_pOleComponent ) |
| { |
| sal_Int32 nOldState = m_nObjectState; |
| |
| // TODO/LATER detect target state here and do a notification |
| // StateChangeNotification_Impl( sal_True, nOldState, nNewState ); |
| if ( m_nObjectState == embed::EmbedStates::LOADED ) |
| { |
| // if the target object is in loaded state |
| // it must be switched to running state to execute verb |
| aGuard.clear(); |
| changeState( embed::EmbedStates::RUNNING ); |
| aGuard.reset(); |
| } |
| |
| try { |
| if ( !m_pOleComponent ) |
| throw uno::RuntimeException(); |
| |
| // ==== the STAMPIT related solution ============================= |
| m_aVerbExecutionController.StartControlExecution(); |
| // =============================================================== |
| |
| m_pOleComponent->ExecuteVerb( nVerbID ); |
| |
| // ==== the STAMPIT related solution ============================= |
| sal_Bool bModifiedOnExecution = m_aVerbExecutionController.EndControlExecution_WasModified(); |
| |
| // this workaround is implemented for STAMPIT object |
| // if object was modified during verb execution it is saved here |
| if ( bModifiedOnExecution && m_pOleComponent->IsDirty() ) |
| SaveObject_Impl(); |
| // =============================================================== |
| } |
| catch( uno::Exception& ) |
| { |
| // ==== the STAMPIT related solution ============================= |
| m_aVerbExecutionController.EndControlExecution_WasModified(); |
| // =============================================================== |
| |
| aGuard.clear(); |
| StateChangeNotification_Impl( sal_False, nOldState, m_nObjectState ); |
| throw; |
| } |
| |
| // the following notification will be done asynchronously |
| // StateChangeNotification_Impl( sal_False, nOldState, m_nObjectState ); |
| } |
| else |
| #endif |
| { |
| if ( nVerbID == -9 ) |
| { |
| // the workaround verb to show the object in case no server is available |
| |
| // if it is possible, the object will be converted to OOo format |
| if ( !m_bTriedConversion ) |
| { |
| m_bTriedConversion = sal_True; |
| if ( TryToConvertToOOo() ) |
| { |
| changeState( embed::EmbedStates::UI_ACTIVE ); |
| return; |
| } |
| } |
| |
| if ( !m_pOwnView && m_xObjectStream.is() ) |
| { |
| try { |
| uno::Reference< io::XSeekable > xSeekable( m_xObjectStream, uno::UNO_QUERY ); |
| if ( xSeekable.is() ) |
| xSeekable->seek( 0 ); |
| |
| m_pOwnView = new OwnView_Impl( m_xFactory, m_xObjectStream->getInputStream() ); |
| m_pOwnView->acquire(); |
| } |
| catch( uno::RuntimeException& ) |
| { |
| throw; |
| } |
| catch( uno::Exception& ) |
| { |
| } |
| } |
| |
| if ( !m_pOwnView || !m_pOwnView->Open() ) |
| { |
| //Make a RO copy and see if the OS can find something to at |
| //least display the content for us |
| if (!m_aTempDumpURL.getLength()) |
| m_aTempDumpURL = lcl_ExtractObject(m_xFactory, m_xObjectStream); |
| |
| if (m_aTempDumpURL.getLength()) |
| { |
| uno::Reference< ::com::sun::star::system::XSystemShellExecute > xSystemShellExecute( |
| ::com::sun::star::system::SystemShellExecute::create( |
| ::comphelper::getProcessComponentContext() ) ); |
| xSystemShellExecute->execute(m_aTempDumpURL, ::rtl::OUString(), ::com::sun::star::system::SystemShellExecuteFlags::DEFAULTS); |
| } |
| else |
| throw embed::UnreachableStateException(); |
| } |
| } |
| else |
| { |
| |
| throw embed::UnreachableStateException(); |
| } |
| } |
| } |
| |
| //---------------------------------------------- |
| uno::Sequence< embed::VerbDescriptor > SAL_CALL OleEmbeddedObject::getSupportedVerbs() |
| throw ( embed::WrongStateException, |
| uno::RuntimeException ) |
| { |
| RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::getSupportedVerb" ); |
| |
| // begin wrapping related part ==================== |
| uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject; |
| if ( xWrappedObject.is() ) |
| { |
| // the object was converted to OOo embedded object, the current implementation is now only a wrapper |
| return xWrappedObject->getSupportedVerbs(); |
| } |
| // end wrapping related part ==================== |
| |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| if ( m_bDisposed ) |
| throw lang::DisposedException(); // TODO |
| |
| if ( m_nObjectState == -1 ) |
| throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ), |
| uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) ); |
| #ifdef WNT |
| if ( m_pOleComponent ) |
| { |
| // registry could be used in this case |
| // if ( m_nObjectState == embed::EmbedStates::LOADED ) |
| // { |
| // // the list of supported verbs can be retrieved only when object is in running state |
| // throw embed::NeedsRunningStateException(); // TODO: |
| // } |
| |
| return m_pOleComponent->GetVerbList(); |
| } |
| else |
| #endif |
| { |
| return uno::Sequence< embed::VerbDescriptor >(); |
| } |
| } |
| |
| //---------------------------------------------- |
| void SAL_CALL OleEmbeddedObject::setClientSite( |
| const uno::Reference< embed::XEmbeddedClient >& xClient ) |
| throw ( embed::WrongStateException, |
| uno::RuntimeException ) |
| { |
| // begin wrapping related part ==================== |
| uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject; |
| if ( xWrappedObject.is() ) |
| { |
| // the object was converted to OOo embedded object, the current implementation is now only a wrapper |
| xWrappedObject->setClientSite( xClient ); |
| return; |
| } |
| // end wrapping related part ==================== |
| |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| if ( m_bDisposed ) |
| throw lang::DisposedException(); // TODO |
| |
| if ( m_xClientSite != xClient) |
| { |
| if ( m_nObjectState != embed::EmbedStates::LOADED && m_nObjectState != embed::EmbedStates::RUNNING ) |
| throw embed::WrongStateException( |
| ::rtl::OUString::createFromAscii( "The client site can not be set currently!\n" ), |
| uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) ); |
| |
| m_xClientSite = xClient; |
| } |
| } |
| |
| //---------------------------------------------- |
| uno::Reference< embed::XEmbeddedClient > SAL_CALL OleEmbeddedObject::getClientSite() |
| throw ( embed::WrongStateException, |
| uno::RuntimeException ) |
| { |
| // begin wrapping related part ==================== |
| uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject; |
| if ( xWrappedObject.is() ) |
| { |
| // the object was converted to OOo embedded object, the current implementation is now only a wrapper |
| return xWrappedObject->getClientSite(); |
| } |
| // end wrapping related part ==================== |
| |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| if ( m_bDisposed ) |
| throw lang::DisposedException(); // TODO |
| |
| if ( m_nObjectState == -1 ) |
| throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ), |
| uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) ); |
| |
| return m_xClientSite; |
| } |
| |
| //---------------------------------------------- |
| void SAL_CALL OleEmbeddedObject::update() |
| throw ( embed::WrongStateException, |
| uno::Exception, |
| uno::RuntimeException ) |
| { |
| // begin wrapping related part ==================== |
| uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject; |
| if ( xWrappedObject.is() ) |
| { |
| // the object was converted to OOo embedded object, the current implementation is now only a wrapper |
| xWrappedObject->update(); |
| return; |
| } |
| // end wrapping related part ==================== |
| |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| if ( m_bDisposed ) |
| throw lang::DisposedException(); // TODO |
| |
| if ( m_nObjectState == -1 ) |
| throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ), |
| uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) ); |
| |
| if ( m_nUpdateMode == embed::EmbedUpdateModes::EXPLICIT_UPDATE ) |
| { |
| // TODO: update view representation |
| } |
| else |
| { |
| // the object must be up to date |
| OSL_ENSURE( m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE, "Unknown update mode!\n" ); |
| } |
| } |
| |
| //---------------------------------------------- |
| void SAL_CALL OleEmbeddedObject::setUpdateMode( sal_Int32 nMode ) |
| throw ( embed::WrongStateException, |
| uno::RuntimeException ) |
| { |
| // begin wrapping related part ==================== |
| uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject; |
| if ( xWrappedObject.is() ) |
| { |
| // the object was converted to OOo embedded object, the current implementation is now only a wrapper |
| xWrappedObject->setUpdateMode( nMode ); |
| return; |
| } |
| // end wrapping related part ==================== |
| |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| if ( m_bDisposed ) |
| throw lang::DisposedException(); // TODO |
| |
| if ( m_nObjectState == -1 ) |
| throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ), |
| uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) ); |
| |
| OSL_ENSURE( nMode == embed::EmbedUpdateModes::ALWAYS_UPDATE |
| || nMode == embed::EmbedUpdateModes::EXPLICIT_UPDATE, |
| "Unknown update mode!\n" ); |
| m_nUpdateMode = nMode; |
| } |
| |
| //---------------------------------------------- |
| sal_Int64 SAL_CALL OleEmbeddedObject::getStatus( sal_Int64 |
| nAspect |
| ) |
| throw ( embed::WrongStateException, |
| uno::RuntimeException ) |
| { |
| // begin wrapping related part ==================== |
| uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject; |
| if ( xWrappedObject.is() ) |
| { |
| // the object was converted to OOo embedded object, the current implementation is now only a wrapper |
| return xWrappedObject->getStatus( nAspect ); |
| } |
| // end wrapping related part ==================== |
| |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| if ( m_bDisposed ) |
| throw lang::DisposedException(); // TODO |
| |
| if ( m_nObjectState == -1 ) |
| throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object must be in running state!\n" ), |
| uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) ); |
| |
| sal_Int64 nResult = 0; |
| |
| #ifdef WNT |
| if ( m_bGotStatus && m_nStatusAspect == nAspect ) |
| nResult = m_nStatus; |
| else if ( m_pOleComponent ) |
| { |
| // OLE should allow to get status even in loaded state |
| // if ( m_nObjectState == embed::EmbedStates::LOADED ) |
| // changeState( m_nObjectState == embed::EmbedStates::RUNNING ); |
| |
| m_nStatus = m_pOleComponent->GetMiscStatus( nAspect ); |
| m_nStatusAspect = nAspect; |
| m_bGotStatus = sal_True; |
| nResult = m_nStatus; |
| } |
| #endif |
| |
| // this implementation needs size to be provided after object loading/creating to work in optimal way |
| return ( nResult | embed::EmbedMisc::EMBED_NEEDSSIZEONLOAD ); |
| } |
| |
| //---------------------------------------------- |
| void SAL_CALL OleEmbeddedObject::setContainerName( const ::rtl::OUString& sName ) |
| throw ( uno::RuntimeException ) |
| { |
| // begin wrapping related part ==================== |
| uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject; |
| if ( xWrappedObject.is() ) |
| { |
| // the object was converted to OOo embedded object, the current implementation is now only a wrapper |
| xWrappedObject->setContainerName( sName ); |
| return; |
| } |
| // end wrapping related part ==================== |
| |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| if ( m_bDisposed ) |
| throw lang::DisposedException(); // TODO |
| |
| m_aContainerName = sName; |
| } |
| |
| |