nss: upgrade to release 3.73
[LibreOffice.git] / embeddedobj / source / commonembedding / persistence.cxx
blobd21eb297360ae2009ca471b9cb8ddf766b5d3730
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/EntryInitModes.hpp>
25 #include <com/sun/star/embed/StorageWrappedTargetException.hpp>
26 #include <com/sun/star/embed/WrongStateException.hpp>
27 #include <com/sun/star/embed/XStorage.hpp>
28 #include <com/sun/star/embed/XOptimizedStorage.hpp>
29 #include <com/sun/star/embed/ElementModes.hpp>
30 #include <com/sun/star/embed/EmbedUpdateModes.hpp>
31 #include <com/sun/star/embed/StorageFactory.hpp>
32 #include <com/sun/star/io/IOException.hpp>
33 #include <com/sun/star/io/TempFile.hpp>
34 #include <com/sun/star/frame/XModel.hpp>
35 #include <com/sun/star/frame/XStorable.hpp>
36 #include <com/sun/star/frame/XLoadable.hpp>
37 #include <com/sun/star/frame/XModule.hpp>
38 #include <com/sun/star/lang/NoSupportException.hpp>
39 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
40 #include <com/sun/star/lang/DisposedException.hpp>
41 #include <com/sun/star/util/XModifiable.hpp>
43 #include <com/sun/star/container/XNameAccess.hpp>
44 #include <com/sun/star/container/XChild.hpp>
45 #include <com/sun/star/util/XCloseable.hpp>
46 #include <com/sun/star/beans/XPropertySet.hpp>
47 #include <com/sun/star/beans/IllegalTypeException.hpp>
48 #include <com/sun/star/chart2/XChartDocument.hpp>
50 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
51 #include <com/sun/star/io/XTruncate.hpp>
53 #include <comphelper/fileformat.h>
54 #include <comphelper/storagehelper.hxx>
55 #include <comphelper/mimeconfighelper.hxx>
56 #include <comphelper/namedvaluecollection.hxx>
58 #include <tools/diagnose_ex.h>
59 #include <sal/log.hxx>
60 #include <unotools/configmgr.hxx>
61 #include "persistence.hxx"
63 using namespace ::com::sun::star;
66 uno::Sequence< beans::PropertyValue > GetValuableArgs_Impl( const uno::Sequence< beans::PropertyValue >& aMedDescr,
67 bool bCanUseDocumentBaseURL )
69 uno::Sequence< beans::PropertyValue > aResult;
70 sal_Int32 nResLen = 0;
72 for ( beans::PropertyValue const & prop : aMedDescr )
74 if ( prop.Name == "ComponentData" || prop.Name == "DocumentTitle"
75 || prop.Name == "InteractionHandler" || prop.Name == "JumpMark"
76 // || prop.Name == "Password" // makes no sense for embedded objects
77 || prop.Name == "Preview" || prop.Name == "ReadOnly"
78 || prop.Name == "StartPresentation" || prop.Name == "RepairPackage"
79 || prop.Name == "StatusIndicator" || prop.Name == "ViewData"
80 || prop.Name == "ViewId" || prop.Name == "MacroExecutionMode"
81 || prop.Name == "UpdateDocMode"
82 || (prop.Name == "DocumentBaseURL" && bCanUseDocumentBaseURL) )
84 aResult.realloc( ++nResLen );
85 aResult[nResLen-1] = prop;
89 return aResult;
93 static uno::Sequence< beans::PropertyValue > addAsTemplate( const uno::Sequence< beans::PropertyValue >& aOrig )
95 bool bAsTemplateSet = false;
96 sal_Int32 nLength = aOrig.getLength();
97 uno::Sequence< beans::PropertyValue > aResult( nLength );
99 for ( sal_Int32 nInd = 0; nInd < nLength; nInd++ )
101 aResult[nInd].Name = aOrig[nInd].Name;
102 if ( aResult[nInd].Name == "AsTemplate" )
104 aResult[nInd].Value <<= true;
105 bAsTemplateSet = true;
107 else
108 aResult[nInd].Value = aOrig[nInd].Value;
111 if ( !bAsTemplateSet )
113 aResult.realloc( nLength + 1 );
114 aResult[nLength].Name = "AsTemplate";
115 aResult[nLength].Value <<= true;
118 return aResult;
122 static uno::Reference< io::XInputStream > createTempInpStreamFromStor(
123 const uno::Reference< embed::XStorage >& xStorage,
124 const uno::Reference< uno::XComponentContext >& xContext )
126 SAL_WARN_IF( !xStorage.is(), "embeddedobj.common", "The storage can not be empty!" );
128 uno::Reference< io::XInputStream > xResult;
130 uno::Reference < io::XStream > xTempStream( io::TempFile::create(xContext), uno::UNO_QUERY_THROW );
132 uno::Reference < lang::XSingleServiceFactory > xStorageFactory( embed::StorageFactory::create(xContext) );
134 uno::Sequence< uno::Any > aArgs( 2 );
135 aArgs[0] <<= xTempStream;
136 aArgs[1] <<= embed::ElementModes::READWRITE;
137 uno::Reference< embed::XStorage > xTempStorage( xStorageFactory->createInstanceWithArguments( aArgs ),
138 uno::UNO_QUERY_THROW );
142 xStorage->copyToStorage( xTempStorage );
143 } catch( const uno::Exception& )
145 css::uno::Any anyEx = cppu::getCaughtException();
146 throw embed::StorageWrappedTargetException(
147 "Can't copy storage!",
148 uno::Reference< uno::XInterface >(),
149 anyEx );
152 try {
153 if ( xTempStorage.is() )
154 xTempStorage->dispose();
156 catch ( const uno::Exception& )
160 try {
161 uno::Reference< io::XOutputStream > xTempOut = xTempStream->getOutputStream();
162 if ( xTempOut.is() )
163 xTempOut->closeOutput();
165 catch ( const uno::Exception& )
169 xResult = xTempStream->getInputStream();
171 return xResult;
176 static void TransferMediaType( const uno::Reference< embed::XStorage >& i_rSource, const uno::Reference< embed::XStorage >& i_rTarget )
180 const uno::Reference< beans::XPropertySet > xSourceProps( i_rSource, uno::UNO_QUERY_THROW );
181 const uno::Reference< beans::XPropertySet > xTargetProps( i_rTarget, uno::UNO_QUERY_THROW );
182 const OUString sMediaTypePropName( "MediaType" );
183 xTargetProps->setPropertyValue( sMediaTypePropName, xSourceProps->getPropertyValue( sMediaTypePropName ) );
185 catch( const uno::Exception& )
187 DBG_UNHANDLED_EXCEPTION("embeddedobj.common");
192 static uno::Reference< util::XCloseable > CreateDocument( const uno::Reference< uno::XComponentContext >& _rxContext,
193 const OUString& _rDocumentServiceName, bool _bEmbeddedScriptSupport, const bool i_bDocumentRecoverySupport )
195 ::comphelper::NamedValueCollection aArguments;
196 aArguments.put( "EmbeddedObject", true );
197 aArguments.put( "EmbeddedScriptSupport", _bEmbeddedScriptSupport );
198 aArguments.put( "DocumentRecoverySupport", i_bDocumentRecoverySupport );
200 uno::Reference< uno::XInterface > xDocument;
203 xDocument = _rxContext->getServiceManager()->createInstanceWithArgumentsAndContext(
204 _rDocumentServiceName, aArguments.getWrappedPropertyValues(), _rxContext );
206 catch( const uno::Exception& )
208 // if an embedded object implementation does not support XInitialization,
209 // the default factory from cppuhelper will throw an
210 // IllegalArgumentException when we try to create the instance with arguments.
211 // Okay, so we fall back to creating the instance without any arguments.
212 OSL_FAIL("Consider implementing interface XInitialization to avoid duplicate construction");
213 xDocument = _rxContext->getServiceManager()->createInstanceWithContext( _rDocumentServiceName, _rxContext );
216 SAL_WARN_IF(!xDocument.is(), "embeddedobj.common", "Service " << _rDocumentServiceName << " is not available?");
217 return uno::Reference< util::XCloseable >( xDocument, uno::UNO_QUERY );
221 static void SetDocToEmbedded( const uno::Reference< frame::XModel >& rDocument, const OUString& aModuleName )
223 if (!rDocument.is())
224 return;
226 uno::Sequence< beans::PropertyValue > aSeq( 1 );
227 aSeq[0].Name = "SetEmbedded";
228 aSeq[0].Value <<= true;
229 rDocument->attachResource( OUString(), aSeq );
231 if ( !aModuleName.isEmpty() )
235 uno::Reference< frame::XModule > xModule( rDocument, uno::UNO_QUERY_THROW );
236 xModule->setIdentifier( aModuleName );
238 catch( const uno::Exception& )
244 void OCommonEmbeddedObject::SwitchOwnPersistence( const uno::Reference< embed::XStorage >& xNewParentStorage,
245 const uno::Reference< embed::XStorage >& xNewObjectStorage,
246 const OUString& aNewName )
248 if ( xNewParentStorage == m_xParentStorage && aNewName == m_aEntryName )
250 SAL_WARN_IF( xNewObjectStorage != m_xObjectStorage, "embeddedobj.common", "The storage must be the same!" );
251 return;
254 auto xOldObjectStorage = m_xObjectStorage;
255 m_xObjectStorage = xNewObjectStorage;
256 m_xParentStorage = xNewParentStorage;
257 m_aEntryName = aNewName;
259 // the linked document should not be switched
260 if ( !m_bIsLinkURL )
262 uno::Reference< document::XStorageBasedDocument > xDoc( m_xDocHolder->GetComponent(), uno::UNO_QUERY );
263 if ( xDoc.is() )
264 SwitchDocToStorage_Impl( xDoc, m_xObjectStorage );
267 try {
268 if ( xOldObjectStorage.is() )
269 xOldObjectStorage->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 == 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_THROW );
319 // set the document mode to embedded as the first action on document!!!
320 EmbedAndReparentDoc_Impl( xDocument );
322 // if we have a storage to recover the document from, do not use initNew, but instead load from that storage
323 bool bInitNew = true;
324 if ( m_xRecoveryStorage.is() )
326 uno::Reference< document::XStorageBasedDocument > xDoc( xLoadable, uno::UNO_QUERY );
327 SAL_WARN_IF( !xDoc.is(), "embeddedobj.common", "OCommonEmbeddedObject::InitNewDocument_Impl: cannot recover from a storage when the document is not storage based!" );
328 if ( xDoc.is() )
330 ::comphelper::NamedValueCollection aLoadArgs;
331 FillDefaultLoadArgs_Impl( m_xRecoveryStorage, aLoadArgs );
333 xDoc->loadFromStorage( m_xRecoveryStorage, aLoadArgs.getPropertyValues() );
334 SwitchDocToStorage_Impl( xDoc, m_xObjectStorage );
335 bInitNew = false;
339 if ( bInitNew )
341 // init document as a new
342 xLoadable->initNew();
344 xModel->attachResource( xModel->getURL(), m_aDocMediaDescriptor );
346 catch( const uno::Exception& )
348 if ( xDocument.is() )
352 xDocument->close( true );
354 catch( const uno::Exception& )
359 throw; // TODO
362 return xDocument;
366 uno::Reference< util::XCloseable > OCommonEmbeddedObject::LoadLink_Impl()
368 uno::Reference< util::XCloseable > xDocument( CreateDocument( m_xContext, GetDocumentServiceName(),
369 m_bEmbeddedScriptSupport, m_bDocumentRecoverySupport ) );
371 uno::Reference< frame::XLoadable > xLoadable( xDocument, uno::UNO_QUERY_THROW );
373 sal_Int32 nLen = 2;
374 uno::Sequence< beans::PropertyValue > aArgs( nLen );
376 aArgs[0].Name = "URL";
377 if(m_aLinkTempFile.is())
378 aArgs[0].Value <<= m_aLinkTempFile->getUri();
379 else
380 aArgs[0].Value <<= m_aLinkURL;
382 aArgs[1].Name = "FilterName";
383 aArgs[1].Value <<= m_aLinkFilterName;
385 if ( m_bLinkHasPassword )
387 aArgs.realloc( ++nLen );
388 aArgs[nLen-1].Name = "Password";
389 aArgs[nLen-1].Value <<= m_aLinkPassword;
392 aArgs.realloc( m_aDocMediaDescriptor.getLength() + nLen );
393 for ( sal_Int32 nInd = 0; nInd < m_aDocMediaDescriptor.getLength(); nInd++ )
395 aArgs[nInd+nLen].Name = m_aDocMediaDescriptor[nInd].Name;
396 aArgs[nInd+nLen].Value = m_aDocMediaDescriptor[nInd].Value;
401 // the document is not really an embedded one, it is a link
402 EmbedAndReparentDoc_Impl( xDocument );
404 // load the document
405 xLoadable->load( aArgs );
407 if ( !m_bLinkHasPassword )
409 // check if there is a password to cache
410 uno::Reference< frame::XModel > xModel( xLoadable, uno::UNO_QUERY_THROW );
411 const uno::Sequence< beans::PropertyValue > aProps = xModel->getArgs();
412 for ( beans::PropertyValue const & prop : aProps )
413 if ( prop.Name == "Password" && ( prop.Value >>= m_aLinkPassword ) )
415 m_bLinkHasPassword = true;
416 break;
420 catch( const uno::Exception& )
422 if ( xDocument.is() )
426 xDocument->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 OUString sDocumentServiceName = GetDocumentServiceName();
447 if (utl::ConfigManager::IsFuzzing() && nVersion == SOFFICE_FILEFORMAT_CURRENT &&
448 sDocumentServiceName == "com.sun.star.chart2.ChartDocument")
450 return "chart8";
452 try {
453 ::comphelper::MimeConfigurationHelper aHelper( m_xContext );
454 aFilterName = aHelper.GetDefaultFilterFromServiceName(sDocumentServiceName, nVersion);
456 // If no filter is found, fall back to the FileFormatVersion=6200 filter, Base only has that.
457 if (aFilterName.isEmpty() && nVersion == SOFFICE_FILEFORMAT_CURRENT)
458 aFilterName = aHelper.GetDefaultFilterFromServiceName(GetDocumentServiceName(), SOFFICE_FILEFORMAT_60);
459 } catch( const uno::Exception& )
463 return aFilterName;
467 void OCommonEmbeddedObject::FillDefaultLoadArgs_Impl( const uno::Reference< embed::XStorage >& i_rxStorage,
468 ::comphelper::NamedValueCollection& o_rLoadArgs ) const
470 o_rLoadArgs.put( "DocumentBaseURL", GetBaseURL_Impl() );
471 o_rLoadArgs.put( "HierarchicalDocumentName", m_aEntryName );
472 o_rLoadArgs.put( "ReadOnly", m_bReadOnly );
474 OUString aFilterName = GetFilterName( ::comphelper::OStorageHelper::GetXStorageFormat( i_rxStorage ) );
475 SAL_WARN_IF( aFilterName.isEmpty(), "embeddedobj.common", "OCommonEmbeddedObject::FillDefaultLoadArgs_Impl: Wrong document service name!" );
476 if ( aFilterName.isEmpty() )
477 throw io::IOException(); // TODO: error message/code
479 o_rLoadArgs.put( "FilterName", aFilterName );
483 uno::Reference< util::XCloseable > OCommonEmbeddedObject::LoadDocumentFromStorage_Impl()
485 ENSURE_OR_THROW( m_xObjectStorage.is(), "no object storage" );
487 const uno::Reference< embed::XStorage > xSourceStorage( m_xRecoveryStorage.is() ? m_xRecoveryStorage : m_xObjectStorage );
489 uno::Reference< util::XCloseable > xDocument( CreateDocument( m_xContext, GetDocumentServiceName(),
490 m_bEmbeddedScriptSupport, m_bDocumentRecoverySupport ) );
492 //#i103460# ODF: take the size given from the parent frame as default
493 uno::Reference< chart2::XChartDocument > xChart( xDocument, uno::UNO_QUERY );
494 if( xChart.is() )
496 uno::Reference< embed::XVisualObject > xChartVisualObject( xChart, uno::UNO_QUERY );
497 if( xChartVisualObject.is() )
498 xChartVisualObject->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT, m_aDefaultSizeForChart_In_100TH_MM );
501 uno::Reference< frame::XLoadable > xLoadable( xDocument, uno::UNO_QUERY );
502 uno::Reference< document::XStorageBasedDocument > xDoc( xDocument, uno::UNO_QUERY );
503 if ( !xDoc.is() && !xLoadable.is() )
504 throw uno::RuntimeException();
506 ::comphelper::NamedValueCollection aLoadArgs;
507 FillDefaultLoadArgs_Impl( xSourceStorage, aLoadArgs );
509 uno::Reference< io::XInputStream > xTempInpStream;
510 if ( !xDoc.is() )
512 xTempInpStream = createTempInpStreamFromStor( xSourceStorage, m_xContext );
513 if ( !xTempInpStream.is() )
514 throw uno::RuntimeException();
516 OUString aTempFileURL;
519 // no need to let the file stay after the stream is removed since the embedded document
520 // can not be stored directly
521 uno::Reference< beans::XPropertySet > xTempStreamProps( xTempInpStream, uno::UNO_QUERY_THROW );
522 xTempStreamProps->getPropertyValue("Uri") >>= aTempFileURL;
524 catch( const uno::Exception& )
528 SAL_WARN_IF( aTempFileURL.isEmpty(), "embeddedobj.common", "Couldn't retrieve temporary file URL!" );
530 aLoadArgs.put( "URL", aTempFileURL );
531 aLoadArgs.put( "InputStream", xTempInpStream );
535 aLoadArgs.merge( m_aDocMediaDescriptor, true );
539 // set the document mode to embedded as the first step!!!
540 EmbedAndReparentDoc_Impl( xDocument );
542 if ( xDoc.is() )
544 xDoc->loadFromStorage( xSourceStorage, aLoadArgs.getPropertyValues() );
545 if ( xSourceStorage != m_xObjectStorage )
546 SwitchDocToStorage_Impl( xDoc, m_xObjectStorage );
548 else
549 xLoadable->load( aLoadArgs.getPropertyValues() );
551 catch( const uno::Exception& )
553 if ( xDocument.is() )
557 xDocument->close( true );
559 catch( const uno::Exception& )
561 DBG_UNHANDLED_EXCEPTION("embeddedobj.common");
565 throw; // TODO
568 return xDocument;
572 uno::Reference< io::XInputStream > OCommonEmbeddedObject::StoreDocumentToTempStream_Impl(
573 sal_Int32 nStorageFormat,
574 const OUString& aBaseURL,
575 const OUString& aHierarchName )
577 uno::Reference < io::XOutputStream > xTempOut(
578 io::TempFile::create(m_xContext),
579 uno::UNO_QUERY_THROW );
580 uno::Reference< io::XInputStream > aResult( xTempOut, uno::UNO_QUERY_THROW );
582 uno::Reference< frame::XStorable > xStorable;
584 osl::MutexGuard aGuard( m_aMutex );
585 if ( m_xDocHolder.is() )
586 xStorable.set( m_xDocHolder->GetComponent(), uno::UNO_QUERY );
589 if( !xStorable.is() )
590 throw uno::RuntimeException(); // TODO:
592 OUString aFilterName = GetFilterName( nStorageFormat );
594 SAL_WARN_IF( aFilterName.isEmpty(), "embeddedobj.common", "Wrong document service name!" );
595 if ( aFilterName.isEmpty() )
596 throw io::IOException(); // TODO:
598 uno::Sequence< beans::PropertyValue > aArgs( 4 );
599 aArgs[0].Name = "FilterName";
600 aArgs[0].Value <<= aFilterName;
601 aArgs[1].Name = "OutputStream";
602 aArgs[1].Value <<= xTempOut;
603 aArgs[2].Name = "DocumentBaseURL";
604 aArgs[2].Value <<= aBaseURL;
605 aArgs[3].Name = "HierarchicalDocumentName";
606 aArgs[3].Value <<= aHierarchName;
608 xStorable->storeToURL( "private:stream", aArgs );
611 xTempOut->closeOutput();
613 catch( const uno::Exception& )
615 SAL_WARN( "embeddedobj.common", "Looks like stream was closed already" );
618 return aResult;
622 void OCommonEmbeddedObject::SaveObject_Impl()
624 if ( !m_xClientSite.is() )
625 return;
629 // check whether the component is modified,
630 // if not there is no need for storing
631 uno::Reference< util::XModifiable > xModifiable( m_xDocHolder->GetComponent(), uno::UNO_QUERY );
632 if ( xModifiable.is() && !xModifiable->isModified() )
633 return;
635 catch( const uno::Exception& )
638 try {
639 m_xClientSite->saveObject();
641 catch( const uno::Exception& )
643 SAL_WARN( "embeddedobj.common", "The object was not stored!" );
648 OUString OCommonEmbeddedObject::GetBaseURL_Impl() const
650 OUString aBaseURL;
652 if ( m_xClientSite.is() )
656 uno::Reference< frame::XModel > xParentModel( m_xClientSite->getComponent(), uno::UNO_QUERY_THROW );
657 const uno::Sequence< beans::PropertyValue > aModelProps = xParentModel->getArgs();
658 for ( beans::PropertyValue const & prop : aModelProps )
659 if ( prop.Name == "DocumentBaseURL" )
661 prop.Value >>= aBaseURL;
662 break;
665 catch( const uno::Exception& )
669 if ( aBaseURL.isEmpty() )
671 for ( beans::PropertyValue const & prop : m_aDocMediaDescriptor )
672 if ( prop.Name == "DocumentBaseURL" )
674 prop.Value >>= aBaseURL;
675 break;
679 if ( aBaseURL.isEmpty() )
680 aBaseURL = m_aDefaultParentBaseURL;
682 return aBaseURL;
686 OUString OCommonEmbeddedObject::GetBaseURLFrom_Impl(
687 const uno::Sequence< beans::PropertyValue >& lArguments,
688 const uno::Sequence< beans::PropertyValue >& lObjArgs )
690 OUString aBaseURL;
692 for ( beans::PropertyValue const & prop : lArguments )
693 if ( prop.Name == "DocumentBaseURL" )
695 prop.Value >>= aBaseURL;
696 break;
699 if ( aBaseURL.isEmpty() )
701 for ( beans::PropertyValue const & prop : lObjArgs )
702 if ( prop.Name == "DefaultParentBaseURL" )
704 prop.Value >>= aBaseURL;
705 break;
709 return aBaseURL;
713 void OCommonEmbeddedObject::SwitchDocToStorage_Impl( const uno::Reference< document::XStorageBasedDocument >& xDoc, const uno::Reference< embed::XStorage >& xStorage )
715 xDoc->switchToStorage( xStorage );
717 uno::Reference< util::XModifiable > xModif( xDoc, uno::UNO_QUERY );
718 if ( xModif.is() )
719 xModif->setModified( false );
721 if ( m_xRecoveryStorage.is() )
722 m_xRecoveryStorage.clear();
725 namespace {
727 OUString getStringPropertyValue( const uno::Sequence<beans::PropertyValue>& rProps, const OUString& rName )
729 OUString aStr;
731 for (beans::PropertyValue const & prop : rProps)
733 if (prop.Name == rName)
735 prop.Value >>= aStr;
736 break;
740 return aStr;
745 void OCommonEmbeddedObject::StoreDocToStorage_Impl(
746 const uno::Reference<embed::XStorage>& xStorage,
747 const uno::Sequence<beans::PropertyValue>& rMediaArgs,
748 const uno::Sequence<beans::PropertyValue>& rObjArgs,
749 sal_Int32 nStorageFormat,
750 const OUString& aHierarchName,
751 bool bAttachToTheStorage )
753 SAL_WARN_IF( !xStorage.is(), "embeddedobj.common", "No storage is provided for storing!" );
755 if ( !xStorage.is() )
756 throw uno::RuntimeException(); // TODO:
758 uno::Reference< document::XStorageBasedDocument > xDoc;
760 osl::MutexGuard aGuard( m_aMutex );
761 if ( m_xDocHolder.is() )
762 xDoc.set( m_xDocHolder->GetComponent(), uno::UNO_QUERY );
765 OUString aBaseURL = GetBaseURLFrom_Impl(rMediaArgs, rObjArgs);
767 if ( xDoc.is() )
769 OUString aFilterName = GetFilterName( nStorageFormat );
771 // No filter found? Try the older format, e.g. Base has only that.
772 if (aFilterName.isEmpty() && nStorageFormat == SOFFICE_FILEFORMAT_CURRENT)
773 aFilterName = GetFilterName( SOFFICE_FILEFORMAT_60 );
775 SAL_WARN_IF( aFilterName.isEmpty(), "embeddedobj.common", "Wrong document service name!" );
776 if ( aFilterName.isEmpty() )
777 throw io::IOException(); // TODO:
779 uno::Sequence<beans::PropertyValue> aArgs(5);
780 aArgs[0].Name = "FilterName";
781 aArgs[0].Value <<= aFilterName;
782 aArgs[1].Name = "HierarchicalDocumentName";
783 aArgs[1].Value <<= aHierarchName;
784 aArgs[2].Name = "DocumentBaseURL";
785 aArgs[2].Value <<= aBaseURL;
786 aArgs[3].Name = "SourceShellID";
787 aArgs[3].Value <<= getStringPropertyValue(rObjArgs, "SourceShellID");
788 aArgs[4].Name = "DestinationShellID";
789 aArgs[4].Value <<= getStringPropertyValue(rObjArgs, "DestinationShellID");
791 xDoc->storeToStorage( xStorage, aArgs );
792 if ( bAttachToTheStorage )
793 SwitchDocToStorage_Impl( xDoc, xStorage );
795 else
797 // store document to temporary stream based on temporary file
798 uno::Reference < io::XInputStream > xTempIn = StoreDocumentToTempStream_Impl( nStorageFormat, aBaseURL, aHierarchName );
800 SAL_WARN_IF( !xTempIn.is(), "embeddedobj.common", "The stream reference can not be empty!" );
802 // open storage based on document temporary file for reading
803 uno::Reference < lang::XSingleServiceFactory > xStorageFactory = embed::StorageFactory::create(m_xContext);
805 uno::Sequence< uno::Any > aArgs(1);
806 aArgs[0] <<= xTempIn;
807 uno::Reference< embed::XStorage > xTempStorage( xStorageFactory->createInstanceWithArguments( aArgs ),
808 uno::UNO_QUERY_THROW );
810 // object storage must be committed automatically
811 xTempStorage->copyToStorage( xStorage );
816 uno::Reference< util::XCloseable > OCommonEmbeddedObject::CreateDocFromMediaDescr_Impl(
817 const uno::Sequence< beans::PropertyValue >& aMedDescr )
819 uno::Reference< util::XCloseable > xDocument( CreateDocument( m_xContext, GetDocumentServiceName(),
820 m_bEmbeddedScriptSupport, m_bDocumentRecoverySupport ) );
822 uno::Reference< frame::XLoadable > xLoadable( xDocument, uno::UNO_QUERY_THROW );
826 // set the document mode to embedded as the first action on the document!!!
827 EmbedAndReparentDoc_Impl( xDocument );
829 xLoadable->load( addAsTemplate( aMedDescr ) );
831 catch( const uno::Exception& )
833 if ( xDocument.is() )
837 xDocument->close( true );
839 catch( const uno::Exception& )
844 throw; // TODO
847 return xDocument;
851 uno::Reference< util::XCloseable > OCommonEmbeddedObject::CreateTempDocFromLink_Impl()
853 uno::Reference< util::XCloseable > xResult;
855 SAL_WARN_IF( !m_bIsLinkURL, "embeddedobj.common", "The object is not a linked one!" );
857 uno::Sequence< beans::PropertyValue > aTempMediaDescr;
859 sal_Int32 nStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
860 try {
861 nStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage );
863 catch ( const beans::IllegalTypeException& )
865 // the container just has an unknown type, use current file format
867 catch ( const uno::Exception& )
869 SAL_WARN( "embeddedobj.common", "Can not retrieve storage media type!" );
872 if ( m_xDocHolder->GetComponent().is() )
874 aTempMediaDescr.realloc( 4 );
876 // TODO/LATER: may be private:stream should be used as target URL
877 OUString aTempFileURL;
878 uno::Reference< io::XInputStream > xTempStream = StoreDocumentToTempStream_Impl( SOFFICE_FILEFORMAT_CURRENT,
879 OUString(),
880 OUString() );
883 // no need to let the file stay after the stream is removed since the embedded document
884 // can not be stored directly
885 uno::Reference< beans::XPropertySet > xTempStreamProps( xTempStream, uno::UNO_QUERY_THROW );
886 xTempStreamProps->getPropertyValue("Uri") >>= aTempFileURL;
888 catch( const uno::Exception& )
892 SAL_WARN_IF( aTempFileURL.isEmpty(), "embeddedobj.common", "Couldn't retrieve temporary file URL!" );
894 aTempMediaDescr[0].Name = "URL";
895 aTempMediaDescr[0].Value <<= aTempFileURL;
896 aTempMediaDescr[1].Name = "InputStream";
897 aTempMediaDescr[1].Value <<= xTempStream;
898 aTempMediaDescr[2].Name = "FilterName";
899 aTempMediaDescr[2].Value <<= GetFilterName( nStorageFormat );
900 aTempMediaDescr[3].Name = "AsTemplate";
901 aTempMediaDescr[3].Value <<= true;
903 else
905 aTempMediaDescr.realloc( 2 );
906 aTempMediaDescr[0].Name = "URL";
908 // tdf#141529 use URL of the linked TempFile if it exists
909 aTempMediaDescr[0].Value <<= m_aLinkTempFile.is()
910 ? m_aLinkTempFile->getUri()
911 : m_aLinkURL;
913 aTempMediaDescr[1].Name = "FilterName";
914 aTempMediaDescr[1].Value <<= m_aLinkFilterName;
917 xResult = CreateDocFromMediaDescr_Impl( aTempMediaDescr );
919 return xResult;
923 void SAL_CALL OCommonEmbeddedObject::setPersistentEntry(
924 const uno::Reference< embed::XStorage >& xStorage,
925 const OUString& sEntName,
926 sal_Int32 nEntryConnectionMode,
927 const uno::Sequence< beans::PropertyValue >& lArguments,
928 const uno::Sequence< beans::PropertyValue >& lObjArgs )
930 // the type of the object must be already set
931 // a kind of typedetection should be done in the factory
933 ::osl::MutexGuard aGuard( m_aMutex );
934 if ( m_bDisposed )
935 throw lang::DisposedException(); // TODO
937 if ( !xStorage.is() )
938 throw lang::IllegalArgumentException( "No parent storage is provided!",
939 static_cast< ::cppu::OWeakObject* >(this),
940 1 );
942 if ( sEntName.isEmpty() )
943 throw lang::IllegalArgumentException( "Empty element name is provided!",
944 static_cast< ::cppu::OWeakObject* >(this),
945 2 );
947 // May be LOADED should be forbidden here ???
948 if ( ( m_nObjectState != -1 || nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
949 && ( m_nObjectState == -1 || nEntryConnectionMode != embed::EntryInitModes::NO_INIT ) )
951 // if the object is not loaded
952 // it can not get persistent representation without initialization
954 // if the object is loaded
955 // it can switch persistent representation only without initialization
957 throw embed::WrongStateException(
958 "Can't change persistent representation of activated object!",
959 static_cast< ::cppu::OWeakObject* >(this) );
962 if ( m_bWaitSaveCompleted )
964 if ( nEntryConnectionMode != embed::EntryInitModes::NO_INIT )
965 throw embed::WrongStateException(
966 "The object waits for saveCompleted() call!",
967 static_cast< ::cppu::OWeakObject* >(this) );
968 // saveCompleted is expected, handle it accordingly
969 if ( m_xNewParentStorage == xStorage && m_aNewEntryName == sEntName )
971 saveCompleted( true );
972 return;
975 // if a completely different entry is provided, switch first back to the old persistence in saveCompleted
976 // and then switch to the target persistence
977 bool bSwitchFurther = ( m_xParentStorage != xStorage || m_aEntryName != sEntName );
978 saveCompleted( false );
979 if ( !bSwitchFurther )
980 return;
983 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
984 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
985 // OSL_ENSURE( !m_bIsLinkURL, "This method implementation must not be used for links!" );
986 if ( m_bIsLinkURL )
988 m_aEntryName = sEntName;
989 return;
992 uno::Reference< container::XNameAccess > xNameAccess( xStorage, uno::UNO_QUERY_THROW );
994 // detect entry existence
995 bool bElExists = xNameAccess->hasByName( sEntName );
997 m_aDocMediaDescriptor = GetValuableArgs_Impl( lArguments,
998 nEntryConnectionMode != embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT );
1000 m_bReadOnly = false;
1001 for ( beans::PropertyValue const & prop : lArguments )
1002 if ( prop.Name == "ReadOnly" )
1003 prop.Value >>= m_bReadOnly;
1005 // TODO: use lObjArgs for StoreVisualReplacement
1006 for ( beans::PropertyValue const & prop : lObjArgs )
1007 if ( prop.Name == "OutplaceDispatchInterceptor" )
1009 uno::Reference< frame::XDispatchProviderInterceptor > xDispatchInterceptor;
1010 if ( prop.Value >>= xDispatchInterceptor )
1011 m_xDocHolder->SetOutplaceDispatchInterceptor( xDispatchInterceptor );
1013 else if ( prop.Name == "DefaultParentBaseURL" )
1015 prop.Value >>= m_aDefaultParentBaseURL;
1017 else if ( prop.Name == "Parent" )
1019 prop.Value >>= m_xParent;
1021 else if ( prop.Name == "IndividualMiscStatus" )
1023 sal_Int64 nMiscStatus=0;
1024 prop.Value >>= nMiscStatus;
1025 m_nMiscStatus |= nMiscStatus;
1027 else if ( prop.Name == "CloneFrom" )
1029 uno::Reference < embed::XEmbeddedObject > xObj;
1030 prop.Value >>= xObj;
1031 if ( xObj.is() )
1033 m_bHasClonedSize = true;
1034 m_aClonedSize = xObj->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT );
1035 m_nClonedMapUnit = xObj->getMapUnit( embed::Aspects::MSOLE_CONTENT );
1038 else if ( prop.Name == "OutplaceFrameProperties" )
1040 uno::Sequence< uno::Any > aOutFrameProps;
1041 uno::Sequence< beans::NamedValue > aOutFramePropsTyped;
1042 if ( prop.Value >>= aOutFrameProps )
1044 m_xDocHolder->SetOutplaceFrameProperties( aOutFrameProps );
1046 else if ( prop.Value >>= aOutFramePropsTyped )
1048 aOutFrameProps.realloc( aOutFramePropsTyped.getLength() );
1049 uno::Any* pProp = aOutFrameProps.getArray();
1050 for ( const beans::NamedValue* pTypedProp = aOutFramePropsTyped.getConstArray();
1051 pTypedProp != aOutFramePropsTyped.getConstArray() + aOutFramePropsTyped.getLength();
1052 ++pTypedProp, ++pProp
1055 *pProp <<= *pTypedProp;
1057 m_xDocHolder->SetOutplaceFrameProperties( aOutFrameProps );
1059 else
1060 SAL_WARN( "embeddedobj.common", "OCommonEmbeddedObject::setPersistentEntry: illegal type for argument 'OutplaceFrameProperties'!" );
1062 else if ( prop.Name == "ModuleName" )
1064 prop.Value >>= m_aModuleName;
1066 else if ( prop.Name == "EmbeddedScriptSupport" )
1068 OSL_VERIFY( prop.Value >>= m_bEmbeddedScriptSupport );
1070 else if ( prop.Name == "DocumentRecoverySupport" )
1072 OSL_VERIFY( prop.Value >>= m_bDocumentRecoverySupport );
1074 else if ( prop.Name == "RecoveryStorage" )
1076 OSL_VERIFY( prop.Value >>= m_xRecoveryStorage );
1080 sal_Int32 nStorageMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
1082 SwitchOwnPersistence( xStorage, sEntName );
1084 if ( nEntryConnectionMode == embed::EntryInitModes::DEFAULT_INIT )
1086 if ( bElExists )
1088 // the initialization from existing storage allows to leave object in loaded state
1089 m_nObjectState = embed::EmbedStates::LOADED;
1091 else
1093 m_xDocHolder->SetComponent( InitNewDocument_Impl(), m_bReadOnly );
1094 if ( !m_xDocHolder->GetComponent().is() )
1095 throw io::IOException(); // TODO: can not create document
1097 m_nObjectState = embed::EmbedStates::RUNNING;
1100 else
1102 if ( ( nStorageMode & embed::ElementModes::READWRITE ) != embed::ElementModes::READWRITE )
1103 throw io::IOException();
1105 if ( nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
1107 // the document just already changed its storage to store to
1108 // the links to OOo documents for now ignore this call
1109 // TODO: OOo links will have persistence so it will be switched here
1111 else if ( nEntryConnectionMode == embed::EntryInitModes::TRUNCATE_INIT )
1113 if ( m_xRecoveryStorage.is() )
1114 TransferMediaType( m_xRecoveryStorage, m_xObjectStorage );
1116 // TODO:
1117 m_xDocHolder->SetComponent( InitNewDocument_Impl(), m_bReadOnly );
1119 if ( !m_xDocHolder->GetComponent().is() )
1120 throw io::IOException(); // TODO: can not create document
1122 m_nObjectState = embed::EmbedStates::RUNNING;
1124 else if ( nEntryConnectionMode == embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT )
1126 m_xDocHolder->SetComponent( CreateDocFromMediaDescr_Impl( lArguments ), m_bReadOnly );
1127 m_nObjectState = embed::EmbedStates::RUNNING;
1129 //else if ( nEntryConnectionMode == embed::EntryInitModes::TRANSFERABLE_INIT )
1131 //TODO:
1133 else
1134 throw lang::IllegalArgumentException( "Wrong connection mode is provided!",
1135 static_cast< ::cppu::OWeakObject* >(this),
1136 3 );
1141 void SAL_CALL OCommonEmbeddedObject::storeToEntry( const uno::Reference< embed::XStorage >& xStorage,
1142 const OUString& sEntName,
1143 const uno::Sequence< beans::PropertyValue >& lArguments,
1144 const uno::Sequence< beans::PropertyValue >& lObjArgs )
1146 ::osl::ResettableMutexGuard aGuard( m_aMutex );
1147 if ( m_bDisposed )
1148 throw lang::DisposedException(); // TODO
1150 if ( m_nObjectState == -1 )
1152 // the object is still not loaded
1153 throw embed::WrongStateException( "Can't store object without persistence!",
1154 static_cast< ::cppu::OWeakObject* >(this) );
1157 if ( m_bWaitSaveCompleted )
1158 throw embed::WrongStateException(
1159 "The object waits for saveCompleted() call!",
1160 static_cast< ::cppu::OWeakObject* >(this) );
1162 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1163 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1164 // OSL_ENSURE( !m_bIsLinkURL, "This method implementation must not be used for links!" );
1165 if ( m_bIsLinkURL )
1166 return;
1168 OSL_ENSURE( m_xParentStorage.is() && m_xObjectStorage.is(), "The object has no valid persistence!" );
1170 sal_Int32 nTargetStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1171 sal_Int32 nOriginalStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1172 try {
1173 nTargetStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( xStorage );
1175 catch ( const beans::IllegalTypeException& )
1177 // the container just has an unknown type, use current file format
1179 catch ( const uno::Exception& )
1181 SAL_WARN( "embeddedobj.common", "Can not retrieve target storage media type!" );
1183 if (nTargetStorageFormat == SOFFICE_FILEFORMAT_60)
1185 SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1186 nTargetStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1187 // setting MediaType is done later anyway, no need to do it here
1192 nOriginalStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage );
1194 catch ( const beans::IllegalTypeException& )
1196 // the container just has an unknown type, use current file format
1198 catch ( const uno::Exception& )
1200 SAL_WARN( "embeddedobj.common", "Can not retrieve own storage media type!" );
1203 bool bTryOptimization = false;
1204 for ( beans::PropertyValue const & prop : lObjArgs )
1206 // StoreVisualReplacement and VisualReplacement args have no sense here
1207 if ( prop.Name == "CanTryOptimization" )
1208 prop.Value >>= bTryOptimization;
1211 bool bSwitchBackToLoaded = false;
1213 // Storing to different format can be done only in running state.
1214 if ( m_nObjectState == embed::EmbedStates::LOADED )
1216 // TODO/LATER: copying is not legal for documents with relative links.
1217 if ( nTargetStorageFormat == nOriginalStorageFormat )
1219 bool bOptimizationWorks = false;
1220 if ( bTryOptimization )
1224 // try to use optimized copying
1225 uno::Reference< embed::XOptimizedStorage > xSource( m_xParentStorage, uno::UNO_QUERY_THROW );
1226 uno::Reference< embed::XOptimizedStorage > xTarget( xStorage, uno::UNO_QUERY_THROW );
1227 xSource->copyElementDirectlyTo( m_aEntryName, xTarget, sEntName );
1228 bOptimizationWorks = true;
1230 catch( const uno::Exception& )
1235 if ( !bOptimizationWorks )
1236 m_xParentStorage->copyElementTo( m_aEntryName, xStorage, sEntName );
1238 else
1240 changeState( embed::EmbedStates::RUNNING );
1241 bSwitchBackToLoaded = true;
1245 if ( m_nObjectState == embed::EmbedStates::LOADED )
1246 return;
1248 uno::Reference< embed::XStorage > xSubStorage =
1249 xStorage->openStorageElement( sEntName, embed::ElementModes::READWRITE );
1251 if ( !xSubStorage.is() )
1252 throw uno::RuntimeException(); //TODO
1254 aGuard.clear();
1255 // TODO/LATER: support hierarchical name for embedded objects in embedded objects
1256 StoreDocToStorage_Impl(
1257 xSubStorage, lArguments, lObjArgs, nTargetStorageFormat, sEntName, false );
1258 aGuard.reset();
1260 if ( bSwitchBackToLoaded )
1261 changeState( embed::EmbedStates::LOADED );
1263 // TODO: should the listener notification be done?
1267 void SAL_CALL OCommonEmbeddedObject::storeAsEntry( const uno::Reference< embed::XStorage >& xStorage,
1268 const OUString& sEntName,
1269 const uno::Sequence< beans::PropertyValue >& lArguments,
1270 const uno::Sequence< beans::PropertyValue >& lObjArgs )
1272 // TODO: use lObjArgs
1274 ::osl::ResettableMutexGuard aGuard( m_aMutex );
1275 if ( m_bDisposed )
1276 throw lang::DisposedException(); // TODO
1278 if ( m_nObjectState == -1 )
1280 // the object is still not loaded
1281 throw embed::WrongStateException( "Can't store object without persistence!",
1282 static_cast< ::cppu::OWeakObject* >(this) );
1285 if ( m_bWaitSaveCompleted )
1286 throw embed::WrongStateException(
1287 "The object waits for saveCompleted() call!",
1288 static_cast< ::cppu::OWeakObject* >(this) );
1290 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1291 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1292 // OSL_ENSURE( !m_bIsLinkURL, "This method implementation must not be used for links!" );
1293 if ( m_bIsLinkURL )
1295 m_aNewEntryName = sEntName;
1297 if(m_aLinkTempFile.is() && m_bLinkTempFileChanged)
1299 // tdf#141529 if we have a changed copy of the original OLE data we now
1300 // need to write it back 'over' the original OLE data
1301 uno::Reference < ucb::XSimpleFileAccess2 > xFileAccess(ucb::SimpleFileAccess::create( m_xContext ));
1302 uno::Reference < io::XInputStream > xTempIn = m_aLinkTempFile->getInputStream();
1304 // This is *needed* since OTempFileService calls OTempFileService::readBytes which
1305 // ensures the SvStream mpStream gets/is opened, *but* also sets the mnCachedPos from
1306 // OTempFileService which still points to the end-of-file (from write-cc'ing).
1307 uno::Reference < io::XSeekable > xSeek( xTempIn, uno::UNO_QUERY_THROW );
1308 xSeek->seek(0);
1310 xFileAccess->writeFile(m_aLinkURL, xTempIn);
1312 // Do *not* close input, that would remove the temporary file too early
1313 // xTempIn->closeInput();
1315 // reset flag m_bLinkTempFileChanged
1316 m_bLinkTempFileChanged = false;
1319 return;
1322 OSL_ENSURE( m_xParentStorage.is() && m_xObjectStorage.is(), "The object has no valid persistence!" );
1324 sal_Int32 nTargetStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1325 sal_Int32 nOriginalStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1326 try {
1327 nTargetStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( xStorage );
1329 catch ( const beans::IllegalTypeException& )
1331 // the container just has an unknown type, use current file format
1333 catch ( const uno::Exception& )
1335 SAL_WARN( "embeddedobj.common", "Can not retrieve target storage media type!" );
1337 if (nTargetStorageFormat == SOFFICE_FILEFORMAT_60)
1339 SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1340 nTargetStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1341 // setting MediaType is done later anyway, no need to do it here
1346 nOriginalStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage );
1348 catch ( const beans::IllegalTypeException& )
1350 // the container just has an unknown type, use current file format
1352 catch ( const uno::Exception& )
1354 SAL_WARN( "embeddedobj.common", "Can not retrieve own storage media type!" );
1357 PostEvent_Impl( "OnSaveAs" );
1359 bool bTryOptimization = false;
1360 for ( beans::PropertyValue const & prop : lObjArgs )
1362 // StoreVisualReplacement and VisualReplacement args have no sense here
1363 if ( prop.Name == "CanTryOptimization" )
1364 prop.Value >>= bTryOptimization;
1367 bool bSwitchBackToLoaded = false;
1369 // Storing to different format can be done only in running state.
1370 if ( m_nObjectState == embed::EmbedStates::LOADED )
1372 // TODO/LATER: copying is not legal for documents with relative links.
1373 if ( nTargetStorageFormat == nOriginalStorageFormat )
1375 bool bOptimizationWorks = false;
1376 if ( bTryOptimization )
1380 // try to use optimized copying
1381 uno::Reference< embed::XOptimizedStorage > xSource( m_xParentStorage, uno::UNO_QUERY_THROW );
1382 uno::Reference< embed::XOptimizedStorage > xTarget( xStorage, uno::UNO_QUERY_THROW );
1383 xSource->copyElementDirectlyTo( m_aEntryName, xTarget, sEntName );
1384 bOptimizationWorks = true;
1386 catch( const uno::Exception& )
1391 if ( !bOptimizationWorks )
1392 m_xParentStorage->copyElementTo( m_aEntryName, xStorage, sEntName );
1394 else
1396 changeState( embed::EmbedStates::RUNNING );
1397 bSwitchBackToLoaded = true;
1401 uno::Reference< embed::XStorage > xSubStorage =
1402 xStorage->openStorageElement( sEntName, embed::ElementModes::READWRITE );
1404 if ( !xSubStorage.is() )
1405 throw uno::RuntimeException(); //TODO
1407 if ( m_nObjectState != embed::EmbedStates::LOADED )
1409 aGuard.clear();
1410 // TODO/LATER: support hierarchical name for embedded objects in embedded objects
1411 StoreDocToStorage_Impl(
1412 xSubStorage, lArguments, lObjArgs, nTargetStorageFormat, sEntName, false );
1413 aGuard.reset();
1415 if ( bSwitchBackToLoaded )
1416 changeState( embed::EmbedStates::LOADED );
1419 m_bWaitSaveCompleted = true;
1420 m_xNewObjectStorage = xSubStorage;
1421 m_xNewParentStorage = xStorage;
1422 m_aNewEntryName = sEntName;
1423 m_aNewDocMediaDescriptor = GetValuableArgs_Impl( lArguments, true );
1425 // TODO: register listeners for storages above, in case they are disposed
1426 // an exception will be thrown on saveCompleted( true )
1428 // TODO: should the listener notification be done here or in saveCompleted?
1432 void SAL_CALL OCommonEmbeddedObject::saveCompleted( sal_Bool bUseNew )
1434 ::osl::MutexGuard aGuard( m_aMutex );
1435 if ( m_bDisposed )
1436 throw lang::DisposedException(); // TODO
1438 if ( m_nObjectState == -1 )
1440 // the object is still not loaded
1441 throw embed::WrongStateException( "Can't store object without persistence!",
1442 static_cast< ::cppu::OWeakObject* >(this) );
1445 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1446 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1447 // OSL_ENSURE( !m_bIsLinkURL, "This method implementation must not be used for links!" );
1448 if ( m_bIsLinkURL )
1450 if ( bUseNew )
1451 m_aEntryName = m_aNewEntryName;
1452 m_aNewEntryName.clear();
1453 return;
1456 // it is allowed to call saveCompleted( false ) for nonstored objects
1457 if ( !m_bWaitSaveCompleted && !bUseNew )
1458 return;
1460 SAL_WARN_IF( !m_bWaitSaveCompleted, "embeddedobj.common", "Unexpected saveCompleted() call!" );
1461 if ( !m_bWaitSaveCompleted )
1462 throw io::IOException(); // TODO: illegal call
1464 OSL_ENSURE( m_xNewObjectStorage.is() && m_xNewParentStorage.is() , "Internal object information is broken!" );
1465 if ( !m_xNewObjectStorage.is() || !m_xNewParentStorage.is() )
1466 throw uno::RuntimeException(); // TODO: broken internal information
1468 if ( bUseNew )
1470 SwitchOwnPersistence( m_xNewParentStorage, m_xNewObjectStorage, m_aNewEntryName );
1471 m_aDocMediaDescriptor = m_aNewDocMediaDescriptor;
1473 uno::Reference< util::XModifiable > xModif( m_xDocHolder->GetComponent(), uno::UNO_QUERY );
1474 if ( xModif.is() )
1475 xModif->setModified( false );
1477 PostEvent_Impl( "OnSaveAsDone");
1479 else
1481 try {
1482 m_xNewObjectStorage->dispose();
1484 catch ( const uno::Exception& )
1489 m_xNewObjectStorage.clear();
1490 m_xNewParentStorage.clear();
1491 m_aNewEntryName.clear();
1492 m_aNewDocMediaDescriptor.realloc( 0 );
1493 m_bWaitSaveCompleted = false;
1495 if ( bUseNew )
1497 // TODO: notify listeners
1499 if ( m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE )
1501 // TODO: update visual representation
1507 sal_Bool SAL_CALL OCommonEmbeddedObject::hasEntry()
1509 ::osl::MutexGuard aGuard( m_aMutex );
1510 if ( m_bDisposed )
1511 throw lang::DisposedException(); // TODO
1513 if ( m_bWaitSaveCompleted )
1514 throw embed::WrongStateException(
1515 "The object waits for saveCompleted() call!",
1516 static_cast< ::cppu::OWeakObject* >(this) );
1518 if ( m_xObjectStorage.is() )
1519 return true;
1521 return false;
1525 OUString SAL_CALL OCommonEmbeddedObject::getEntryName()
1527 ::osl::MutexGuard aGuard( m_aMutex );
1528 if ( m_bDisposed )
1529 throw lang::DisposedException(); // TODO
1531 if ( m_nObjectState == -1 )
1533 // the object is still not loaded
1534 throw embed::WrongStateException( "The object persistence is not initialized!",
1535 static_cast< ::cppu::OWeakObject* >(this) );
1538 if ( m_bWaitSaveCompleted )
1539 throw embed::WrongStateException(
1540 "The object waits for saveCompleted() call!",
1541 static_cast< ::cppu::OWeakObject* >(this) );
1543 return m_aEntryName;
1547 void SAL_CALL OCommonEmbeddedObject::storeOwn()
1549 // during switching from Activated to Running and from Running to Loaded states the object will
1550 // ask container to store the object, the container has to make decision
1551 // to do so or not
1553 ::osl::ResettableMutexGuard aGuard( m_aMutex );
1554 if ( m_bDisposed )
1555 throw lang::DisposedException(); // TODO
1557 if ( m_nObjectState == -1 )
1559 // the object is still not loaded
1560 throw embed::WrongStateException( "Can't store object without persistence!",
1561 static_cast< ::cppu::OWeakObject* >(this) );
1564 if ( m_bWaitSaveCompleted )
1565 throw embed::WrongStateException(
1566 "The object waits for saveCompleted() call!",
1567 static_cast< ::cppu::OWeakObject* >(this) );
1569 if ( m_bReadOnly )
1570 throw io::IOException(); // TODO: access denied
1572 // nothing to do, if the object is in loaded state
1573 if ( m_nObjectState == embed::EmbedStates::LOADED )
1574 return;
1576 PostEvent_Impl( "OnSave" );
1578 SAL_WARN_IF( !m_xDocHolder->GetComponent().is(), "embeddedobj.common", "If an object is activated or in running state it must have a document!" );
1579 if ( !m_xDocHolder->GetComponent().is() )
1580 throw uno::RuntimeException();
1582 if ( m_bIsLinkURL )
1584 // TODO: just store the document to its location
1585 uno::Reference< frame::XStorable > xStorable( m_xDocHolder->GetComponent(), uno::UNO_QUERY_THROW );
1587 // free the main mutex for the storing time
1588 aGuard.clear();
1590 xStorable->store();
1592 aGuard.reset();
1594 else
1596 OSL_ENSURE( m_xParentStorage.is() && m_xObjectStorage.is(), "The object has no valid persistence!" );
1598 if ( !m_xObjectStorage.is() )
1599 throw io::IOException(); //TODO: access denied
1601 sal_Int32 nStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1602 try {
1603 nStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage );
1605 catch ( const beans::IllegalTypeException& )
1607 // the container just has an unknown type, use current file format
1609 catch ( const uno::Exception& )
1611 SAL_WARN( "embeddedobj.common", "Can not retrieve storage media type!" );
1613 if (nStorageFormat == SOFFICE_FILEFORMAT_60)
1615 SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1616 nStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1617 // setting MediaType is done later anyway, no need to do it here
1620 aGuard.clear();
1621 uno::Sequence<beans::PropertyValue> aEmpty;
1622 uno::Sequence<beans::PropertyValue> aMediaArgs(1);
1623 aMediaArgs[0].Name = "DocumentBaseURL";
1624 aMediaArgs[0].Value <<= GetBaseURL_Impl();
1625 StoreDocToStorage_Impl( m_xObjectStorage, aMediaArgs, aEmpty, nStorageFormat, m_aEntryName, true );
1626 aGuard.reset();
1629 uno::Reference< util::XModifiable > xModif( m_xDocHolder->GetComponent(), uno::UNO_QUERY );
1630 if ( xModif.is() )
1631 xModif->setModified( false );
1633 PostEvent_Impl( "OnSaveDone" );
1637 sal_Bool SAL_CALL OCommonEmbeddedObject::isReadonly()
1639 ::osl::MutexGuard aGuard( m_aMutex );
1640 if ( m_bDisposed )
1641 throw lang::DisposedException(); // TODO
1643 if ( m_nObjectState == -1 )
1645 // the object is still not loaded
1646 throw embed::WrongStateException( "The object persistence is not initialized!",
1647 static_cast< ::cppu::OWeakObject* >(this) );
1650 if ( m_bWaitSaveCompleted )
1651 throw embed::WrongStateException(
1652 "The object waits for saveCompleted() call!",
1653 static_cast< ::cppu::OWeakObject* >(this) );
1655 return m_bReadOnly;
1659 void SAL_CALL OCommonEmbeddedObject::reload(
1660 const uno::Sequence< beans::PropertyValue >& lArguments,
1661 const uno::Sequence< beans::PropertyValue >& lObjArgs )
1663 // TODO: use lObjArgs
1664 // for now this method is used only to switch readonly state
1666 ::osl::MutexGuard aGuard( m_aMutex );
1667 if ( m_bDisposed )
1668 throw lang::DisposedException(); // TODO
1670 if ( m_nObjectState == -1 )
1672 // the object is still not loaded
1673 throw embed::WrongStateException( "The object persistence is not initialized!",
1674 static_cast< ::cppu::OWeakObject* >(this) );
1677 if ( m_nObjectState != embed::EmbedStates::LOADED )
1679 // the object is still not loaded
1680 throw embed::WrongStateException(
1681 "The object must be in loaded state to be reloaded!",
1682 static_cast< ::cppu::OWeakObject* >(this) );
1685 if ( m_bWaitSaveCompleted )
1686 throw embed::WrongStateException(
1687 "The object waits for saveCompleted() call!",
1688 static_cast< ::cppu::OWeakObject* >(this) );
1690 if ( m_bIsLinkURL )
1692 // reload of the link
1693 OUString aOldLinkFilter = m_aLinkFilterName;
1695 OUString aNewLinkFilter;
1696 for ( beans::PropertyValue const & prop : lArguments )
1698 if ( prop.Name == "URL" )
1700 // the new URL
1701 prop.Value >>= m_aLinkURL;
1702 m_aLinkFilterName.clear();
1704 else if ( prop.Name == "FilterName" )
1706 prop.Value >>= aNewLinkFilter;
1707 m_aLinkFilterName.clear();
1711 ::comphelper::MimeConfigurationHelper aHelper( m_xContext );
1712 if ( m_aLinkFilterName.isEmpty() )
1714 if ( !aNewLinkFilter.isEmpty() )
1715 m_aLinkFilterName = aNewLinkFilter;
1716 else
1718 uno::Sequence< beans::PropertyValue > aArgs( 1 );
1719 aArgs[0].Name = "URL";
1720 aArgs[0].Value <<= m_aLinkURL;
1721 m_aLinkFilterName = aHelper.UpdateMediaDescriptorWithFilterName( aArgs, false );
1725 if ( aOldLinkFilter != m_aLinkFilterName )
1727 uno::Sequence< beans::NamedValue > aObject = aHelper.GetObjectPropsByFilter( m_aLinkFilterName );
1729 // TODO/LATER: probably the document holder could be cleaned explicitly as in the destructor
1730 m_xDocHolder.clear();
1732 LinkInit_Impl( aObject, lArguments, lObjArgs );
1736 m_aDocMediaDescriptor = GetValuableArgs_Impl( lArguments, true );
1738 // TODO: use lObjArgs for StoreVisualReplacement
1739 for ( beans::PropertyValue const & prop : lObjArgs )
1740 if ( prop.Name == "OutplaceDispatchInterceptor" )
1742 uno::Reference< frame::XDispatchProviderInterceptor > xDispatchInterceptor;
1743 if ( prop.Value >>= xDispatchInterceptor )
1744 m_xDocHolder->SetOutplaceDispatchInterceptor( xDispatchInterceptor );
1746 break;
1749 // TODO:
1750 // when document allows reloading through API the object can be reloaded not only in loaded state
1752 bool bOldReadOnlyValue = m_bReadOnly;
1754 m_bReadOnly = false;
1755 for ( beans::PropertyValue const & prop : lArguments )
1756 if ( prop.Name == "ReadOnly" )
1757 prop.Value >>= m_bReadOnly;
1759 if ( bOldReadOnlyValue == m_bReadOnly || m_bIsLinkURL )
1760 return;
1762 // close own storage
1763 try {
1764 if ( m_xObjectStorage.is() )
1765 m_xObjectStorage->dispose();
1767 catch ( const uno::Exception& )
1771 sal_Int32 nStorageMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
1772 m_xObjectStorage = m_xParentStorage->openStorageElement( m_aEntryName, nStorageMode );
1775 sal_Bool SAL_CALL OCommonEmbeddedObject::isStored()
1777 if (!m_xObjectStorage.is())
1778 return false;
1780 return m_xObjectStorage->getElementNames().hasElements();
1784 void SAL_CALL OCommonEmbeddedObject::breakLink( const uno::Reference< embed::XStorage >& xStorage,
1785 const OUString& sEntName )
1787 ::osl::ResettableMutexGuard aGuard( m_aMutex );
1788 if ( m_bDisposed )
1789 throw lang::DisposedException(); // TODO
1791 if (!m_bIsLinkURL || m_nObjectState == -1)
1793 // it must be a linked initialized object
1794 throw embed::WrongStateException(
1795 "The object is not a valid linked object!",
1796 static_cast< ::cppu::OWeakObject* >(this) );
1798 // the current implementation of OOo links does not implement this method since it does not implement
1799 // all the set of interfaces required for OOo embedded object ( XEmbedPersist is not supported ).
1801 if ( !xStorage.is() )
1802 throw lang::IllegalArgumentException( "No parent storage is provided!",
1803 static_cast< ::cppu::OWeakObject* >(this),
1804 1 );
1806 if ( sEntName.isEmpty() )
1807 throw lang::IllegalArgumentException( "Empty element name is provided!",
1808 static_cast< ::cppu::OWeakObject* >(this),
1809 2 );
1811 if ( m_bWaitSaveCompleted )
1812 throw embed::WrongStateException(
1813 "The object waits for saveCompleted() call!",
1814 static_cast< ::cppu::OWeakObject* >(this) );
1816 uno::Reference< container::XNameAccess > xNameAccess( xStorage, uno::UNO_QUERY_THROW );
1818 m_bReadOnly = false;
1820 if ( m_xParentStorage != xStorage || m_aEntryName != sEntName )
1821 SwitchOwnPersistence( xStorage, sEntName );
1823 // for linked object it means that it becomes embedded object
1824 // the document must switch it's persistence also
1826 // TODO/LATER: handle the case when temp doc can not be created
1827 // the document is a new embedded object so it must be marked as modified
1828 uno::Reference< util::XCloseable > xDocument = CreateTempDocFromLink_Impl();
1831 if(m_xDocHolder.is() && m_xDocHolder->GetComponent().is())
1833 // tdf#141528 m_xDocHolder->GetComponent() may be not set, so add it
1834 // to the try path to not get thrown out of the local context to the next
1835 // highter try...catch on the stack. To make breakLink work it is
1836 // *necessary* to execute the code below that resets the linked state,
1837 // esp. the *.clear stuff and resetting m_bIsLink.
1838 uno::Reference< util::XModifiable > xModif( m_xDocHolder->GetComponent(), uno::UNO_QUERY_THROW );
1840 // all other locations in this file check for xModif.is(), so do it here, too
1841 if ( xModif.is() )
1842 xModif->setModified( true );
1845 catch( const uno::Exception& )
1848 m_xDocHolder->SetComponent( xDocument, m_bReadOnly );
1849 SAL_WARN_IF( !m_xDocHolder->GetComponent().is(), "embeddedobj.common", "If document can't be created, an exception must be thrown!" );
1851 if ( m_nObjectState == embed::EmbedStates::LOADED )
1853 // the state is changed and can not be switched to loaded state back without saving
1854 m_nObjectState = embed::EmbedStates::RUNNING;
1855 StateChangeNotification_Impl( false, embed::EmbedStates::LOADED, m_nObjectState, aGuard );
1857 else if ( m_nObjectState == embed::EmbedStates::ACTIVE )
1858 m_xDocHolder->Show();
1860 // tdf#141529 reset all stuff involved in linked state, including
1861 // the OLE content copied to the temp file
1862 m_bIsLinkURL = false;
1863 m_aLinkTempFile.clear();
1864 m_aLinkFilterName.clear();
1865 m_aLinkURL.clear();
1869 sal_Bool SAL_CALL OCommonEmbeddedObject::isLink()
1871 ::osl::MutexGuard aGuard( m_aMutex );
1872 if ( m_bDisposed )
1873 throw lang::DisposedException(); // TODO
1875 return m_bIsLinkURL;
1879 OUString SAL_CALL OCommonEmbeddedObject::getLinkURL()
1881 ::osl::MutexGuard aGuard( m_aMutex );
1882 if ( m_bDisposed )
1883 throw lang::DisposedException(); // TODO
1885 if ( !m_bIsLinkURL )
1886 throw embed::WrongStateException(
1887 "The object is not a link object!",
1888 static_cast< ::cppu::OWeakObject* >(this) );
1890 return m_aLinkURL;
1893 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */