build fix
[LibreOffice.git] / embeddedobj / source / commonembedding / persistence.cxx
blob036dc026735d9ba48d5f53dd9ad055ffe7ea0571
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <commonembobj.hxx>
21 #include <com/sun/star/embed/Aspects.hpp>
22 #include <com/sun/star/document/XStorageBasedDocument.hpp>
23 #include <com/sun/star/embed/EmbedStates.hpp>
24 #include <com/sun/star/embed/EmbedVerbs.hpp>
25 #include <com/sun/star/embed/EntryInitModes.hpp>
26 #include <com/sun/star/embed/XStorage.hpp>
27 #include <com/sun/star/embed/XOptimizedStorage.hpp>
28 #include <com/sun/star/embed/ElementModes.hpp>
29 #include <com/sun/star/embed/EmbedUpdateModes.hpp>
30 #include <com/sun/star/embed/StorageFactory.hpp>
31 #include <com/sun/star/io/TempFile.hpp>
32 #include <com/sun/star/frame/XModel.hpp>
33 #include <com/sun/star/frame/XStorable.hpp>
34 #include <com/sun/star/frame/XLoadable.hpp>
35 #include <com/sun/star/frame/XComponentLoader.hpp>
36 #include <com/sun/star/frame/XModule.hpp>
37 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
38 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
39 #include <com/sun/star/lang/DisposedException.hpp>
40 #include <com/sun/star/util/XModifiable.hpp>
42 #include <com/sun/star/container/XNameAccess.hpp>
43 #include <com/sun/star/container/XChild.hpp>
44 #include <com/sun/star/util/XCloseable.hpp>
45 #include <com/sun/star/beans/XPropertySet.hpp>
46 #include <com/sun/star/beans/IllegalTypeException.hpp>
47 #include <com/sun/star/chart2/XChartDocument.hpp>
49 #include <comphelper/fileformat.h>
50 #include <comphelper/processfactory.hxx>
51 #include <comphelper/storagehelper.hxx>
52 #include <comphelper/mimeconfighelper.hxx>
53 #include <comphelper/namedvaluecollection.hxx>
55 #include <tools/diagnose_ex.h>
56 #include "persistence.hxx"
58 using namespace ::com::sun::star;
61 uno::Sequence< beans::PropertyValue > GetValuableArgs_Impl( const uno::Sequence< beans::PropertyValue >& aMedDescr,
62 bool bCanUseDocumentBaseURL )
64 uno::Sequence< beans::PropertyValue > aResult;
65 sal_Int32 nResLen = 0;
67 for ( sal_Int32 nInd = 0; nInd < aMedDescr.getLength(); nInd++ )
69 if ( aMedDescr[nInd].Name == "ComponentData" || aMedDescr[nInd].Name == "DocumentTitle"
70 || aMedDescr[nInd].Name == "InteractionHandler" || aMedDescr[nInd].Name == "JumpMark"
71 // || aMedDescr[nInd].Name == "Password" // makes no sense for embedded objects
72 || aMedDescr[nInd].Name == "Preview" || aMedDescr[nInd].Name == "ReadOnly"
73 || aMedDescr[nInd].Name == "StartPresentation" || aMedDescr[nInd].Name == "RepairPackage"
74 || aMedDescr[nInd].Name == "StatusIndicator" || aMedDescr[nInd].Name == "ViewData"
75 || aMedDescr[nInd].Name == "ViewId" || aMedDescr[nInd].Name == "MacroExecutionMode"
76 || aMedDescr[nInd].Name == "UpdateDocMode"
77 || (aMedDescr[nInd].Name == "DocumentBaseURL" && bCanUseDocumentBaseURL) )
79 aResult.realloc( ++nResLen );
80 aResult[nResLen-1] = aMedDescr[nInd];
84 return aResult;
88 uno::Sequence< beans::PropertyValue > addAsTemplate( const uno::Sequence< beans::PropertyValue >& aOrig )
90 bool bAsTemplateSet = false;
91 sal_Int32 nLength = aOrig.getLength();
92 uno::Sequence< beans::PropertyValue > aResult( nLength );
94 for ( sal_Int32 nInd = 0; nInd < nLength; nInd++ )
96 aResult[nInd].Name = aOrig[nInd].Name;
97 if ( aResult[nInd].Name == "AsTemplate" )
99 aResult[nInd].Value <<= true;
100 bAsTemplateSet = true;
102 else
103 aResult[nInd].Value = aOrig[nInd].Value;
106 if ( !bAsTemplateSet )
108 aResult.realloc( nLength + 1 );
109 aResult[nLength].Name = "AsTemplate";
110 aResult[nLength].Value <<= true;
113 return aResult;
117 uno::Reference< io::XInputStream > createTempInpStreamFromStor(
118 const uno::Reference< embed::XStorage >& xStorage,
119 const uno::Reference< uno::XComponentContext >& xContext )
121 SAL_WARN_IF( !xStorage.is(), "embeddedobj.common", "The storage can not be empty!" );
123 uno::Reference< io::XInputStream > xResult;
125 uno::Reference < io::XStream > xTempStream( io::TempFile::create(xContext), uno::UNO_QUERY_THROW );
127 uno::Reference < lang::XSingleServiceFactory > xStorageFactory( embed::StorageFactory::create(xContext) );
129 uno::Sequence< uno::Any > aArgs( 2 );
130 aArgs[0] <<= xTempStream;
131 aArgs[1] <<= embed::ElementModes::READWRITE;
132 uno::Reference< embed::XStorage > xTempStorage( xStorageFactory->createInstanceWithArguments( aArgs ),
133 uno::UNO_QUERY );
134 if ( !xTempStorage.is() )
135 throw uno::RuntimeException(); // TODO:
139 xStorage->copyToStorage( xTempStorage );
140 } catch( const uno::Exception& e )
142 throw embed::StorageWrappedTargetException(
143 "Can't copy storage!",
144 uno::Reference< uno::XInterface >(),
145 uno::makeAny( e ) );
148 try {
149 uno::Reference< lang::XComponent > xComponent( xTempStorage, uno::UNO_QUERY );
150 SAL_WARN_IF( !xComponent.is(), "embeddedobj.common", "Wrong storage implementation!" );
151 if ( xComponent.is() )
152 xComponent->dispose();
154 catch ( const uno::Exception& )
158 try {
159 uno::Reference< io::XOutputStream > xTempOut = xTempStream->getOutputStream();
160 if ( xTempOut.is() )
161 xTempOut->closeOutput();
163 catch ( const uno::Exception& )
167 xResult = xTempStream->getInputStream();
169 return xResult;
174 static void TransferMediaType( const uno::Reference< embed::XStorage >& i_rSource, const uno::Reference< embed::XStorage >& i_rTarget )
178 const uno::Reference< beans::XPropertySet > xSourceProps( i_rSource, uno::UNO_QUERY_THROW );
179 const uno::Reference< beans::XPropertySet > xTargetProps( i_rTarget, uno::UNO_QUERY_THROW );
180 const OUString sMediaTypePropName( "MediaType" );
181 xTargetProps->setPropertyValue( sMediaTypePropName, xSourceProps->getPropertyValue( sMediaTypePropName ) );
183 catch( const uno::Exception& )
185 DBG_UNHANDLED_EXCEPTION();
190 static uno::Reference< util::XCloseable > CreateDocument( const uno::Reference< uno::XComponentContext >& _rxContext,
191 const OUString& _rDocumentServiceName, bool _bEmbeddedScriptSupport, const bool i_bDocumentRecoverySupport )
193 ::comphelper::NamedValueCollection aArguments;
194 aArguments.put( "EmbeddedObject", true );
195 aArguments.put( "EmbeddedScriptSupport", _bEmbeddedScriptSupport );
196 aArguments.put( "DocumentRecoverySupport", i_bDocumentRecoverySupport );
198 uno::Reference< uno::XInterface > xDocument;
201 xDocument = _rxContext->getServiceManager()->createInstanceWithArgumentsAndContext(
202 _rDocumentServiceName, aArguments.getWrappedPropertyValues(), _rxContext );
204 catch( const uno::Exception& )
206 // if an embedded object implementation does not support XInitialization,
207 // the default factory from cppuhelper will throw an
208 // IllegalArgumentException when we try to create the instance with arguments.
209 // Okay, so we fall back to creating the instance without any arguments.
210 OSL_FAIL("Consider implementing interface XInitialization to avoid duplicate construction");
211 xDocument = _rxContext->getServiceManager()->createInstanceWithContext( _rDocumentServiceName, _rxContext );
214 SAL_WARN_IF(!xDocument.is(), "embeddedobj.common", "Service " << _rDocumentServiceName << " is not available?");
215 return uno::Reference< util::XCloseable >( xDocument, uno::UNO_QUERY );
219 static void SetDocToEmbedded( const uno::Reference< frame::XModel >& rDocument, const OUString& aModuleName )
221 if (rDocument.is())
223 uno::Sequence< beans::PropertyValue > aSeq( 1 );
224 aSeq[0].Name = "SetEmbedded";
225 aSeq[0].Value <<= true;
226 rDocument->attachResource( OUString(), aSeq );
228 if ( !aModuleName.isEmpty() )
232 uno::Reference< frame::XModule > xModule( rDocument, uno::UNO_QUERY_THROW );
233 xModule->setIdentifier( aModuleName );
235 catch( const uno::Exception& )
242 void OCommonEmbeddedObject::SwitchOwnPersistence( const uno::Reference< embed::XStorage >& xNewParentStorage,
243 const uno::Reference< embed::XStorage >& xNewObjectStorage,
244 const OUString& aNewName )
246 if ( xNewParentStorage == m_xParentStorage && aNewName.equals( m_aEntryName ) )
248 SAL_WARN_IF( xNewObjectStorage != m_xObjectStorage, "embeddedobj.common", "The storage must be the same!" );
249 return;
252 uno::Reference< lang::XComponent > xComponent( m_xObjectStorage, uno::UNO_QUERY );
253 OSL_ENSURE( !m_xObjectStorage.is() || xComponent.is(), "Wrong storage implementation!" );
255 m_xObjectStorage = xNewObjectStorage;
256 m_xParentStorage = xNewParentStorage;
257 m_aEntryName = aNewName;
259 // the linked document should not be switched
260 if ( !m_bIsLink )
262 uno::Reference< document::XStorageBasedDocument > xDoc( m_pDocHolder->GetComponent(), uno::UNO_QUERY );
263 if ( xDoc.is() )
264 SwitchDocToStorage_Impl( xDoc, m_xObjectStorage );
267 try {
268 if ( xComponent.is() )
269 xComponent->dispose();
271 catch ( const uno::Exception& )
277 void OCommonEmbeddedObject::SwitchOwnPersistence( const uno::Reference< embed::XStorage >& xNewParentStorage,
278 const OUString& aNewName )
280 if ( xNewParentStorage == m_xParentStorage && aNewName.equals( m_aEntryName ) )
281 return;
283 sal_Int32 nStorageMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
285 uno::Reference< embed::XStorage > xNewOwnStorage = xNewParentStorage->openStorageElement( aNewName, nStorageMode );
286 SAL_WARN_IF( !xNewOwnStorage.is(), "embeddedobj.common", "The method can not return empty reference!" );
288 SwitchOwnPersistence( xNewParentStorage, xNewOwnStorage, aNewName );
292 void OCommonEmbeddedObject::EmbedAndReparentDoc_Impl( const uno::Reference< util::XCloseable >& i_rxDocument ) const
294 SetDocToEmbedded( uno::Reference< frame::XModel >( i_rxDocument, uno::UNO_QUERY ), m_aModuleName );
298 uno::Reference < container::XChild > xChild( i_rxDocument, uno::UNO_QUERY );
299 if ( xChild.is() )
300 xChild->setParent( m_xParent );
302 catch( const lang::NoSupportException & )
304 SAL_WARN( "embeddedobj.common", "OCommonEmbeddedObject::EmbedAndReparentDoc: cannot set parent at document!" );
309 uno::Reference< util::XCloseable > OCommonEmbeddedObject::InitNewDocument_Impl()
311 uno::Reference< util::XCloseable > xDocument( CreateDocument( m_xContext, GetDocumentServiceName(),
312 m_bEmbeddedScriptSupport, m_bDocumentRecoverySupport ) );
314 uno::Reference< frame::XModel > xModel( xDocument, uno::UNO_QUERY );
315 uno::Reference< frame::XLoadable > xLoadable( xModel, uno::UNO_QUERY );
316 if ( !xLoadable.is() )
317 throw uno::RuntimeException();
321 // set the document mode to embedded as the first action on document!!!
322 EmbedAndReparentDoc_Impl( xDocument );
324 // if we have a storage to recover the document from, do not use initNew, but instead load from that storage
325 bool bInitNew = true;
326 if ( m_xRecoveryStorage.is() )
328 uno::Reference< document::XStorageBasedDocument > xDoc( xLoadable, uno::UNO_QUERY );
329 SAL_WARN_IF( !xDoc.is(), "embeddedobj.common", "OCommonEmbeddedObject::InitNewDocument_Impl: cannot recover from a storage when the document is not storage based!" );
330 if ( xDoc.is() )
332 ::comphelper::NamedValueCollection aLoadArgs;
333 FillDefaultLoadArgs_Impl( m_xRecoveryStorage, aLoadArgs );
335 xDoc->loadFromStorage( m_xRecoveryStorage, aLoadArgs.getPropertyValues() );
336 SwitchDocToStorage_Impl( xDoc, m_xObjectStorage );
337 bInitNew = false;
341 if ( bInitNew )
343 // init document as a new
344 xLoadable->initNew();
346 xModel->attachResource( xModel->getURL(), m_aDocMediaDescriptor );
348 catch( const uno::Exception& )
350 uno::Reference< util::XCloseable > xCloseable( xDocument, uno::UNO_QUERY );
351 if ( xCloseable.is() )
355 xCloseable->close( true );
357 catch( const uno::Exception& )
362 throw; // TODO
365 return xDocument;
369 uno::Reference< util::XCloseable > OCommonEmbeddedObject::LoadLink_Impl()
371 uno::Reference< util::XCloseable > xDocument( CreateDocument( m_xContext, GetDocumentServiceName(),
372 m_bEmbeddedScriptSupport, m_bDocumentRecoverySupport ) );
374 uno::Reference< frame::XLoadable > xLoadable( xDocument, uno::UNO_QUERY );
375 if ( !xLoadable.is() )
376 throw uno::RuntimeException();
378 sal_Int32 nLen = 2;
379 uno::Sequence< beans::PropertyValue > aArgs( nLen );
380 aArgs[0].Name = "URL";
381 aArgs[0].Value <<= m_aLinkURL;
382 aArgs[1].Name = "FilterName";
383 aArgs[1].Value <<= m_aLinkFilterName;
384 if ( m_bLinkHasPassword )
386 aArgs.realloc( ++nLen );
387 aArgs[nLen-1].Name = "Password";
388 aArgs[nLen-1].Value <<= m_aLinkPassword;
391 aArgs.realloc( m_aDocMediaDescriptor.getLength() + nLen );
392 for ( sal_Int32 nInd = 0; nInd < m_aDocMediaDescriptor.getLength(); nInd++ )
394 aArgs[nInd+nLen].Name = m_aDocMediaDescriptor[nInd].Name;
395 aArgs[nInd+nLen].Value = m_aDocMediaDescriptor[nInd].Value;
400 // the document is not really an embedded one, it is a link
401 EmbedAndReparentDoc_Impl( xDocument );
403 // load the document
404 xLoadable->load( aArgs );
406 if ( !m_bLinkHasPassword )
408 // check if there is a password to cache
409 uno::Reference< frame::XModel > xModel( xLoadable, uno::UNO_QUERY_THROW );
410 uno::Sequence< beans::PropertyValue > aProps = xModel->getArgs();
411 for ( sal_Int32 nInd = 0; nInd < aProps.getLength(); nInd++ )
412 if ( aProps[nInd].Name == "Password" && ( aProps[nInd].Value >>= m_aLinkPassword ) )
414 m_bLinkHasPassword = true;
415 break;
419 catch( const uno::Exception& )
421 uno::Reference< util::XCloseable > xCloseable( xDocument, uno::UNO_QUERY );
422 if ( xCloseable.is() )
426 xCloseable->close( true );
428 catch( const uno::Exception& )
433 throw; // TODO
436 return xDocument;
441 OUString OCommonEmbeddedObject::GetFilterName( sal_Int32 nVersion ) const
443 OUString aFilterName = GetPresetFilterName();
444 if ( aFilterName.isEmpty() )
446 try {
447 ::comphelper::MimeConfigurationHelper aHelper( m_xContext );
448 aFilterName = aHelper.GetDefaultFilterFromServiceName( GetDocumentServiceName(), nVersion );
450 // If no filter is found, fall back to the FileFormatVersion=6200 filter, Base only has that.
451 if (aFilterName.isEmpty() && nVersion == SOFFICE_FILEFORMAT_CURRENT)
452 aFilterName = aHelper.GetDefaultFilterFromServiceName(GetDocumentServiceName(), SOFFICE_FILEFORMAT_60);
453 } catch( const uno::Exception& )
457 return aFilterName;
461 void OCommonEmbeddedObject::FillDefaultLoadArgs_Impl( const uno::Reference< embed::XStorage >& i_rxStorage,
462 ::comphelper::NamedValueCollection& o_rLoadArgs ) const
464 o_rLoadArgs.put( "DocumentBaseURL", GetBaseURL_Impl() );
465 o_rLoadArgs.put( "HierarchicalDocumentName", m_aEntryName );
466 o_rLoadArgs.put( "ReadOnly", m_bReadOnly );
468 OUString aFilterName = GetFilterName( ::comphelper::OStorageHelper::GetXStorageFormat( i_rxStorage ) );
469 SAL_WARN_IF( aFilterName.isEmpty(), "embeddedobj.common", "OCommonEmbeddedObject::FillDefaultLoadArgs_Impl: Wrong document service name!" );
470 if ( aFilterName.isEmpty() )
471 throw io::IOException(); // TODO: error message/code
473 o_rLoadArgs.put( "FilterName", aFilterName );
477 uno::Reference< util::XCloseable > OCommonEmbeddedObject::LoadDocumentFromStorage_Impl()
479 ENSURE_OR_THROW( m_xObjectStorage.is(), "no object storage" );
481 const uno::Reference< embed::XStorage > xSourceStorage( m_xRecoveryStorage.is() ? m_xRecoveryStorage : m_xObjectStorage );
483 uno::Reference< util::XCloseable > xDocument( CreateDocument( m_xContext, GetDocumentServiceName(),
484 m_bEmbeddedScriptSupport, m_bDocumentRecoverySupport ) );
486 //#i103460# ODF: take the size given from the parent frame as default
487 uno::Reference< chart2::XChartDocument > xChart( xDocument, uno::UNO_QUERY );
488 if( xChart.is() )
490 uno::Reference< embed::XVisualObject > xChartVisualObject( xChart, uno::UNO_QUERY );
491 if( xChartVisualObject.is() )
492 xChartVisualObject->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT, m_aDefaultSizeForChart_In_100TH_MM );
495 uno::Reference< frame::XLoadable > xLoadable( xDocument, uno::UNO_QUERY );
496 uno::Reference< document::XStorageBasedDocument > xDoc( xDocument, uno::UNO_QUERY );
497 if ( !xDoc.is() && !xLoadable.is() ) ///BUG: This should be || instead of && ?
498 throw uno::RuntimeException();
500 ::comphelper::NamedValueCollection aLoadArgs;
501 FillDefaultLoadArgs_Impl( xSourceStorage, aLoadArgs );
503 uno::Reference< io::XInputStream > xTempInpStream;
504 if ( !xDoc.is() )
506 xTempInpStream = createTempInpStreamFromStor( xSourceStorage, m_xContext );
507 if ( !xTempInpStream.is() )
508 throw uno::RuntimeException();
510 OUString aTempFileURL;
513 // no need to let the file stay after the stream is removed since the embedded document
514 // can not be stored directly
515 uno::Reference< beans::XPropertySet > xTempStreamProps( xTempInpStream, uno::UNO_QUERY_THROW );
516 xTempStreamProps->getPropertyValue("Uri") >>= aTempFileURL;
518 catch( const uno::Exception& )
522 SAL_WARN_IF( aTempFileURL.isEmpty(), "embeddedobj.common", "Couldn't retrieve temporary file URL!" );
524 aLoadArgs.put( "URL", aTempFileURL );
525 aLoadArgs.put( "InputStream", xTempInpStream );
529 aLoadArgs.merge( m_aDocMediaDescriptor, true );
533 // set the document mode to embedded as the first step!!!
534 EmbedAndReparentDoc_Impl( xDocument );
536 if ( xDoc.is() )
538 xDoc->loadFromStorage( xSourceStorage, aLoadArgs.getPropertyValues() );
539 if ( xSourceStorage != m_xObjectStorage )
540 SwitchDocToStorage_Impl( xDoc, m_xObjectStorage );
542 else
543 xLoadable->load( aLoadArgs.getPropertyValues() );
545 catch( const uno::Exception& )
547 uno::Reference< util::XCloseable > xCloseable( xDocument, uno::UNO_QUERY );
548 if ( xCloseable.is() )
552 xCloseable->close( true );
554 catch( const uno::Exception& )
556 DBG_UNHANDLED_EXCEPTION();
560 throw; // TODO
563 return xDocument;
567 uno::Reference< io::XInputStream > OCommonEmbeddedObject::StoreDocumentToTempStream_Impl(
568 sal_Int32 nStorageFormat,
569 const OUString& aBaseURL,
570 const OUString& aHierarchName )
572 uno::Reference < io::XOutputStream > xTempOut(
573 io::TempFile::create(m_xContext),
574 uno::UNO_QUERY_THROW );
575 uno::Reference< io::XInputStream > aResult( xTempOut, uno::UNO_QUERY );
577 if ( !aResult.is() )
578 throw uno::RuntimeException(); // TODO:
580 uno::Reference< frame::XStorable > xStorable;
582 osl::MutexGuard aGuard( m_aMutex );
583 if ( m_pDocHolder )
584 xStorable.set( m_pDocHolder->GetComponent(), uno::UNO_QUERY );
587 if( !xStorable.is() )
588 throw uno::RuntimeException(); // TODO:
590 OUString aFilterName = GetFilterName( nStorageFormat );
592 SAL_WARN_IF( aFilterName.isEmpty(), "embeddedobj.common", "Wrong document service name!" );
593 if ( aFilterName.isEmpty() )
594 throw io::IOException(); // TODO:
596 uno::Sequence< beans::PropertyValue > aArgs( 4 );
597 aArgs[0].Name = "FilterName";
598 aArgs[0].Value <<= aFilterName;
599 aArgs[1].Name = "OutputStream";
600 aArgs[1].Value <<= xTempOut;
601 aArgs[2].Name = "DocumentBaseURL";
602 aArgs[2].Value <<= aBaseURL;
603 aArgs[3].Name = "HierarchicalDocumentName";
604 aArgs[3].Value <<= aHierarchName;
606 xStorable->storeToURL( "private:stream", aArgs );
609 xTempOut->closeOutput();
611 catch( const uno::Exception& )
613 SAL_WARN( "embeddedobj.common", "Looks like stream was closed already" );
616 return aResult;
620 void OCommonEmbeddedObject::SaveObject_Impl()
622 if ( m_xClientSite.is() )
626 // check whether the component is modified,
627 // if not there is no need for storing
628 uno::Reference< util::XModifiable > xModifiable( m_pDocHolder->GetComponent(), uno::UNO_QUERY );
629 if ( xModifiable.is() && !xModifiable->isModified() )
630 return;
632 catch( const uno::Exception& )
635 try {
636 m_xClientSite->saveObject();
638 catch( const uno::Exception& )
640 SAL_WARN( "embeddedobj.common", "The object was not stored!" );
646 OUString OCommonEmbeddedObject::GetBaseURL_Impl() const
648 OUString aBaseURL;
649 sal_Int32 nInd = 0;
651 if ( m_xClientSite.is() )
655 uno::Reference< frame::XModel > xParentModel( m_xClientSite->getComponent(), uno::UNO_QUERY_THROW );
656 uno::Sequence< beans::PropertyValue > aModelProps = xParentModel->getArgs();
657 for ( nInd = 0; nInd < aModelProps.getLength(); nInd++ )
658 if ( aModelProps[nInd].Name == "DocumentBaseURL" )
660 aModelProps[nInd].Value >>= aBaseURL;
661 break;
666 catch( const uno::Exception& )
670 if ( aBaseURL.isEmpty() )
672 for ( nInd = 0; nInd < m_aDocMediaDescriptor.getLength(); nInd++ )
673 if ( m_aDocMediaDescriptor[nInd].Name == "DocumentBaseURL" )
675 m_aDocMediaDescriptor[nInd].Value >>= aBaseURL;
676 break;
680 if ( aBaseURL.isEmpty() )
681 aBaseURL = m_aDefaultParentBaseURL;
683 return aBaseURL;
687 OUString OCommonEmbeddedObject::GetBaseURLFrom_Impl(
688 const uno::Sequence< beans::PropertyValue >& lArguments,
689 const uno::Sequence< beans::PropertyValue >& lObjArgs )
691 OUString aBaseURL;
692 sal_Int32 nInd = 0;
694 for ( nInd = 0; nInd < lArguments.getLength(); nInd++ )
695 if ( lArguments[nInd].Name == "DocumentBaseURL" )
697 lArguments[nInd].Value >>= aBaseURL;
698 break;
701 if ( aBaseURL.isEmpty() )
703 for ( nInd = 0; nInd < lObjArgs.getLength(); nInd++ )
704 if ( lObjArgs[nInd].Name == "DefaultParentBaseURL" )
706 lObjArgs[nInd].Value >>= aBaseURL;
707 break;
711 return aBaseURL;
715 void OCommonEmbeddedObject::SwitchDocToStorage_Impl( const uno::Reference< document::XStorageBasedDocument >& xDoc, const uno::Reference< embed::XStorage >& xStorage )
717 xDoc->switchToStorage( xStorage );
719 uno::Reference< util::XModifiable > xModif( xDoc, uno::UNO_QUERY );
720 if ( xModif.is() )
721 xModif->setModified( false );
723 if ( m_xRecoveryStorage.is() )
724 m_xRecoveryStorage.clear();
727 namespace {
729 OUString getStringPropertyValue( const uno::Sequence<beans::PropertyValue>& rProps, const OUString& rName )
731 OUString aStr;
733 for (sal_Int32 i = 0; i < rProps.getLength(); ++i)
735 if (rProps[i].Name == rName)
737 rProps[i].Value >>= aStr;
738 break;
742 return aStr;
747 void OCommonEmbeddedObject::StoreDocToStorage_Impl(
748 const uno::Reference<embed::XStorage>& xStorage,
749 const uno::Sequence<beans::PropertyValue>& rMediaArgs,
750 const uno::Sequence<beans::PropertyValue>& rObjArgs,
751 sal_Int32 nStorageFormat,
752 const OUString& aHierarchName,
753 bool bAttachToTheStorage )
755 SAL_WARN_IF( !xStorage.is(), "embeddedobj.common", "No storage is provided for storing!" );
757 if ( !xStorage.is() )
758 throw uno::RuntimeException(); // TODO:
760 uno::Reference< document::XStorageBasedDocument > xDoc;
762 osl::MutexGuard aGuard( m_aMutex );
763 if ( m_pDocHolder )
764 xDoc.set( m_pDocHolder->GetComponent(), uno::UNO_QUERY );
767 OUString aBaseURL = GetBaseURLFrom_Impl(rMediaArgs, rObjArgs);
769 if ( xDoc.is() )
771 OUString aFilterName = GetFilterName( nStorageFormat );
773 // No filter found? Try the older format, e.g. Base has only that.
774 if (aFilterName.isEmpty() && nStorageFormat == SOFFICE_FILEFORMAT_CURRENT)
775 aFilterName = GetFilterName( SOFFICE_FILEFORMAT_60 );
777 SAL_WARN_IF( aFilterName.isEmpty(), "embeddedobj.common", "Wrong document service name!" );
778 if ( aFilterName.isEmpty() )
779 throw io::IOException(); // TODO:
781 uno::Sequence<beans::PropertyValue> aArgs(5);
782 aArgs[0].Name = "FilterName";
783 aArgs[0].Value <<= aFilterName;
784 aArgs[1].Name = "HierarchicalDocumentName";
785 aArgs[1].Value <<= aHierarchName;
786 aArgs[2].Name = "DocumentBaseURL";
787 aArgs[2].Value <<= aBaseURL;
788 aArgs[3].Name = "SourceShellID";
789 aArgs[3].Value <<= getStringPropertyValue(rObjArgs, "SourceShellID");
790 aArgs[4].Name = "DestinationShellID";
791 aArgs[4].Value <<= getStringPropertyValue(rObjArgs, "DestinationShellID");
793 xDoc->storeToStorage( xStorage, aArgs );
794 if ( bAttachToTheStorage )
795 SwitchDocToStorage_Impl( xDoc, xStorage );
797 else
799 // store document to temporary stream based on temporary file
800 uno::Reference < io::XInputStream > xTempIn = StoreDocumentToTempStream_Impl( nStorageFormat, aBaseURL, aHierarchName );
802 SAL_WARN_IF( !xTempIn.is(), "embeddedobj.common", "The stream reference can not be empty!" );
804 // open storage based on document temporary file for reading
805 uno::Reference < lang::XSingleServiceFactory > xStorageFactory = embed::StorageFactory::create(m_xContext);
807 uno::Sequence< uno::Any > aArgs(1);
808 aArgs[0] <<= xTempIn;
809 uno::Reference< embed::XStorage > xTempStorage( xStorageFactory->createInstanceWithArguments( aArgs ),
810 uno::UNO_QUERY );
811 if ( !xTempStorage.is() )
812 throw uno::RuntimeException(); // TODO:
814 // object storage must be committed automatically
815 xTempStorage->copyToStorage( xStorage );
820 uno::Reference< util::XCloseable > OCommonEmbeddedObject::CreateDocFromMediaDescr_Impl(
821 const uno::Sequence< beans::PropertyValue >& aMedDescr )
823 uno::Reference< util::XCloseable > xDocument( CreateDocument( m_xContext, GetDocumentServiceName(),
824 m_bEmbeddedScriptSupport, m_bDocumentRecoverySupport ) );
826 uno::Reference< frame::XLoadable > xLoadable( xDocument, uno::UNO_QUERY );
827 if ( !xLoadable.is() )
828 throw uno::RuntimeException();
832 // set the document mode to embedded as the first action on the document!!!
833 EmbedAndReparentDoc_Impl( xDocument );
835 xLoadable->load( addAsTemplate( aMedDescr ) );
837 catch( const uno::Exception& )
839 uno::Reference< util::XCloseable > xCloseable( xDocument, uno::UNO_QUERY );
840 if ( xCloseable.is() )
844 xCloseable->close( true );
846 catch( const uno::Exception& )
851 throw; // TODO
854 return xDocument;
858 uno::Reference< util::XCloseable > OCommonEmbeddedObject::CreateTempDocFromLink_Impl()
860 uno::Reference< util::XCloseable > xResult;
862 SAL_WARN_IF( !m_bIsLink, "embeddedobj.common", "The object is not a linked one!" );
864 uno::Sequence< beans::PropertyValue > aTempMediaDescr;
866 sal_Int32 nStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
867 try {
868 nStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage );
870 catch ( const beans::IllegalTypeException& )
872 // the container just has an unknown type, use current file format
874 catch ( const uno::Exception& )
876 SAL_WARN( "embeddedobj.common", "Can not retrieve storage media type!" );
879 if ( m_pDocHolder->GetComponent().is() )
881 aTempMediaDescr.realloc( 4 );
883 // TODO/LATER: may be private:stream should be used as target URL
884 OUString aTempFileURL;
885 uno::Reference< io::XInputStream > xTempStream = StoreDocumentToTempStream_Impl( SOFFICE_FILEFORMAT_CURRENT,
886 OUString(),
887 OUString() );
890 // no need to let the file stay after the stream is removed since the embedded document
891 // can not be stored directly
892 uno::Reference< beans::XPropertySet > xTempStreamProps( xTempStream, uno::UNO_QUERY_THROW );
893 xTempStreamProps->getPropertyValue("Uri") >>= aTempFileURL;
895 catch( const uno::Exception& )
899 SAL_WARN_IF( aTempFileURL.isEmpty(), "embeddedobj.common", "Couldn't retrieve temporary file URL!" );
901 aTempMediaDescr[0].Name = "URL";
902 aTempMediaDescr[0].Value <<= aTempFileURL;
903 aTempMediaDescr[1].Name = "InputStream";
904 aTempMediaDescr[1].Value <<= xTempStream;
905 aTempMediaDescr[2].Name = "FilterName";
906 aTempMediaDescr[2].Value <<= GetFilterName( nStorageFormat );
907 aTempMediaDescr[3].Name = "AsTemplate";
908 aTempMediaDescr[3].Value <<= true;
910 else
912 aTempMediaDescr.realloc( 2 );
913 aTempMediaDescr[0].Name = "URL";
914 aTempMediaDescr[0].Value <<= m_aLinkURL;
915 aTempMediaDescr[1].Name = "FilterName";
916 aTempMediaDescr[1].Value <<= m_aLinkFilterName;
919 xResult = CreateDocFromMediaDescr_Impl( aTempMediaDescr );
921 return xResult;
925 void SAL_CALL OCommonEmbeddedObject::setPersistentEntry(
926 const uno::Reference< embed::XStorage >& xStorage,
927 const OUString& sEntName,
928 sal_Int32 nEntryConnectionMode,
929 const uno::Sequence< beans::PropertyValue >& lArguments,
930 const uno::Sequence< beans::PropertyValue >& lObjArgs )
931 throw ( lang::IllegalArgumentException,
932 embed::WrongStateException,
933 io::IOException,
934 uno::Exception,
935 uno::RuntimeException, std::exception )
937 // the type of the object must be already set
938 // a kind of typedetection should be done in the factory
940 ::osl::MutexGuard aGuard( m_aMutex );
941 if ( m_bDisposed )
942 throw lang::DisposedException(); // TODO
944 if ( !xStorage.is() )
945 throw lang::IllegalArgumentException( "No parent storage is provided!",
946 static_cast< ::cppu::OWeakObject* >(this),
947 1 );
949 if ( sEntName.isEmpty() )
950 throw lang::IllegalArgumentException( "Empty element name is provided!",
951 static_cast< ::cppu::OWeakObject* >(this),
952 2 );
954 // May be LOADED should be forbidden here ???
955 if ( ( m_nObjectState != -1 || nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
956 && ( m_nObjectState == -1 || nEntryConnectionMode != embed::EntryInitModes::NO_INIT ) )
958 // if the object is not loaded
959 // it can not get persistent representation without initialization
961 // if the object is loaded
962 // it can switch persistent representation only without initialization
964 throw embed::WrongStateException(
965 "Can't change persistent representation of activated object!",
966 static_cast< ::cppu::OWeakObject* >(this) );
969 if ( m_bWaitSaveCompleted )
971 if ( nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
973 // saveCompleted is expected, handle it accordingly
974 if ( m_xNewParentStorage == xStorage && m_aNewEntryName.equals( sEntName ) )
976 saveCompleted( true );
977 return;
980 // if a completely different entry is provided, switch first back to the old persistence in saveCompleted
981 // and then switch to the target persistence
982 bool bSwitchFurther = ( m_xParentStorage != xStorage || !m_aEntryName.equals( sEntName ) );
983 saveCompleted( false );
984 if ( !bSwitchFurther )
985 return;
987 else
988 throw embed::WrongStateException(
989 "The object waits for saveCompleted() call!",
990 static_cast< ::cppu::OWeakObject* >(this) );
993 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
994 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
995 // OSL_ENSURE( !m_bIsLink, "This method implementation must not be used for links!\n" );
996 if ( m_bIsLink )
998 m_aEntryName = sEntName;
999 return;
1002 uno::Reference< container::XNameAccess > xNameAccess( xStorage, uno::UNO_QUERY );
1003 if ( !xNameAccess.is() )
1004 throw uno::RuntimeException(); //TODO
1006 // detect entry existence
1007 bool bElExists = xNameAccess->hasByName( sEntName );
1009 m_aDocMediaDescriptor = GetValuableArgs_Impl( lArguments,
1010 nEntryConnectionMode != embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT );
1012 m_bReadOnly = false;
1013 for ( sal_Int32 nInd = 0; nInd < lArguments.getLength(); nInd++ )
1014 if ( lArguments[nInd].Name == "ReadOnly" )
1015 lArguments[nInd].Value >>= m_bReadOnly;
1017 // TODO: use lObjArgs for StoreVisualReplacement
1018 for ( sal_Int32 nObjInd = 0; nObjInd < lObjArgs.getLength(); nObjInd++ )
1019 if ( lObjArgs[nObjInd].Name == "OutplaceDispatchInterceptor" )
1021 uno::Reference< frame::XDispatchProviderInterceptor > xDispatchInterceptor;
1022 if ( lObjArgs[nObjInd].Value >>= xDispatchInterceptor )
1023 m_pDocHolder->SetOutplaceDispatchInterceptor( xDispatchInterceptor );
1025 else if ( lObjArgs[nObjInd].Name == "DefaultParentBaseURL" )
1027 lObjArgs[nObjInd].Value >>= m_aDefaultParentBaseURL;
1029 else if ( lObjArgs[nObjInd].Name == "Parent" )
1031 lObjArgs[nObjInd].Value >>= m_xParent;
1033 else if ( lObjArgs[nObjInd].Name == "IndividualMiscStatus" )
1035 sal_Int64 nMiscStatus=0;
1036 lObjArgs[nObjInd].Value >>= nMiscStatus;
1037 m_nMiscStatus |= nMiscStatus;
1039 else if ( lObjArgs[nObjInd].Name == "CloneFrom" )
1041 uno::Reference < embed::XEmbeddedObject > xObj;
1042 lObjArgs[nObjInd].Value >>= xObj;
1043 if ( xObj.is() )
1045 m_bHasClonedSize = true;
1046 m_aClonedSize = xObj->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT );
1047 m_nClonedMapUnit = xObj->getMapUnit( embed::Aspects::MSOLE_CONTENT );
1050 else if ( lObjArgs[nObjInd].Name == "OutplaceFrameProperties" )
1052 uno::Sequence< uno::Any > aOutFrameProps;
1053 uno::Sequence< beans::NamedValue > aOutFramePropsTyped;
1054 if ( lObjArgs[nObjInd].Value >>= aOutFrameProps )
1056 m_pDocHolder->SetOutplaceFrameProperties( aOutFrameProps );
1058 else if ( lObjArgs[nObjInd].Value >>= aOutFramePropsTyped )
1060 aOutFrameProps.realloc( aOutFramePropsTyped.getLength() );
1061 uno::Any* pProp = aOutFrameProps.getArray();
1062 for ( const beans::NamedValue* pTypedProp = aOutFramePropsTyped.getConstArray();
1063 pTypedProp != aOutFramePropsTyped.getConstArray() + aOutFramePropsTyped.getLength();
1064 ++pTypedProp, ++pProp
1067 *pProp <<= *pTypedProp;
1069 m_pDocHolder->SetOutplaceFrameProperties( aOutFrameProps );
1071 else
1072 SAL_WARN( "embeddedobj.common", "OCommonEmbeddedObject::setPersistentEntry: illegal type for argument 'OutplaceFrameProperties'!" );
1074 else if ( lObjArgs[nObjInd].Name == "ModuleName" )
1076 lObjArgs[nObjInd].Value >>= m_aModuleName;
1078 else if ( lObjArgs[nObjInd].Name == "EmbeddedScriptSupport" )
1080 OSL_VERIFY( lObjArgs[nObjInd].Value >>= m_bEmbeddedScriptSupport );
1082 else if ( lObjArgs[nObjInd].Name == "DocumentRecoverySupport" )
1084 OSL_VERIFY( lObjArgs[nObjInd].Value >>= m_bDocumentRecoverySupport );
1086 else if ( lObjArgs[nObjInd].Name == "RecoveryStorage" )
1088 OSL_VERIFY( lObjArgs[nObjInd].Value >>= m_xRecoveryStorage );
1092 sal_Int32 nStorageMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
1094 SwitchOwnPersistence( xStorage, sEntName );
1096 if ( nEntryConnectionMode == embed::EntryInitModes::DEFAULT_INIT )
1098 if ( bElExists )
1100 // the initialization from existing storage allows to leave object in loaded state
1101 m_nObjectState = embed::EmbedStates::LOADED;
1103 else
1105 m_pDocHolder->SetComponent( InitNewDocument_Impl(), m_bReadOnly );
1106 if ( !m_pDocHolder->GetComponent().is() )
1107 throw io::IOException(); // TODO: can not create document
1109 m_nObjectState = embed::EmbedStates::RUNNING;
1112 else
1114 if ( ( nStorageMode & embed::ElementModes::READWRITE ) != embed::ElementModes::READWRITE )
1115 throw io::IOException();
1117 if ( nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
1119 // the document just already changed its storage to store to
1120 // the links to OOo documents for now ignore this call
1121 // TODO: OOo links will have persistence so it will be switched here
1123 else if ( nEntryConnectionMode == embed::EntryInitModes::TRUNCATE_INIT )
1125 if ( m_xRecoveryStorage.is() )
1126 TransferMediaType( m_xRecoveryStorage, m_xObjectStorage );
1128 // TODO:
1129 m_pDocHolder->SetComponent( InitNewDocument_Impl(), m_bReadOnly );
1131 if ( !m_pDocHolder->GetComponent().is() )
1132 throw io::IOException(); // TODO: can not create document
1134 m_nObjectState = embed::EmbedStates::RUNNING;
1136 else if ( nEntryConnectionMode == embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT )
1138 m_pDocHolder->SetComponent( CreateDocFromMediaDescr_Impl( lArguments ), m_bReadOnly );
1139 m_nObjectState = embed::EmbedStates::RUNNING;
1141 //else if ( nEntryConnectionMode == embed::EntryInitModes::TRANSFERABLE_INIT )
1143 //TODO:
1145 else
1146 throw lang::IllegalArgumentException( "Wrong connection mode is provided!",
1147 static_cast< ::cppu::OWeakObject* >(this),
1148 3 );
1153 void SAL_CALL OCommonEmbeddedObject::storeToEntry( const uno::Reference< embed::XStorage >& xStorage,
1154 const OUString& sEntName,
1155 const uno::Sequence< beans::PropertyValue >& lArguments,
1156 const uno::Sequence< beans::PropertyValue >& lObjArgs )
1157 throw ( lang::IllegalArgumentException,
1158 embed::WrongStateException,
1159 io::IOException,
1160 uno::Exception,
1161 uno::RuntimeException, std::exception )
1163 ::osl::ResettableMutexGuard aGuard( m_aMutex );
1164 if ( m_bDisposed )
1165 throw lang::DisposedException(); // TODO
1167 if ( m_nObjectState == -1 )
1169 // the object is still not loaded
1170 throw embed::WrongStateException( "Can't store object without persistence!",
1171 static_cast< ::cppu::OWeakObject* >(this) );
1174 if ( m_bWaitSaveCompleted )
1175 throw embed::WrongStateException(
1176 "The object waits for saveCompleted() call!",
1177 static_cast< ::cppu::OWeakObject* >(this) );
1179 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1180 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1181 // OSL_ENSURE( !m_bIsLink, "This method implementation must not be used for links!\n" );
1182 if ( m_bIsLink )
1183 return;
1185 OSL_ENSURE( m_xParentStorage.is() && m_xObjectStorage.is(), "The object has no valid persistence!\n" );
1187 sal_Int32 nTargetStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1188 sal_Int32 nOriginalStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1189 try {
1190 nTargetStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( xStorage );
1192 catch ( const beans::IllegalTypeException& )
1194 // the container just has an unknown type, use current file format
1196 catch ( const uno::Exception& )
1198 SAL_WARN( "embeddedobj.common", "Can not retrieve target storage media type!" );
1200 if (nTargetStorageFormat == SOFFICE_FILEFORMAT_60)
1202 SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1203 nTargetStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1204 // setting MediaType is done later anyway, no need to do it here
1209 nOriginalStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage );
1211 catch ( const beans::IllegalTypeException& )
1213 // the container just has an unknown type, use current file format
1215 catch ( const uno::Exception& )
1217 SAL_WARN( "embeddedobj.common", "Can not retrieve own storage media type!" );
1220 bool bTryOptimization = false;
1221 for ( sal_Int32 nInd = 0; nInd < lObjArgs.getLength(); nInd++ )
1223 // StoreVisualReplacement and VisualReplacement args have no sense here
1224 if ( lObjArgs[nInd].Name == "CanTryOptimization" )
1225 lObjArgs[nInd].Value >>= bTryOptimization;
1228 bool bSwitchBackToLoaded = false;
1230 // Storing to different format can be done only in running state.
1231 if ( m_nObjectState == embed::EmbedStates::LOADED )
1233 // TODO/LATER: copying is not legal for documents with relative links.
1234 if ( nTargetStorageFormat == nOriginalStorageFormat )
1236 bool bOptimizationWorks = false;
1237 if ( bTryOptimization )
1241 // try to use optimized copying
1242 uno::Reference< embed::XOptimizedStorage > xSource( m_xParentStorage, uno::UNO_QUERY_THROW );
1243 uno::Reference< embed::XOptimizedStorage > xTarget( xStorage, uno::UNO_QUERY_THROW );
1244 xSource->copyElementDirectlyTo( m_aEntryName, xTarget, sEntName );
1245 bOptimizationWorks = true;
1247 catch( const uno::Exception& )
1252 if ( !bOptimizationWorks )
1253 m_xParentStorage->copyElementTo( m_aEntryName, xStorage, sEntName );
1255 else
1257 changeState( embed::EmbedStates::RUNNING );
1258 bSwitchBackToLoaded = true;
1262 if ( m_nObjectState != embed::EmbedStates::LOADED )
1264 uno::Reference< embed::XStorage > xSubStorage =
1265 xStorage->openStorageElement( sEntName, embed::ElementModes::READWRITE );
1267 if ( !xSubStorage.is() )
1268 throw uno::RuntimeException(); //TODO
1270 aGuard.clear();
1271 // TODO/LATER: support hierarchical name for embedded objects in embedded objects
1272 StoreDocToStorage_Impl(
1273 xSubStorage, lArguments, lObjArgs, nTargetStorageFormat, sEntName, false );
1274 aGuard.reset();
1276 if ( bSwitchBackToLoaded )
1277 changeState( embed::EmbedStates::LOADED );
1280 // TODO: should the listener notification be done?
1284 void SAL_CALL OCommonEmbeddedObject::storeAsEntry( const uno::Reference< embed::XStorage >& xStorage,
1285 const OUString& sEntName,
1286 const uno::Sequence< beans::PropertyValue >& lArguments,
1287 const uno::Sequence< beans::PropertyValue >& lObjArgs )
1288 throw ( lang::IllegalArgumentException,
1289 embed::WrongStateException,
1290 io::IOException,
1291 uno::Exception,
1292 uno::RuntimeException, std::exception )
1294 // TODO: use lObjArgs
1296 ::osl::ResettableMutexGuard aGuard( m_aMutex );
1297 if ( m_bDisposed )
1298 throw lang::DisposedException(); // TODO
1300 if ( m_nObjectState == -1 )
1302 // the object is still not loaded
1303 throw embed::WrongStateException( "Can't store object without persistence!",
1304 static_cast< ::cppu::OWeakObject* >(this) );
1307 if ( m_bWaitSaveCompleted )
1308 throw embed::WrongStateException(
1309 "The object waits for saveCompleted() call!",
1310 static_cast< ::cppu::OWeakObject* >(this) );
1312 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1313 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1314 // OSL_ENSURE( !m_bIsLink, "This method implementation must not be used for links!\n" );
1315 if ( m_bIsLink )
1317 m_aNewEntryName = sEntName;
1318 return;
1321 OSL_ENSURE( m_xParentStorage.is() && m_xObjectStorage.is(), "The object has no valid persistence!\n" );
1323 sal_Int32 nTargetStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1324 sal_Int32 nOriginalStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1325 try {
1326 nTargetStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( xStorage );
1328 catch ( const beans::IllegalTypeException& )
1330 // the container just has an unknown type, use current file format
1332 catch ( const uno::Exception& )
1334 SAL_WARN( "embeddedobj.common", "Can not retrieve target storage media type!" );
1336 if (nTargetStorageFormat == SOFFICE_FILEFORMAT_60)
1338 SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1339 nTargetStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1340 // setting MediaType is done later anyway, no need to do it here
1345 nOriginalStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage );
1347 catch ( const beans::IllegalTypeException& )
1349 // the container just has an unknown type, use current file format
1351 catch ( const uno::Exception& )
1353 SAL_WARN( "embeddedobj.common", "Can not retrieve own storage media type!" );
1356 PostEvent_Impl( "OnSaveAs" );
1358 bool bTryOptimization = false;
1359 for ( sal_Int32 nInd = 0; nInd < lObjArgs.getLength(); nInd++ )
1361 // StoreVisualReplacement and VisualReplacement args have no sense here
1362 if ( lObjArgs[nInd].Name == "CanTryOptimization" )
1363 lObjArgs[nInd].Value >>= bTryOptimization;
1366 bool bSwitchBackToLoaded = false;
1368 // Storing to different format can be done only in running state.
1369 if ( m_nObjectState == embed::EmbedStates::LOADED )
1371 // TODO/LATER: copying is not legal for documents with relative links.
1372 if ( nTargetStorageFormat == nOriginalStorageFormat )
1374 bool bOptimizationWorks = false;
1375 if ( bTryOptimization )
1379 // try to use optimized copying
1380 uno::Reference< embed::XOptimizedStorage > xSource( m_xParentStorage, uno::UNO_QUERY_THROW );
1381 uno::Reference< embed::XOptimizedStorage > xTarget( xStorage, uno::UNO_QUERY_THROW );
1382 xSource->copyElementDirectlyTo( m_aEntryName, xTarget, sEntName );
1383 bOptimizationWorks = true;
1385 catch( const uno::Exception& )
1390 if ( !bOptimizationWorks )
1391 m_xParentStorage->copyElementTo( m_aEntryName, xStorage, sEntName );
1393 else
1395 changeState( embed::EmbedStates::RUNNING );
1396 bSwitchBackToLoaded = true;
1400 uno::Reference< embed::XStorage > xSubStorage =
1401 xStorage->openStorageElement( sEntName, embed::ElementModes::READWRITE );
1403 if ( !xSubStorage.is() )
1404 throw uno::RuntimeException(); //TODO
1406 if ( m_nObjectState != embed::EmbedStates::LOADED )
1408 aGuard.clear();
1409 // TODO/LATER: support hierarchical name for embedded objects in embedded objects
1410 StoreDocToStorage_Impl(
1411 xSubStorage, lArguments, lObjArgs, nTargetStorageFormat, sEntName, false );
1412 aGuard.reset();
1414 if ( bSwitchBackToLoaded )
1415 changeState( embed::EmbedStates::LOADED );
1418 m_bWaitSaveCompleted = true;
1419 m_xNewObjectStorage = xSubStorage;
1420 m_xNewParentStorage = xStorage;
1421 m_aNewEntryName = sEntName;
1422 m_aNewDocMediaDescriptor = GetValuableArgs_Impl( lArguments, true );
1424 // TODO: register listeners for storages above, in case thay are disposed
1425 // an exception will be thrown on saveCompleted( true )
1427 // TODO: should the listener notification be done here or in saveCompleted?
1431 void SAL_CALL OCommonEmbeddedObject::saveCompleted( sal_Bool bUseNew )
1432 throw ( embed::WrongStateException,
1433 uno::Exception,
1434 uno::RuntimeException, std::exception )
1436 ::osl::MutexGuard aGuard( m_aMutex );
1437 if ( m_bDisposed )
1438 throw lang::DisposedException(); // TODO
1440 if ( m_nObjectState == -1 )
1442 // the object is still not loaded
1443 throw embed::WrongStateException( "Can't store object without persistence!",
1444 static_cast< ::cppu::OWeakObject* >(this) );
1447 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1448 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1449 // OSL_ENSURE( !m_bIsLink, "This method implementation must not be used for links!\n" );
1450 if ( m_bIsLink )
1452 if ( bUseNew )
1453 m_aEntryName = m_aNewEntryName;
1454 m_aNewEntryName.clear();
1455 return;
1458 // it is allowed to call saveCompleted( false ) for nonstored objects
1459 if ( !m_bWaitSaveCompleted && !bUseNew )
1460 return;
1462 SAL_WARN_IF( !m_bWaitSaveCompleted, "embeddedobj.common", "Unexpected saveCompleted() call!" );
1463 if ( !m_bWaitSaveCompleted )
1464 throw io::IOException(); // TODO: illegal call
1466 OSL_ENSURE( m_xNewObjectStorage.is() && m_xNewParentStorage.is() , "Internal object information is broken!\n" );
1467 if ( !m_xNewObjectStorage.is() || !m_xNewParentStorage.is() )
1468 throw uno::RuntimeException(); // TODO: broken internal information
1470 if ( bUseNew )
1472 SwitchOwnPersistence( m_xNewParentStorage, m_xNewObjectStorage, m_aNewEntryName );
1473 m_aDocMediaDescriptor = m_aNewDocMediaDescriptor;
1475 uno::Reference< util::XModifiable > xModif( m_pDocHolder->GetComponent(), uno::UNO_QUERY );
1476 if ( xModif.is() )
1477 xModif->setModified( false );
1479 PostEvent_Impl( "OnSaveAsDone");
1481 else
1483 try {
1484 uno::Reference< lang::XComponent > xComponent( m_xNewObjectStorage, uno::UNO_QUERY );
1485 SAL_WARN_IF( !xComponent.is(), "embeddedobj.common", "Wrong storage implementation!" );
1486 if ( xComponent.is() )
1487 xComponent->dispose();
1489 catch ( const uno::Exception& )
1494 m_xNewObjectStorage.clear();
1495 m_xNewParentStorage.clear();
1496 m_aNewEntryName.clear();
1497 m_aNewDocMediaDescriptor.realloc( 0 );
1498 m_bWaitSaveCompleted = false;
1500 if ( bUseNew )
1502 // TODO: notify listeners
1504 if ( m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE )
1506 // TODO: update visual representation
1512 sal_Bool SAL_CALL OCommonEmbeddedObject::hasEntry()
1513 throw ( embed::WrongStateException,
1514 uno::RuntimeException, std::exception )
1516 ::osl::MutexGuard aGuard( m_aMutex );
1517 if ( m_bDisposed )
1518 throw lang::DisposedException(); // TODO
1520 if ( m_bWaitSaveCompleted )
1521 throw embed::WrongStateException(
1522 "The object waits for saveCompleted() call!",
1523 static_cast< ::cppu::OWeakObject* >(this) );
1525 if ( m_xObjectStorage.is() )
1526 return true;
1528 return false;
1532 OUString SAL_CALL OCommonEmbeddedObject::getEntryName()
1533 throw ( embed::WrongStateException,
1534 uno::RuntimeException, std::exception )
1536 ::osl::MutexGuard aGuard( m_aMutex );
1537 if ( m_bDisposed )
1538 throw lang::DisposedException(); // TODO
1540 if ( m_nObjectState == -1 )
1542 // the object is still not loaded
1543 throw embed::WrongStateException( "The object persistence is not initialized!",
1544 static_cast< ::cppu::OWeakObject* >(this) );
1547 if ( m_bWaitSaveCompleted )
1548 throw embed::WrongStateException(
1549 "The object waits for saveCompleted() call!",
1550 static_cast< ::cppu::OWeakObject* >(this) );
1552 return m_aEntryName;
1556 void SAL_CALL OCommonEmbeddedObject::storeOwn()
1557 throw ( embed::WrongStateException,
1558 io::IOException,
1559 uno::Exception,
1560 uno::RuntimeException, std::exception )
1562 // during switching from Activated to Running and from Running to Loaded states the object will
1563 // ask container to store the object, the container has to make decision
1564 // to do so or not
1566 ::osl::ResettableMutexGuard aGuard( m_aMutex );
1567 if ( m_bDisposed )
1568 throw lang::DisposedException(); // TODO
1570 if ( m_nObjectState == -1 )
1572 // the object is still not loaded
1573 throw embed::WrongStateException( "Can't store object without persistence!",
1574 static_cast< ::cppu::OWeakObject* >(this) );
1577 if ( m_bWaitSaveCompleted )
1578 throw embed::WrongStateException(
1579 "The object waits for saveCompleted() call!",
1580 static_cast< ::cppu::OWeakObject* >(this) );
1582 if ( m_bReadOnly )
1583 throw io::IOException(); // TODO: access denied
1585 // nothing to do, if the object is in loaded state
1586 if ( m_nObjectState == embed::EmbedStates::LOADED )
1587 return;
1589 PostEvent_Impl( "OnSave" );
1591 SAL_WARN_IF( !m_pDocHolder->GetComponent().is(), "embeddedobj.common", "If an object is activated or in running state it must have a document!" );
1592 if ( !m_pDocHolder->GetComponent().is() )
1593 throw uno::RuntimeException();
1595 if ( m_bIsLink )
1597 // TODO: just store the document to its location
1598 uno::Reference< frame::XStorable > xStorable( m_pDocHolder->GetComponent(), uno::UNO_QUERY );
1599 if ( !xStorable.is() )
1600 throw uno::RuntimeException(); // TODO
1602 // free the main mutex for the storing time
1603 aGuard.clear();
1605 xStorable->store();
1607 aGuard.reset();
1609 else
1611 OSL_ENSURE( m_xParentStorage.is() && m_xObjectStorage.is(), "The object has no valid persistence!\n" );
1613 if ( !m_xObjectStorage.is() )
1614 throw io::IOException(); //TODO: access denied
1616 sal_Int32 nStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1617 try {
1618 nStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage );
1620 catch ( const beans::IllegalTypeException& )
1622 // the container just has an unknown type, use current file format
1624 catch ( const uno::Exception& )
1626 SAL_WARN( "embeddedobj.common", "Can not retrieve storage media type!" );
1628 if (nStorageFormat == SOFFICE_FILEFORMAT_60)
1630 SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1631 nStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1632 // setting MediaType is done later anyway, no need to do it here
1635 aGuard.clear();
1636 uno::Sequence<beans::PropertyValue> aEmpty;
1637 uno::Sequence<beans::PropertyValue> aMediaArgs(1);
1638 aMediaArgs[0].Name = "DocumentBaseURL";
1639 aMediaArgs[0].Value <<= GetBaseURL_Impl();
1640 StoreDocToStorage_Impl( m_xObjectStorage, aMediaArgs, aEmpty, nStorageFormat, m_aEntryName, true );
1641 aGuard.reset();
1644 uno::Reference< util::XModifiable > xModif( m_pDocHolder->GetComponent(), uno::UNO_QUERY );
1645 if ( xModif.is() )
1646 xModif->setModified( false );
1648 PostEvent_Impl( "OnSaveDone" );
1652 sal_Bool SAL_CALL OCommonEmbeddedObject::isReadonly()
1653 throw ( embed::WrongStateException,
1654 uno::RuntimeException, std::exception )
1656 ::osl::MutexGuard aGuard( m_aMutex );
1657 if ( m_bDisposed )
1658 throw lang::DisposedException(); // TODO
1660 if ( m_nObjectState == -1 )
1662 // the object is still not loaded
1663 throw embed::WrongStateException( "The object persistence is not initialized!",
1664 static_cast< ::cppu::OWeakObject* >(this) );
1667 if ( m_bWaitSaveCompleted )
1668 throw embed::WrongStateException(
1669 "The object waits for saveCompleted() call!",
1670 static_cast< ::cppu::OWeakObject* >(this) );
1672 return m_bReadOnly;
1676 void SAL_CALL OCommonEmbeddedObject::reload(
1677 const uno::Sequence< beans::PropertyValue >& lArguments,
1678 const uno::Sequence< beans::PropertyValue >& lObjArgs )
1679 throw ( lang::IllegalArgumentException,
1680 embed::WrongStateException,
1681 io::IOException,
1682 uno::Exception,
1683 uno::RuntimeException, std::exception )
1685 // TODO: use lObjArgs
1686 // for now this method is used only to switch readonly state
1688 ::osl::MutexGuard aGuard( m_aMutex );
1689 if ( m_bDisposed )
1690 throw lang::DisposedException(); // TODO
1692 if ( m_nObjectState == -1 )
1694 // the object is still not loaded
1695 throw embed::WrongStateException( "The object persistence is not initialized!",
1696 static_cast< ::cppu::OWeakObject* >(this) );
1699 if ( m_nObjectState != embed::EmbedStates::LOADED )
1701 // the object is still not loaded
1702 throw embed::WrongStateException(
1703 "The object must be in loaded state to be reloaded!",
1704 static_cast< ::cppu::OWeakObject* >(this) );
1707 if ( m_bWaitSaveCompleted )
1708 throw embed::WrongStateException(
1709 "The object waits for saveCompleted() call!",
1710 static_cast< ::cppu::OWeakObject* >(this) );
1712 if ( m_bIsLink )
1714 // reload of the link
1715 OUString aOldLinkFilter = m_aLinkFilterName;
1717 OUString aNewLinkFilter;
1718 for ( sal_Int32 nInd = 0; nInd < lArguments.getLength(); nInd++ )
1720 if ( lArguments[nInd].Name == "URL" )
1722 // the new URL
1723 lArguments[nInd].Value >>= m_aLinkURL;
1724 m_aLinkFilterName.clear();
1726 else if ( lArguments[nInd].Name == "FilterName" )
1728 lArguments[nInd].Value >>= aNewLinkFilter;
1729 m_aLinkFilterName.clear();
1733 ::comphelper::MimeConfigurationHelper aHelper( m_xContext );
1734 if ( m_aLinkFilterName.isEmpty() )
1736 if ( !aNewLinkFilter.isEmpty() )
1737 m_aLinkFilterName = aNewLinkFilter;
1738 else
1740 uno::Sequence< beans::PropertyValue > aArgs( 1 );
1741 aArgs[0].Name = "URL";
1742 aArgs[0].Value <<= m_aLinkURL;
1743 m_aLinkFilterName = aHelper.UpdateMediaDescriptorWithFilterName( aArgs, false );
1747 if ( !aOldLinkFilter.equals( m_aLinkFilterName ) )
1749 uno::Sequence< beans::NamedValue > aObject = aHelper.GetObjectPropsByFilter( m_aLinkFilterName );
1751 // TODO/LATER: probably the document holder could be cleaned explicitly as in the destructor
1752 m_pDocHolder->release();
1753 m_pDocHolder = nullptr;
1755 LinkInit_Impl( aObject, lArguments, lObjArgs );
1759 m_aDocMediaDescriptor = GetValuableArgs_Impl( lArguments, true );
1761 // TODO: use lObjArgs for StoreVisualReplacement
1762 for ( sal_Int32 nObjInd = 0; nObjInd < lObjArgs.getLength(); nObjInd++ )
1763 if ( lObjArgs[nObjInd].Name == "OutplaceDispatchInterceptor" )
1765 uno::Reference< frame::XDispatchProviderInterceptor > xDispatchInterceptor;
1766 if ( lObjArgs[nObjInd].Value >>= xDispatchInterceptor )
1767 m_pDocHolder->SetOutplaceDispatchInterceptor( xDispatchInterceptor );
1769 break;
1772 // TODO:
1773 // when document allows reloading through API the object can be reloaded not only in loaded state
1775 bool bOldReadOnlyValue = m_bReadOnly;
1777 m_bReadOnly = false;
1778 for ( sal_Int32 nInd = 0; nInd < lArguments.getLength(); nInd++ )
1779 if ( lArguments[nInd].Name == "ReadOnly" )
1780 lArguments[nInd].Value >>= m_bReadOnly;
1782 if ( bOldReadOnlyValue != m_bReadOnly && !m_bIsLink )
1784 // close own storage
1785 try {
1786 uno::Reference< lang::XComponent > xComponent( m_xObjectStorage, uno::UNO_QUERY );
1787 OSL_ENSURE( !m_xObjectStorage.is() || xComponent.is(), "Wrong storage implementation!" );
1788 if ( xComponent.is() )
1789 xComponent->dispose();
1791 catch ( const uno::Exception& )
1795 sal_Int32 nStorageMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
1796 m_xObjectStorage = m_xParentStorage->openStorageElement( m_aEntryName, nStorageMode );
1800 sal_Bool SAL_CALL OCommonEmbeddedObject::isStored() throw (css::uno::RuntimeException, std::exception)
1802 uno::Reference<container::XNameAccess> xNA(m_xObjectStorage, uno::UNO_QUERY);
1803 if (!xNA.is())
1804 return false;
1806 return xNA->getElementNames().getLength() > 0;
1810 void SAL_CALL OCommonEmbeddedObject::breakLink( const uno::Reference< embed::XStorage >& xStorage,
1811 const OUString& sEntName )
1812 throw ( lang::IllegalArgumentException,
1813 embed::WrongStateException,
1814 io::IOException,
1815 uno::Exception,
1816 uno::RuntimeException, std::exception )
1818 ::osl::ResettableMutexGuard aGuard( m_aMutex );
1819 if ( m_bDisposed )
1820 throw lang::DisposedException(); // TODO
1822 if ( !m_bIsLink )
1824 // it must be a linked initialized object
1825 throw embed::WrongStateException(
1826 "The object is not a valid linked object!",
1827 static_cast< ::cppu::OWeakObject* >(this) );
1829 else
1831 // the current implementation of OOo links does not implement this method since it does not implement
1832 // all the set of interfaces required for OOo embedded object ( XEmbedPersist is not supported ).
1835 if ( !xStorage.is() )
1836 throw lang::IllegalArgumentException( "No parent storage is provided!",
1837 static_cast< ::cppu::OWeakObject* >(this),
1838 1 );
1840 if ( sEntName.isEmpty() )
1841 throw lang::IllegalArgumentException( "Empty element name is provided!",
1842 static_cast< ::cppu::OWeakObject* >(this),
1843 2 );
1845 if ( !m_bIsLink || m_nObjectState == -1 )
1847 // it must be a linked initialized object
1848 throw embed::WrongStateException(
1849 "The object is not a valid linked object!",
1850 static_cast< ::cppu::OWeakObject* >(this) );
1853 if ( m_bWaitSaveCompleted )
1854 throw embed::WrongStateException(
1855 "The object waits for saveCompleted() call!",
1856 static_cast< ::cppu::OWeakObject* >(this) );
1858 uno::Reference< container::XNameAccess > xNameAccess( xStorage, uno::UNO_QUERY );
1859 if ( !xNameAccess.is() )
1860 throw uno::RuntimeException(); //TODO
1862 m_bReadOnly = false;
1864 if ( m_xParentStorage != xStorage || !m_aEntryName.equals( sEntName ) )
1865 SwitchOwnPersistence( xStorage, sEntName );
1867 // for linked object it means that it becomes embedded object
1868 // the document must switch it's persistence also
1870 // TODO/LATER: handle the case when temp doc can not be created
1871 // the document is a new embedded object so it must be marked as modified
1872 uno::Reference< util::XCloseable > xDocument = CreateTempDocFromLink_Impl();
1873 uno::Reference< util::XModifiable > xModif( m_pDocHolder->GetComponent(), uno::UNO_QUERY );
1874 if ( !xModif.is() )
1875 throw uno::RuntimeException();
1878 xModif->setModified( true );
1880 catch( const uno::Exception& )
1883 m_pDocHolder->SetComponent( xDocument, m_bReadOnly );
1884 SAL_WARN_IF( !m_pDocHolder->GetComponent().is(), "embeddedobj.common", "If document can't be created, an exception must be thrown!" );
1886 if ( m_nObjectState == embed::EmbedStates::LOADED )
1888 // the state is changed and can not be switched to loaded state back without saving
1889 m_nObjectState = embed::EmbedStates::RUNNING;
1890 StateChangeNotification_Impl( false, embed::EmbedStates::LOADED, m_nObjectState, aGuard );
1892 else if ( m_nObjectState == embed::EmbedStates::ACTIVE )
1893 m_pDocHolder->Show();
1895 m_bIsLink = false;
1896 m_aLinkFilterName.clear();
1897 m_aLinkURL.clear();
1901 sal_Bool SAL_CALL OCommonEmbeddedObject::isLink()
1902 throw ( embed::WrongStateException,
1903 uno::RuntimeException, std::exception )
1905 ::osl::MutexGuard aGuard( m_aMutex );
1906 if ( m_bDisposed )
1907 throw lang::DisposedException(); // TODO
1909 return m_bIsLink;
1913 OUString SAL_CALL OCommonEmbeddedObject::getLinkURL()
1914 throw ( embed::WrongStateException,
1915 uno::Exception,
1916 uno::RuntimeException, std::exception )
1918 ::osl::MutexGuard aGuard( m_aMutex );
1919 if ( m_bDisposed )
1920 throw lang::DisposedException(); // TODO
1922 if ( !m_bIsLink )
1923 throw embed::WrongStateException(
1924 "The object is not a link object!",
1925 static_cast< ::cppu::OWeakObject* >(this) );
1927 return m_aLinkURL;
1930 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */