bump product version to 6.4.0.3
[LibreOffice.git] / embeddedobj / source / commonembedding / persistence.cxx
blobf162dfef5f31753220e4884abbe87bd0c9449444
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 <comphelper/fileformat.h>
51 #include <comphelper/storagehelper.hxx>
52 #include <comphelper/mimeconfighelper.hxx>
53 #include <comphelper/namedvaluecollection.hxx>
55 #include <tools/diagnose_ex.h>
56 #include <sal/log.hxx>
57 #include <unotools/configmgr.hxx>
58 #include "persistence.hxx"
60 using namespace ::com::sun::star;
63 uno::Sequence< beans::PropertyValue > GetValuableArgs_Impl( const uno::Sequence< beans::PropertyValue >& aMedDescr,
64 bool bCanUseDocumentBaseURL )
66 uno::Sequence< beans::PropertyValue > aResult;
67 sal_Int32 nResLen = 0;
69 for ( sal_Int32 nInd = 0; nInd < aMedDescr.getLength(); nInd++ )
71 if ( aMedDescr[nInd].Name == "ComponentData" || aMedDescr[nInd].Name == "DocumentTitle"
72 || aMedDescr[nInd].Name == "InteractionHandler" || aMedDescr[nInd].Name == "JumpMark"
73 // || aMedDescr[nInd].Name == "Password" // makes no sense for embedded objects
74 || aMedDescr[nInd].Name == "Preview" || aMedDescr[nInd].Name == "ReadOnly"
75 || aMedDescr[nInd].Name == "StartPresentation" || aMedDescr[nInd].Name == "RepairPackage"
76 || aMedDescr[nInd].Name == "StatusIndicator" || aMedDescr[nInd].Name == "ViewData"
77 || aMedDescr[nInd].Name == "ViewId" || aMedDescr[nInd].Name == "MacroExecutionMode"
78 || aMedDescr[nInd].Name == "UpdateDocMode"
79 || (aMedDescr[nInd].Name == "DocumentBaseURL" && bCanUseDocumentBaseURL) )
81 aResult.realloc( ++nResLen );
82 aResult[nResLen-1] = aMedDescr[nInd];
86 return aResult;
90 static uno::Sequence< beans::PropertyValue > addAsTemplate( const uno::Sequence< beans::PropertyValue >& aOrig )
92 bool bAsTemplateSet = false;
93 sal_Int32 nLength = aOrig.getLength();
94 uno::Sequence< beans::PropertyValue > aResult( nLength );
96 for ( sal_Int32 nInd = 0; nInd < nLength; nInd++ )
98 aResult[nInd].Name = aOrig[nInd].Name;
99 if ( aResult[nInd].Name == "AsTemplate" )
101 aResult[nInd].Value <<= true;
102 bAsTemplateSet = true;
104 else
105 aResult[nInd].Value = aOrig[nInd].Value;
108 if ( !bAsTemplateSet )
110 aResult.realloc( nLength + 1 );
111 aResult[nLength].Name = "AsTemplate";
112 aResult[nLength].Value <<= true;
115 return aResult;
119 static uno::Reference< io::XInputStream > createTempInpStreamFromStor(
120 const uno::Reference< embed::XStorage >& xStorage,
121 const uno::Reference< uno::XComponentContext >& xContext )
123 SAL_WARN_IF( !xStorage.is(), "embeddedobj.common", "The storage can not be empty!" );
125 uno::Reference< io::XInputStream > xResult;
127 uno::Reference < io::XStream > xTempStream( io::TempFile::create(xContext), uno::UNO_QUERY_THROW );
129 uno::Reference < lang::XSingleServiceFactory > xStorageFactory( embed::StorageFactory::create(xContext) );
131 uno::Sequence< uno::Any > aArgs( 2 );
132 aArgs[0] <<= xTempStream;
133 aArgs[1] <<= embed::ElementModes::READWRITE;
134 uno::Reference< embed::XStorage > xTempStorage( xStorageFactory->createInstanceWithArguments( aArgs ),
135 uno::UNO_QUERY_THROW );
139 xStorage->copyToStorage( xTempStorage );
140 } catch( const uno::Exception& )
142 css::uno::Any anyEx = cppu::getCaughtException();
143 throw embed::StorageWrappedTargetException(
144 "Can't copy storage!",
145 uno::Reference< uno::XInterface >(),
146 anyEx );
149 try {
150 if ( xTempStorage.is() )
151 xTempStorage->dispose();
153 catch ( const uno::Exception& )
157 try {
158 uno::Reference< io::XOutputStream > xTempOut = xTempStream->getOutputStream();
159 if ( xTempOut.is() )
160 xTempOut->closeOutput();
162 catch ( const uno::Exception& )
166 xResult = xTempStream->getInputStream();
168 return xResult;
173 static void TransferMediaType( const uno::Reference< embed::XStorage >& i_rSource, const uno::Reference< embed::XStorage >& i_rTarget )
177 const uno::Reference< beans::XPropertySet > xSourceProps( i_rSource, uno::UNO_QUERY_THROW );
178 const uno::Reference< beans::XPropertySet > xTargetProps( i_rTarget, uno::UNO_QUERY_THROW );
179 const OUString sMediaTypePropName( "MediaType" );
180 xTargetProps->setPropertyValue( sMediaTypePropName, xSourceProps->getPropertyValue( sMediaTypePropName ) );
182 catch( const uno::Exception& )
184 DBG_UNHANDLED_EXCEPTION("embeddedobj.common");
189 static uno::Reference< util::XCloseable > CreateDocument( const uno::Reference< uno::XComponentContext >& _rxContext,
190 const OUString& _rDocumentServiceName, bool _bEmbeddedScriptSupport, const bool i_bDocumentRecoverySupport )
192 ::comphelper::NamedValueCollection aArguments;
193 aArguments.put( "EmbeddedObject", true );
194 aArguments.put( "EmbeddedScriptSupport", _bEmbeddedScriptSupport );
195 aArguments.put( "DocumentRecoverySupport", i_bDocumentRecoverySupport );
197 uno::Reference< uno::XInterface > xDocument;
200 xDocument = _rxContext->getServiceManager()->createInstanceWithArgumentsAndContext(
201 _rDocumentServiceName, aArguments.getWrappedPropertyValues(), _rxContext );
203 catch( const uno::Exception& )
205 // if an embedded object implementation does not support XInitialization,
206 // the default factory from cppuhelper will throw an
207 // IllegalArgumentException when we try to create the instance with arguments.
208 // Okay, so we fall back to creating the instance without any arguments.
209 OSL_FAIL("Consider implementing interface XInitialization to avoid duplicate construction");
210 xDocument = _rxContext->getServiceManager()->createInstanceWithContext( _rDocumentServiceName, _rxContext );
213 SAL_WARN_IF(!xDocument.is(), "embeddedobj.common", "Service " << _rDocumentServiceName << " is not available?");
214 return uno::Reference< util::XCloseable >( xDocument, uno::UNO_QUERY );
218 static void SetDocToEmbedded( const uno::Reference< frame::XModel >& rDocument, const OUString& aModuleName )
220 if (rDocument.is())
222 uno::Sequence< beans::PropertyValue > aSeq( 1 );
223 aSeq[0].Name = "SetEmbedded";
224 aSeq[0].Value <<= true;
225 rDocument->attachResource( OUString(), aSeq );
227 if ( !aModuleName.isEmpty() )
231 uno::Reference< frame::XModule > xModule( rDocument, uno::UNO_QUERY_THROW );
232 xModule->setIdentifier( aModuleName );
234 catch( const uno::Exception& )
241 void OCommonEmbeddedObject::SwitchOwnPersistence( const uno::Reference< embed::XStorage >& xNewParentStorage,
242 const uno::Reference< embed::XStorage >& xNewObjectStorage,
243 const OUString& aNewName )
245 if ( xNewParentStorage == m_xParentStorage && aNewName == m_aEntryName )
247 SAL_WARN_IF( xNewObjectStorage != m_xObjectStorage, "embeddedobj.common", "The storage must be the same!" );
248 return;
251 auto xOldObjectStorage = m_xObjectStorage;
252 m_xObjectStorage = xNewObjectStorage;
253 m_xParentStorage = xNewParentStorage;
254 m_aEntryName = aNewName;
256 // the linked document should not be switched
257 if ( !m_bIsLink )
259 uno::Reference< document::XStorageBasedDocument > xDoc( m_xDocHolder->GetComponent(), uno::UNO_QUERY );
260 if ( xDoc.is() )
261 SwitchDocToStorage_Impl( xDoc, m_xObjectStorage );
264 try {
265 if ( xOldObjectStorage.is() )
266 xOldObjectStorage->dispose();
268 catch ( const uno::Exception& )
274 void OCommonEmbeddedObject::SwitchOwnPersistence( const uno::Reference< embed::XStorage >& xNewParentStorage,
275 const OUString& aNewName )
277 if ( xNewParentStorage == m_xParentStorage && aNewName == m_aEntryName )
278 return;
280 sal_Int32 nStorageMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
282 uno::Reference< embed::XStorage > xNewOwnStorage = xNewParentStorage->openStorageElement( aNewName, nStorageMode );
283 SAL_WARN_IF( !xNewOwnStorage.is(), "embeddedobj.common", "The method can not return empty reference!" );
285 SwitchOwnPersistence( xNewParentStorage, xNewOwnStorage, aNewName );
289 void OCommonEmbeddedObject::EmbedAndReparentDoc_Impl( const uno::Reference< util::XCloseable >& i_rxDocument ) const
291 SetDocToEmbedded( uno::Reference< frame::XModel >( i_rxDocument, uno::UNO_QUERY ), m_aModuleName );
295 uno::Reference < container::XChild > xChild( i_rxDocument, uno::UNO_QUERY );
296 if ( xChild.is() )
297 xChild->setParent( m_xParent );
299 catch( const lang::NoSupportException & )
301 SAL_WARN( "embeddedobj.common", "OCommonEmbeddedObject::EmbedAndReparentDoc: cannot set parent at document!" );
306 uno::Reference< util::XCloseable > OCommonEmbeddedObject::InitNewDocument_Impl()
308 uno::Reference< util::XCloseable > xDocument( CreateDocument( m_xContext, GetDocumentServiceName(),
309 m_bEmbeddedScriptSupport, m_bDocumentRecoverySupport ) );
311 uno::Reference< frame::XModel > xModel( xDocument, uno::UNO_QUERY );
312 uno::Reference< frame::XLoadable > xLoadable( xModel, uno::UNO_QUERY_THROW );
316 // set the document mode to embedded as the first action on document!!!
317 EmbedAndReparentDoc_Impl( xDocument );
319 // if we have a storage to recover the document from, do not use initNew, but instead load from that storage
320 bool bInitNew = true;
321 if ( m_xRecoveryStorage.is() )
323 uno::Reference< document::XStorageBasedDocument > xDoc( xLoadable, uno::UNO_QUERY );
324 SAL_WARN_IF( !xDoc.is(), "embeddedobj.common", "OCommonEmbeddedObject::InitNewDocument_Impl: cannot recover from a storage when the document is not storage based!" );
325 if ( xDoc.is() )
327 ::comphelper::NamedValueCollection aLoadArgs;
328 FillDefaultLoadArgs_Impl( m_xRecoveryStorage, aLoadArgs );
330 xDoc->loadFromStorage( m_xRecoveryStorage, aLoadArgs.getPropertyValues() );
331 SwitchDocToStorage_Impl( xDoc, m_xObjectStorage );
332 bInitNew = false;
336 if ( bInitNew )
338 // init document as a new
339 xLoadable->initNew();
341 xModel->attachResource( xModel->getURL(), m_aDocMediaDescriptor );
343 catch( const uno::Exception& )
345 if ( xDocument.is() )
349 xDocument->close( true );
351 catch( const uno::Exception& )
356 throw; // TODO
359 return xDocument;
363 uno::Reference< util::XCloseable > OCommonEmbeddedObject::LoadLink_Impl()
365 uno::Reference< util::XCloseable > xDocument( CreateDocument( m_xContext, GetDocumentServiceName(),
366 m_bEmbeddedScriptSupport, m_bDocumentRecoverySupport ) );
368 uno::Reference< frame::XLoadable > xLoadable( xDocument, uno::UNO_QUERY_THROW );
370 sal_Int32 nLen = 2;
371 uno::Sequence< beans::PropertyValue > aArgs( nLen );
372 aArgs[0].Name = "URL";
373 aArgs[0].Value <<= m_aLinkURL;
374 aArgs[1].Name = "FilterName";
375 aArgs[1].Value <<= m_aLinkFilterName;
376 if ( m_bLinkHasPassword )
378 aArgs.realloc( ++nLen );
379 aArgs[nLen-1].Name = "Password";
380 aArgs[nLen-1].Value <<= m_aLinkPassword;
383 aArgs.realloc( m_aDocMediaDescriptor.getLength() + nLen );
384 for ( sal_Int32 nInd = 0; nInd < m_aDocMediaDescriptor.getLength(); nInd++ )
386 aArgs[nInd+nLen].Name = m_aDocMediaDescriptor[nInd].Name;
387 aArgs[nInd+nLen].Value = m_aDocMediaDescriptor[nInd].Value;
392 // the document is not really an embedded one, it is a link
393 EmbedAndReparentDoc_Impl( xDocument );
395 // load the document
396 xLoadable->load( aArgs );
398 if ( !m_bLinkHasPassword )
400 // check if there is a password to cache
401 uno::Reference< frame::XModel > xModel( xLoadable, uno::UNO_QUERY_THROW );
402 uno::Sequence< beans::PropertyValue > aProps = xModel->getArgs();
403 for ( sal_Int32 nInd = 0; nInd < aProps.getLength(); nInd++ )
404 if ( aProps[nInd].Name == "Password" && ( aProps[nInd].Value >>= m_aLinkPassword ) )
406 m_bLinkHasPassword = true;
407 break;
411 catch( const uno::Exception& )
413 if ( xDocument.is() )
417 xDocument->close( true );
419 catch( const uno::Exception& )
424 throw; // TODO
427 return xDocument;
432 OUString OCommonEmbeddedObject::GetFilterName( sal_Int32 nVersion ) const
434 OUString aFilterName = GetPresetFilterName();
435 if ( aFilterName.isEmpty() )
437 OUString sDocumentServiceName = GetDocumentServiceName();
438 if (utl::ConfigManager::IsFuzzing() && nVersion == SOFFICE_FILEFORMAT_CURRENT &&
439 sDocumentServiceName == "com.sun.star.chart2.ChartDocument")
441 return "chart8";
443 try {
444 ::comphelper::MimeConfigurationHelper aHelper( m_xContext );
445 aFilterName = aHelper.GetDefaultFilterFromServiceName(sDocumentServiceName, nVersion);
447 // If no filter is found, fall back to the FileFormatVersion=6200 filter, Base only has that.
448 if (aFilterName.isEmpty() && nVersion == SOFFICE_FILEFORMAT_CURRENT)
449 aFilterName = aHelper.GetDefaultFilterFromServiceName(GetDocumentServiceName(), SOFFICE_FILEFORMAT_60);
450 } catch( const uno::Exception& )
454 return aFilterName;
458 void OCommonEmbeddedObject::FillDefaultLoadArgs_Impl( const uno::Reference< embed::XStorage >& i_rxStorage,
459 ::comphelper::NamedValueCollection& o_rLoadArgs ) const
461 o_rLoadArgs.put( "DocumentBaseURL", GetBaseURL_Impl() );
462 o_rLoadArgs.put( "HierarchicalDocumentName", m_aEntryName );
463 o_rLoadArgs.put( "ReadOnly", m_bReadOnly );
465 OUString aFilterName = GetFilterName( ::comphelper::OStorageHelper::GetXStorageFormat( i_rxStorage ) );
466 SAL_WARN_IF( aFilterName.isEmpty(), "embeddedobj.common", "OCommonEmbeddedObject::FillDefaultLoadArgs_Impl: Wrong document service name!" );
467 if ( aFilterName.isEmpty() )
468 throw io::IOException(); // TODO: error message/code
470 o_rLoadArgs.put( "FilterName", aFilterName );
474 uno::Reference< util::XCloseable > OCommonEmbeddedObject::LoadDocumentFromStorage_Impl()
476 ENSURE_OR_THROW( m_xObjectStorage.is(), "no object storage" );
478 const uno::Reference< embed::XStorage > xSourceStorage( m_xRecoveryStorage.is() ? m_xRecoveryStorage : m_xObjectStorage );
480 uno::Reference< util::XCloseable > xDocument( CreateDocument( m_xContext, GetDocumentServiceName(),
481 m_bEmbeddedScriptSupport, m_bDocumentRecoverySupport ) );
483 //#i103460# ODF: take the size given from the parent frame as default
484 uno::Reference< chart2::XChartDocument > xChart( xDocument, uno::UNO_QUERY );
485 if( xChart.is() )
487 uno::Reference< embed::XVisualObject > xChartVisualObject( xChart, uno::UNO_QUERY );
488 if( xChartVisualObject.is() )
489 xChartVisualObject->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT, m_aDefaultSizeForChart_In_100TH_MM );
492 uno::Reference< frame::XLoadable > xLoadable( xDocument, uno::UNO_QUERY );
493 uno::Reference< document::XStorageBasedDocument > xDoc( xDocument, uno::UNO_QUERY );
494 if ( !xDoc.is() && !xLoadable.is() )
495 throw uno::RuntimeException();
497 ::comphelper::NamedValueCollection aLoadArgs;
498 FillDefaultLoadArgs_Impl( xSourceStorage, aLoadArgs );
500 uno::Reference< io::XInputStream > xTempInpStream;
501 if ( !xDoc.is() )
503 xTempInpStream = createTempInpStreamFromStor( xSourceStorage, m_xContext );
504 if ( !xTempInpStream.is() )
505 throw uno::RuntimeException();
507 OUString aTempFileURL;
510 // no need to let the file stay after the stream is removed since the embedded document
511 // can not be stored directly
512 uno::Reference< beans::XPropertySet > xTempStreamProps( xTempInpStream, uno::UNO_QUERY_THROW );
513 xTempStreamProps->getPropertyValue("Uri") >>= aTempFileURL;
515 catch( const uno::Exception& )
519 SAL_WARN_IF( aTempFileURL.isEmpty(), "embeddedobj.common", "Couldn't retrieve temporary file URL!" );
521 aLoadArgs.put( "URL", aTempFileURL );
522 aLoadArgs.put( "InputStream", xTempInpStream );
526 aLoadArgs.merge( m_aDocMediaDescriptor, true );
530 // set the document mode to embedded as the first step!!!
531 EmbedAndReparentDoc_Impl( xDocument );
533 if ( xDoc.is() )
535 xDoc->loadFromStorage( xSourceStorage, aLoadArgs.getPropertyValues() );
536 if ( xSourceStorage != m_xObjectStorage )
537 SwitchDocToStorage_Impl( xDoc, m_xObjectStorage );
539 else
540 xLoadable->load( aLoadArgs.getPropertyValues() );
542 catch( const uno::Exception& )
544 if ( xDocument.is() )
548 xDocument->close( true );
550 catch( const uno::Exception& )
552 DBG_UNHANDLED_EXCEPTION("embeddedobj.common");
556 throw; // TODO
559 return xDocument;
563 uno::Reference< io::XInputStream > OCommonEmbeddedObject::StoreDocumentToTempStream_Impl(
564 sal_Int32 nStorageFormat,
565 const OUString& aBaseURL,
566 const OUString& aHierarchName )
568 uno::Reference < io::XOutputStream > xTempOut(
569 io::TempFile::create(m_xContext),
570 uno::UNO_QUERY_THROW );
571 uno::Reference< io::XInputStream > aResult( xTempOut, uno::UNO_QUERY_THROW );
573 uno::Reference< frame::XStorable > xStorable;
575 osl::MutexGuard aGuard( m_aMutex );
576 if ( m_xDocHolder.is() )
577 xStorable.set( m_xDocHolder->GetComponent(), uno::UNO_QUERY );
580 if( !xStorable.is() )
581 throw uno::RuntimeException(); // TODO:
583 OUString aFilterName = GetFilterName( nStorageFormat );
585 SAL_WARN_IF( aFilterName.isEmpty(), "embeddedobj.common", "Wrong document service name!" );
586 if ( aFilterName.isEmpty() )
587 throw io::IOException(); // TODO:
589 uno::Sequence< beans::PropertyValue > aArgs( 4 );
590 aArgs[0].Name = "FilterName";
591 aArgs[0].Value <<= aFilterName;
592 aArgs[1].Name = "OutputStream";
593 aArgs[1].Value <<= xTempOut;
594 aArgs[2].Name = "DocumentBaseURL";
595 aArgs[2].Value <<= aBaseURL;
596 aArgs[3].Name = "HierarchicalDocumentName";
597 aArgs[3].Value <<= aHierarchName;
599 xStorable->storeToURL( "private:stream", aArgs );
602 xTempOut->closeOutput();
604 catch( const uno::Exception& )
606 SAL_WARN( "embeddedobj.common", "Looks like stream was closed already" );
609 return aResult;
613 void OCommonEmbeddedObject::SaveObject_Impl()
615 if ( m_xClientSite.is() )
619 // check whether the component is modified,
620 // if not there is no need for storing
621 uno::Reference< util::XModifiable > xModifiable( m_xDocHolder->GetComponent(), uno::UNO_QUERY );
622 if ( xModifiable.is() && !xModifiable->isModified() )
623 return;
625 catch( const uno::Exception& )
628 try {
629 m_xClientSite->saveObject();
631 catch( const uno::Exception& )
633 SAL_WARN( "embeddedobj.common", "The object was not stored!" );
639 OUString OCommonEmbeddedObject::GetBaseURL_Impl() const
641 OUString aBaseURL;
642 sal_Int32 nInd = 0;
644 if ( m_xClientSite.is() )
648 uno::Reference< frame::XModel > xParentModel( m_xClientSite->getComponent(), uno::UNO_QUERY_THROW );
649 uno::Sequence< beans::PropertyValue > aModelProps = xParentModel->getArgs();
650 for ( nInd = 0; nInd < aModelProps.getLength(); nInd++ )
651 if ( aModelProps[nInd].Name == "DocumentBaseURL" )
653 aModelProps[nInd].Value >>= aBaseURL;
654 break;
659 catch( const uno::Exception& )
663 if ( aBaseURL.isEmpty() )
665 for ( nInd = 0; nInd < m_aDocMediaDescriptor.getLength(); nInd++ )
666 if ( m_aDocMediaDescriptor[nInd].Name == "DocumentBaseURL" )
668 m_aDocMediaDescriptor[nInd].Value >>= aBaseURL;
669 break;
673 if ( aBaseURL.isEmpty() )
674 aBaseURL = m_aDefaultParentBaseURL;
676 return aBaseURL;
680 OUString OCommonEmbeddedObject::GetBaseURLFrom_Impl(
681 const uno::Sequence< beans::PropertyValue >& lArguments,
682 const uno::Sequence< beans::PropertyValue >& lObjArgs )
684 OUString aBaseURL;
685 sal_Int32 nInd = 0;
687 for ( nInd = 0; nInd < lArguments.getLength(); nInd++ )
688 if ( lArguments[nInd].Name == "DocumentBaseURL" )
690 lArguments[nInd].Value >>= aBaseURL;
691 break;
694 if ( aBaseURL.isEmpty() )
696 for ( nInd = 0; nInd < lObjArgs.getLength(); nInd++ )
697 if ( lObjArgs[nInd].Name == "DefaultParentBaseURL" )
699 lObjArgs[nInd].Value >>= aBaseURL;
700 break;
704 return aBaseURL;
708 void OCommonEmbeddedObject::SwitchDocToStorage_Impl( const uno::Reference< document::XStorageBasedDocument >& xDoc, const uno::Reference< embed::XStorage >& xStorage )
710 xDoc->switchToStorage( xStorage );
712 uno::Reference< util::XModifiable > xModif( xDoc, uno::UNO_QUERY );
713 if ( xModif.is() )
714 xModif->setModified( false );
716 if ( m_xRecoveryStorage.is() )
717 m_xRecoveryStorage.clear();
720 namespace {
722 OUString getStringPropertyValue( const uno::Sequence<beans::PropertyValue>& rProps, const OUString& rName )
724 OUString aStr;
726 for (sal_Int32 i = 0; i < rProps.getLength(); ++i)
728 if (rProps[i].Name == rName)
730 rProps[i].Value >>= aStr;
731 break;
735 return aStr;
740 void OCommonEmbeddedObject::StoreDocToStorage_Impl(
741 const uno::Reference<embed::XStorage>& xStorage,
742 const uno::Sequence<beans::PropertyValue>& rMediaArgs,
743 const uno::Sequence<beans::PropertyValue>& rObjArgs,
744 sal_Int32 nStorageFormat,
745 const OUString& aHierarchName,
746 bool bAttachToTheStorage )
748 SAL_WARN_IF( !xStorage.is(), "embeddedobj.common", "No storage is provided for storing!" );
750 if ( !xStorage.is() )
751 throw uno::RuntimeException(); // TODO:
753 uno::Reference< document::XStorageBasedDocument > xDoc;
755 osl::MutexGuard aGuard( m_aMutex );
756 if ( m_xDocHolder.is() )
757 xDoc.set( m_xDocHolder->GetComponent(), uno::UNO_QUERY );
760 OUString aBaseURL = GetBaseURLFrom_Impl(rMediaArgs, rObjArgs);
762 if ( xDoc.is() )
764 OUString aFilterName = GetFilterName( nStorageFormat );
766 // No filter found? Try the older format, e.g. Base has only that.
767 if (aFilterName.isEmpty() && nStorageFormat == SOFFICE_FILEFORMAT_CURRENT)
768 aFilterName = GetFilterName( SOFFICE_FILEFORMAT_60 );
770 SAL_WARN_IF( aFilterName.isEmpty(), "embeddedobj.common", "Wrong document service name!" );
771 if ( aFilterName.isEmpty() )
772 throw io::IOException(); // TODO:
774 uno::Sequence<beans::PropertyValue> aArgs(5);
775 aArgs[0].Name = "FilterName";
776 aArgs[0].Value <<= aFilterName;
777 aArgs[1].Name = "HierarchicalDocumentName";
778 aArgs[1].Value <<= aHierarchName;
779 aArgs[2].Name = "DocumentBaseURL";
780 aArgs[2].Value <<= aBaseURL;
781 aArgs[3].Name = "SourceShellID";
782 aArgs[3].Value <<= getStringPropertyValue(rObjArgs, "SourceShellID");
783 aArgs[4].Name = "DestinationShellID";
784 aArgs[4].Value <<= getStringPropertyValue(rObjArgs, "DestinationShellID");
786 xDoc->storeToStorage( xStorage, aArgs );
787 if ( bAttachToTheStorage )
788 SwitchDocToStorage_Impl( xDoc, xStorage );
790 else
792 // store document to temporary stream based on temporary file
793 uno::Reference < io::XInputStream > xTempIn = StoreDocumentToTempStream_Impl( nStorageFormat, aBaseURL, aHierarchName );
795 SAL_WARN_IF( !xTempIn.is(), "embeddedobj.common", "The stream reference can not be empty!" );
797 // open storage based on document temporary file for reading
798 uno::Reference < lang::XSingleServiceFactory > xStorageFactory = embed::StorageFactory::create(m_xContext);
800 uno::Sequence< uno::Any > aArgs(1);
801 aArgs[0] <<= xTempIn;
802 uno::Reference< embed::XStorage > xTempStorage( xStorageFactory->createInstanceWithArguments( aArgs ),
803 uno::UNO_QUERY_THROW );
805 // object storage must be committed automatically
806 xTempStorage->copyToStorage( xStorage );
811 uno::Reference< util::XCloseable > OCommonEmbeddedObject::CreateDocFromMediaDescr_Impl(
812 const uno::Sequence< beans::PropertyValue >& aMedDescr )
814 uno::Reference< util::XCloseable > xDocument( CreateDocument( m_xContext, GetDocumentServiceName(),
815 m_bEmbeddedScriptSupport, m_bDocumentRecoverySupport ) );
817 uno::Reference< frame::XLoadable > xLoadable( xDocument, uno::UNO_QUERY_THROW );
821 // set the document mode to embedded as the first action on the document!!!
822 EmbedAndReparentDoc_Impl( xDocument );
824 xLoadable->load( addAsTemplate( aMedDescr ) );
826 catch( const uno::Exception& )
828 if ( xDocument.is() )
832 xDocument->close( true );
834 catch( const uno::Exception& )
839 throw; // TODO
842 return xDocument;
846 uno::Reference< util::XCloseable > OCommonEmbeddedObject::CreateTempDocFromLink_Impl()
848 uno::Reference< util::XCloseable > xResult;
850 SAL_WARN_IF( !m_bIsLink, "embeddedobj.common", "The object is not a linked one!" );
852 uno::Sequence< beans::PropertyValue > aTempMediaDescr;
854 sal_Int32 nStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
855 try {
856 nStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage );
858 catch ( const beans::IllegalTypeException& )
860 // the container just has an unknown type, use current file format
862 catch ( const uno::Exception& )
864 SAL_WARN( "embeddedobj.common", "Can not retrieve storage media type!" );
867 if ( m_xDocHolder->GetComponent().is() )
869 aTempMediaDescr.realloc( 4 );
871 // TODO/LATER: may be private:stream should be used as target URL
872 OUString aTempFileURL;
873 uno::Reference< io::XInputStream > xTempStream = StoreDocumentToTempStream_Impl( SOFFICE_FILEFORMAT_CURRENT,
874 OUString(),
875 OUString() );
878 // no need to let the file stay after the stream is removed since the embedded document
879 // can not be stored directly
880 uno::Reference< beans::XPropertySet > xTempStreamProps( xTempStream, uno::UNO_QUERY_THROW );
881 xTempStreamProps->getPropertyValue("Uri") >>= aTempFileURL;
883 catch( const uno::Exception& )
887 SAL_WARN_IF( aTempFileURL.isEmpty(), "embeddedobj.common", "Couldn't retrieve temporary file URL!" );
889 aTempMediaDescr[0].Name = "URL";
890 aTempMediaDescr[0].Value <<= aTempFileURL;
891 aTempMediaDescr[1].Name = "InputStream";
892 aTempMediaDescr[1].Value <<= xTempStream;
893 aTempMediaDescr[2].Name = "FilterName";
894 aTempMediaDescr[2].Value <<= GetFilterName( nStorageFormat );
895 aTempMediaDescr[3].Name = "AsTemplate";
896 aTempMediaDescr[3].Value <<= true;
898 else
900 aTempMediaDescr.realloc( 2 );
901 aTempMediaDescr[0].Name = "URL";
902 aTempMediaDescr[0].Value <<= m_aLinkURL;
903 aTempMediaDescr[1].Name = "FilterName";
904 aTempMediaDescr[1].Value <<= m_aLinkFilterName;
907 xResult = CreateDocFromMediaDescr_Impl( aTempMediaDescr );
909 return xResult;
913 void SAL_CALL OCommonEmbeddedObject::setPersistentEntry(
914 const uno::Reference< embed::XStorage >& xStorage,
915 const OUString& sEntName,
916 sal_Int32 nEntryConnectionMode,
917 const uno::Sequence< beans::PropertyValue >& lArguments,
918 const uno::Sequence< beans::PropertyValue >& lObjArgs )
920 // the type of the object must be already set
921 // a kind of typedetection should be done in the factory
923 ::osl::MutexGuard aGuard( m_aMutex );
924 if ( m_bDisposed )
925 throw lang::DisposedException(); // TODO
927 if ( !xStorage.is() )
928 throw lang::IllegalArgumentException( "No parent storage is provided!",
929 static_cast< ::cppu::OWeakObject* >(this),
930 1 );
932 if ( sEntName.isEmpty() )
933 throw lang::IllegalArgumentException( "Empty element name is provided!",
934 static_cast< ::cppu::OWeakObject* >(this),
935 2 );
937 // May be LOADED should be forbidden here ???
938 if ( ( m_nObjectState != -1 || nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
939 && ( m_nObjectState == -1 || nEntryConnectionMode != embed::EntryInitModes::NO_INIT ) )
941 // if the object is not loaded
942 // it can not get persistent representation without initialization
944 // if the object is loaded
945 // it can switch persistent representation only without initialization
947 throw embed::WrongStateException(
948 "Can't change persistent representation of activated object!",
949 static_cast< ::cppu::OWeakObject* >(this) );
952 if ( m_bWaitSaveCompleted )
954 if ( nEntryConnectionMode != embed::EntryInitModes::NO_INIT )
955 throw embed::WrongStateException(
956 "The object waits for saveCompleted() call!",
957 static_cast< ::cppu::OWeakObject* >(this) );
958 // saveCompleted is expected, handle it accordingly
959 if ( m_xNewParentStorage == xStorage && m_aNewEntryName == sEntName )
961 saveCompleted( true );
962 return;
965 // if a completely different entry is provided, switch first back to the old persistence in saveCompleted
966 // and then switch to the target persistence
967 bool bSwitchFurther = ( m_xParentStorage != xStorage || m_aEntryName != sEntName );
968 saveCompleted( false );
969 if ( !bSwitchFurther )
970 return;
973 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
974 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
975 // OSL_ENSURE( !m_bIsLink, "This method implementation must not be used for links!" );
976 if ( m_bIsLink )
978 m_aEntryName = sEntName;
979 return;
982 uno::Reference< container::XNameAccess > xNameAccess( xStorage, uno::UNO_QUERY_THROW );
984 // detect entry existence
985 bool bElExists = xNameAccess->hasByName( sEntName );
987 m_aDocMediaDescriptor = GetValuableArgs_Impl( lArguments,
988 nEntryConnectionMode != embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT );
990 m_bReadOnly = false;
991 for ( sal_Int32 nInd = 0; nInd < lArguments.getLength(); nInd++ )
992 if ( lArguments[nInd].Name == "ReadOnly" )
993 lArguments[nInd].Value >>= m_bReadOnly;
995 // TODO: use lObjArgs for StoreVisualReplacement
996 for ( sal_Int32 nObjInd = 0; nObjInd < lObjArgs.getLength(); nObjInd++ )
997 if ( lObjArgs[nObjInd].Name == "OutplaceDispatchInterceptor" )
999 uno::Reference< frame::XDispatchProviderInterceptor > xDispatchInterceptor;
1000 if ( lObjArgs[nObjInd].Value >>= xDispatchInterceptor )
1001 m_xDocHolder->SetOutplaceDispatchInterceptor( xDispatchInterceptor );
1003 else if ( lObjArgs[nObjInd].Name == "DefaultParentBaseURL" )
1005 lObjArgs[nObjInd].Value >>= m_aDefaultParentBaseURL;
1007 else if ( lObjArgs[nObjInd].Name == "Parent" )
1009 lObjArgs[nObjInd].Value >>= m_xParent;
1011 else if ( lObjArgs[nObjInd].Name == "IndividualMiscStatus" )
1013 sal_Int64 nMiscStatus=0;
1014 lObjArgs[nObjInd].Value >>= nMiscStatus;
1015 m_nMiscStatus |= nMiscStatus;
1017 else if ( lObjArgs[nObjInd].Name == "CloneFrom" )
1019 uno::Reference < embed::XEmbeddedObject > xObj;
1020 lObjArgs[nObjInd].Value >>= xObj;
1021 if ( xObj.is() )
1023 m_bHasClonedSize = true;
1024 m_aClonedSize = xObj->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT );
1025 m_nClonedMapUnit = xObj->getMapUnit( embed::Aspects::MSOLE_CONTENT );
1028 else if ( lObjArgs[nObjInd].Name == "OutplaceFrameProperties" )
1030 uno::Sequence< uno::Any > aOutFrameProps;
1031 uno::Sequence< beans::NamedValue > aOutFramePropsTyped;
1032 if ( lObjArgs[nObjInd].Value >>= aOutFrameProps )
1034 m_xDocHolder->SetOutplaceFrameProperties( aOutFrameProps );
1036 else if ( lObjArgs[nObjInd].Value >>= aOutFramePropsTyped )
1038 aOutFrameProps.realloc( aOutFramePropsTyped.getLength() );
1039 uno::Any* pProp = aOutFrameProps.getArray();
1040 for ( const beans::NamedValue* pTypedProp = aOutFramePropsTyped.getConstArray();
1041 pTypedProp != aOutFramePropsTyped.getConstArray() + aOutFramePropsTyped.getLength();
1042 ++pTypedProp, ++pProp
1045 *pProp <<= *pTypedProp;
1047 m_xDocHolder->SetOutplaceFrameProperties( aOutFrameProps );
1049 else
1050 SAL_WARN( "embeddedobj.common", "OCommonEmbeddedObject::setPersistentEntry: illegal type for argument 'OutplaceFrameProperties'!" );
1052 else if ( lObjArgs[nObjInd].Name == "ModuleName" )
1054 lObjArgs[nObjInd].Value >>= m_aModuleName;
1056 else if ( lObjArgs[nObjInd].Name == "EmbeddedScriptSupport" )
1058 OSL_VERIFY( lObjArgs[nObjInd].Value >>= m_bEmbeddedScriptSupport );
1060 else if ( lObjArgs[nObjInd].Name == "DocumentRecoverySupport" )
1062 OSL_VERIFY( lObjArgs[nObjInd].Value >>= m_bDocumentRecoverySupport );
1064 else if ( lObjArgs[nObjInd].Name == "RecoveryStorage" )
1066 OSL_VERIFY( lObjArgs[nObjInd].Value >>= m_xRecoveryStorage );
1070 sal_Int32 nStorageMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
1072 SwitchOwnPersistence( xStorage, sEntName );
1074 if ( nEntryConnectionMode == embed::EntryInitModes::DEFAULT_INIT )
1076 if ( bElExists )
1078 // the initialization from existing storage allows to leave object in loaded state
1079 m_nObjectState = embed::EmbedStates::LOADED;
1081 else
1083 m_xDocHolder->SetComponent( InitNewDocument_Impl(), m_bReadOnly );
1084 if ( !m_xDocHolder->GetComponent().is() )
1085 throw io::IOException(); // TODO: can not create document
1087 m_nObjectState = embed::EmbedStates::RUNNING;
1090 else
1092 if ( ( nStorageMode & embed::ElementModes::READWRITE ) != embed::ElementModes::READWRITE )
1093 throw io::IOException();
1095 if ( nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
1097 // the document just already changed its storage to store to
1098 // the links to OOo documents for now ignore this call
1099 // TODO: OOo links will have persistence so it will be switched here
1101 else if ( nEntryConnectionMode == embed::EntryInitModes::TRUNCATE_INIT )
1103 if ( m_xRecoveryStorage.is() )
1104 TransferMediaType( m_xRecoveryStorage, m_xObjectStorage );
1106 // TODO:
1107 m_xDocHolder->SetComponent( InitNewDocument_Impl(), m_bReadOnly );
1109 if ( !m_xDocHolder->GetComponent().is() )
1110 throw io::IOException(); // TODO: can not create document
1112 m_nObjectState = embed::EmbedStates::RUNNING;
1114 else if ( nEntryConnectionMode == embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT )
1116 m_xDocHolder->SetComponent( CreateDocFromMediaDescr_Impl( lArguments ), m_bReadOnly );
1117 m_nObjectState = embed::EmbedStates::RUNNING;
1119 //else if ( nEntryConnectionMode == embed::EntryInitModes::TRANSFERABLE_INIT )
1121 //TODO:
1123 else
1124 throw lang::IllegalArgumentException( "Wrong connection mode is provided!",
1125 static_cast< ::cppu::OWeakObject* >(this),
1126 3 );
1131 void SAL_CALL OCommonEmbeddedObject::storeToEntry( const uno::Reference< embed::XStorage >& xStorage,
1132 const OUString& sEntName,
1133 const uno::Sequence< beans::PropertyValue >& lArguments,
1134 const uno::Sequence< beans::PropertyValue >& lObjArgs )
1136 ::osl::ResettableMutexGuard aGuard( m_aMutex );
1137 if ( m_bDisposed )
1138 throw lang::DisposedException(); // TODO
1140 if ( m_nObjectState == -1 )
1142 // the object is still not loaded
1143 throw embed::WrongStateException( "Can't store object without persistence!",
1144 static_cast< ::cppu::OWeakObject* >(this) );
1147 if ( m_bWaitSaveCompleted )
1148 throw embed::WrongStateException(
1149 "The object waits for saveCompleted() call!",
1150 static_cast< ::cppu::OWeakObject* >(this) );
1152 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1153 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1154 // OSL_ENSURE( !m_bIsLink, "This method implementation must not be used for links!" );
1155 if ( m_bIsLink )
1156 return;
1158 OSL_ENSURE( m_xParentStorage.is() && m_xObjectStorage.is(), "The object has no valid persistence!" );
1160 sal_Int32 nTargetStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1161 sal_Int32 nOriginalStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1162 try {
1163 nTargetStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( xStorage );
1165 catch ( const beans::IllegalTypeException& )
1167 // the container just has an unknown type, use current file format
1169 catch ( const uno::Exception& )
1171 SAL_WARN( "embeddedobj.common", "Can not retrieve target storage media type!" );
1173 if (nTargetStorageFormat == SOFFICE_FILEFORMAT_60)
1175 SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1176 nTargetStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1177 // setting MediaType is done later anyway, no need to do it here
1182 nOriginalStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage );
1184 catch ( const beans::IllegalTypeException& )
1186 // the container just has an unknown type, use current file format
1188 catch ( const uno::Exception& )
1190 SAL_WARN( "embeddedobj.common", "Can not retrieve own storage media type!" );
1193 bool bTryOptimization = false;
1194 for ( sal_Int32 nInd = 0; nInd < lObjArgs.getLength(); nInd++ )
1196 // StoreVisualReplacement and VisualReplacement args have no sense here
1197 if ( lObjArgs[nInd].Name == "CanTryOptimization" )
1198 lObjArgs[nInd].Value >>= bTryOptimization;
1201 bool bSwitchBackToLoaded = false;
1203 // Storing to different format can be done only in running state.
1204 if ( m_nObjectState == embed::EmbedStates::LOADED )
1206 // TODO/LATER: copying is not legal for documents with relative links.
1207 if ( nTargetStorageFormat == nOriginalStorageFormat )
1209 bool bOptimizationWorks = false;
1210 if ( bTryOptimization )
1214 // try to use optimized copying
1215 uno::Reference< embed::XOptimizedStorage > xSource( m_xParentStorage, uno::UNO_QUERY_THROW );
1216 uno::Reference< embed::XOptimizedStorage > xTarget( xStorage, uno::UNO_QUERY_THROW );
1217 xSource->copyElementDirectlyTo( m_aEntryName, xTarget, sEntName );
1218 bOptimizationWorks = true;
1220 catch( const uno::Exception& )
1225 if ( !bOptimizationWorks )
1226 m_xParentStorage->copyElementTo( m_aEntryName, xStorage, sEntName );
1228 else
1230 changeState( embed::EmbedStates::RUNNING );
1231 bSwitchBackToLoaded = true;
1235 if ( m_nObjectState != embed::EmbedStates::LOADED )
1237 uno::Reference< embed::XStorage > xSubStorage =
1238 xStorage->openStorageElement( sEntName, embed::ElementModes::READWRITE );
1240 if ( !xSubStorage.is() )
1241 throw uno::RuntimeException(); //TODO
1243 aGuard.clear();
1244 // TODO/LATER: support hierarchical name for embedded objects in embedded objects
1245 StoreDocToStorage_Impl(
1246 xSubStorage, lArguments, lObjArgs, nTargetStorageFormat, sEntName, false );
1247 aGuard.reset();
1249 if ( bSwitchBackToLoaded )
1250 changeState( embed::EmbedStates::LOADED );
1253 // TODO: should the listener notification be done?
1257 void SAL_CALL OCommonEmbeddedObject::storeAsEntry( const uno::Reference< embed::XStorage >& xStorage,
1258 const OUString& sEntName,
1259 const uno::Sequence< beans::PropertyValue >& lArguments,
1260 const uno::Sequence< beans::PropertyValue >& lObjArgs )
1262 // TODO: use lObjArgs
1264 ::osl::ResettableMutexGuard aGuard( m_aMutex );
1265 if ( m_bDisposed )
1266 throw lang::DisposedException(); // TODO
1268 if ( m_nObjectState == -1 )
1270 // the object is still not loaded
1271 throw embed::WrongStateException( "Can't store object without persistence!",
1272 static_cast< ::cppu::OWeakObject* >(this) );
1275 if ( m_bWaitSaveCompleted )
1276 throw embed::WrongStateException(
1277 "The object waits for saveCompleted() call!",
1278 static_cast< ::cppu::OWeakObject* >(this) );
1280 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1281 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1282 // OSL_ENSURE( !m_bIsLink, "This method implementation must not be used for links!" );
1283 if ( m_bIsLink )
1285 m_aNewEntryName = sEntName;
1286 return;
1289 OSL_ENSURE( m_xParentStorage.is() && m_xObjectStorage.is(), "The object has no valid persistence!" );
1291 sal_Int32 nTargetStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1292 sal_Int32 nOriginalStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1293 try {
1294 nTargetStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( xStorage );
1296 catch ( const beans::IllegalTypeException& )
1298 // the container just has an unknown type, use current file format
1300 catch ( const uno::Exception& )
1302 SAL_WARN( "embeddedobj.common", "Can not retrieve target storage media type!" );
1304 if (nTargetStorageFormat == SOFFICE_FILEFORMAT_60)
1306 SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1307 nTargetStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1308 // setting MediaType is done later anyway, no need to do it here
1313 nOriginalStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage );
1315 catch ( const beans::IllegalTypeException& )
1317 // the container just has an unknown type, use current file format
1319 catch ( const uno::Exception& )
1321 SAL_WARN( "embeddedobj.common", "Can not retrieve own storage media type!" );
1324 PostEvent_Impl( "OnSaveAs" );
1326 bool bTryOptimization = false;
1327 for ( sal_Int32 nInd = 0; nInd < lObjArgs.getLength(); nInd++ )
1329 // StoreVisualReplacement and VisualReplacement args have no sense here
1330 if ( lObjArgs[nInd].Name == "CanTryOptimization" )
1331 lObjArgs[nInd].Value >>= bTryOptimization;
1334 bool bSwitchBackToLoaded = false;
1336 // Storing to different format can be done only in running state.
1337 if ( m_nObjectState == embed::EmbedStates::LOADED )
1339 // TODO/LATER: copying is not legal for documents with relative links.
1340 if ( nTargetStorageFormat == nOriginalStorageFormat )
1342 bool bOptimizationWorks = false;
1343 if ( bTryOptimization )
1347 // try to use optimized copying
1348 uno::Reference< embed::XOptimizedStorage > xSource( m_xParentStorage, uno::UNO_QUERY_THROW );
1349 uno::Reference< embed::XOptimizedStorage > xTarget( xStorage, uno::UNO_QUERY_THROW );
1350 xSource->copyElementDirectlyTo( m_aEntryName, xTarget, sEntName );
1351 bOptimizationWorks = true;
1353 catch( const uno::Exception& )
1358 if ( !bOptimizationWorks )
1359 m_xParentStorage->copyElementTo( m_aEntryName, xStorage, sEntName );
1361 else
1363 changeState( embed::EmbedStates::RUNNING );
1364 bSwitchBackToLoaded = true;
1368 uno::Reference< embed::XStorage > xSubStorage =
1369 xStorage->openStorageElement( sEntName, embed::ElementModes::READWRITE );
1371 if ( !xSubStorage.is() )
1372 throw uno::RuntimeException(); //TODO
1374 if ( m_nObjectState != embed::EmbedStates::LOADED )
1376 aGuard.clear();
1377 // TODO/LATER: support hierarchical name for embedded objects in embedded objects
1378 StoreDocToStorage_Impl(
1379 xSubStorage, lArguments, lObjArgs, nTargetStorageFormat, sEntName, false );
1380 aGuard.reset();
1382 if ( bSwitchBackToLoaded )
1383 changeState( embed::EmbedStates::LOADED );
1386 m_bWaitSaveCompleted = true;
1387 m_xNewObjectStorage = xSubStorage;
1388 m_xNewParentStorage = xStorage;
1389 m_aNewEntryName = sEntName;
1390 m_aNewDocMediaDescriptor = GetValuableArgs_Impl( lArguments, true );
1392 // TODO: register listeners for storages above, in case they are disposed
1393 // an exception will be thrown on saveCompleted( true )
1395 // TODO: should the listener notification be done here or in saveCompleted?
1399 void SAL_CALL OCommonEmbeddedObject::saveCompleted( sal_Bool bUseNew )
1401 ::osl::MutexGuard aGuard( m_aMutex );
1402 if ( m_bDisposed )
1403 throw lang::DisposedException(); // TODO
1405 if ( m_nObjectState == -1 )
1407 // the object is still not loaded
1408 throw embed::WrongStateException( "Can't store object without persistence!",
1409 static_cast< ::cppu::OWeakObject* >(this) );
1412 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1413 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1414 // OSL_ENSURE( !m_bIsLink, "This method implementation must not be used for links!" );
1415 if ( m_bIsLink )
1417 if ( bUseNew )
1418 m_aEntryName = m_aNewEntryName;
1419 m_aNewEntryName.clear();
1420 return;
1423 // it is allowed to call saveCompleted( false ) for nonstored objects
1424 if ( !m_bWaitSaveCompleted && !bUseNew )
1425 return;
1427 SAL_WARN_IF( !m_bWaitSaveCompleted, "embeddedobj.common", "Unexpected saveCompleted() call!" );
1428 if ( !m_bWaitSaveCompleted )
1429 throw io::IOException(); // TODO: illegal call
1431 OSL_ENSURE( m_xNewObjectStorage.is() && m_xNewParentStorage.is() , "Internal object information is broken!" );
1432 if ( !m_xNewObjectStorage.is() || !m_xNewParentStorage.is() )
1433 throw uno::RuntimeException(); // TODO: broken internal information
1435 if ( bUseNew )
1437 SwitchOwnPersistence( m_xNewParentStorage, m_xNewObjectStorage, m_aNewEntryName );
1438 m_aDocMediaDescriptor = m_aNewDocMediaDescriptor;
1440 uno::Reference< util::XModifiable > xModif( m_xDocHolder->GetComponent(), uno::UNO_QUERY );
1441 if ( xModif.is() )
1442 xModif->setModified( false );
1444 PostEvent_Impl( "OnSaveAsDone");
1446 else
1448 try {
1449 m_xNewObjectStorage->dispose();
1451 catch ( const uno::Exception& )
1456 m_xNewObjectStorage.clear();
1457 m_xNewParentStorage.clear();
1458 m_aNewEntryName.clear();
1459 m_aNewDocMediaDescriptor.realloc( 0 );
1460 m_bWaitSaveCompleted = false;
1462 if ( bUseNew )
1464 // TODO: notify listeners
1466 if ( m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE )
1468 // TODO: update visual representation
1474 sal_Bool SAL_CALL OCommonEmbeddedObject::hasEntry()
1476 ::osl::MutexGuard aGuard( m_aMutex );
1477 if ( m_bDisposed )
1478 throw lang::DisposedException(); // TODO
1480 if ( m_bWaitSaveCompleted )
1481 throw embed::WrongStateException(
1482 "The object waits for saveCompleted() call!",
1483 static_cast< ::cppu::OWeakObject* >(this) );
1485 if ( m_xObjectStorage.is() )
1486 return true;
1488 return false;
1492 OUString SAL_CALL OCommonEmbeddedObject::getEntryName()
1494 ::osl::MutexGuard aGuard( m_aMutex );
1495 if ( m_bDisposed )
1496 throw lang::DisposedException(); // TODO
1498 if ( m_nObjectState == -1 )
1500 // the object is still not loaded
1501 throw embed::WrongStateException( "The object persistence is not initialized!",
1502 static_cast< ::cppu::OWeakObject* >(this) );
1505 if ( m_bWaitSaveCompleted )
1506 throw embed::WrongStateException(
1507 "The object waits for saveCompleted() call!",
1508 static_cast< ::cppu::OWeakObject* >(this) );
1510 return m_aEntryName;
1514 void SAL_CALL OCommonEmbeddedObject::storeOwn()
1516 // during switching from Activated to Running and from Running to Loaded states the object will
1517 // ask container to store the object, the container has to make decision
1518 // to do so or not
1520 ::osl::ResettableMutexGuard aGuard( m_aMutex );
1521 if ( m_bDisposed )
1522 throw lang::DisposedException(); // TODO
1524 if ( m_nObjectState == -1 )
1526 // the object is still not loaded
1527 throw embed::WrongStateException( "Can't store object without persistence!",
1528 static_cast< ::cppu::OWeakObject* >(this) );
1531 if ( m_bWaitSaveCompleted )
1532 throw embed::WrongStateException(
1533 "The object waits for saveCompleted() call!",
1534 static_cast< ::cppu::OWeakObject* >(this) );
1536 if ( m_bReadOnly )
1537 throw io::IOException(); // TODO: access denied
1539 // nothing to do, if the object is in loaded state
1540 if ( m_nObjectState == embed::EmbedStates::LOADED )
1541 return;
1543 PostEvent_Impl( "OnSave" );
1545 SAL_WARN_IF( !m_xDocHolder->GetComponent().is(), "embeddedobj.common", "If an object is activated or in running state it must have a document!" );
1546 if ( !m_xDocHolder->GetComponent().is() )
1547 throw uno::RuntimeException();
1549 if ( m_bIsLink )
1551 // TODO: just store the document to its location
1552 uno::Reference< frame::XStorable > xStorable( m_xDocHolder->GetComponent(), uno::UNO_QUERY_THROW );
1554 // free the main mutex for the storing time
1555 aGuard.clear();
1557 xStorable->store();
1559 aGuard.reset();
1561 else
1563 OSL_ENSURE( m_xParentStorage.is() && m_xObjectStorage.is(), "The object has no valid persistence!" );
1565 if ( !m_xObjectStorage.is() )
1566 throw io::IOException(); //TODO: access denied
1568 sal_Int32 nStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1569 try {
1570 nStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage );
1572 catch ( const beans::IllegalTypeException& )
1574 // the container just has an unknown type, use current file format
1576 catch ( const uno::Exception& )
1578 SAL_WARN( "embeddedobj.common", "Can not retrieve storage media type!" );
1580 if (nStorageFormat == SOFFICE_FILEFORMAT_60)
1582 SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1583 nStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1584 // setting MediaType is done later anyway, no need to do it here
1587 aGuard.clear();
1588 uno::Sequence<beans::PropertyValue> aEmpty;
1589 uno::Sequence<beans::PropertyValue> aMediaArgs(1);
1590 aMediaArgs[0].Name = "DocumentBaseURL";
1591 aMediaArgs[0].Value <<= GetBaseURL_Impl();
1592 StoreDocToStorage_Impl( m_xObjectStorage, aMediaArgs, aEmpty, nStorageFormat, m_aEntryName, true );
1593 aGuard.reset();
1596 uno::Reference< util::XModifiable > xModif( m_xDocHolder->GetComponent(), uno::UNO_QUERY );
1597 if ( xModif.is() )
1598 xModif->setModified( false );
1600 PostEvent_Impl( "OnSaveDone" );
1604 sal_Bool SAL_CALL OCommonEmbeddedObject::isReadonly()
1606 ::osl::MutexGuard aGuard( m_aMutex );
1607 if ( m_bDisposed )
1608 throw lang::DisposedException(); // TODO
1610 if ( m_nObjectState == -1 )
1612 // the object is still not loaded
1613 throw embed::WrongStateException( "The object persistence is not initialized!",
1614 static_cast< ::cppu::OWeakObject* >(this) );
1617 if ( m_bWaitSaveCompleted )
1618 throw embed::WrongStateException(
1619 "The object waits for saveCompleted() call!",
1620 static_cast< ::cppu::OWeakObject* >(this) );
1622 return m_bReadOnly;
1626 void SAL_CALL OCommonEmbeddedObject::reload(
1627 const uno::Sequence< beans::PropertyValue >& lArguments,
1628 const uno::Sequence< beans::PropertyValue >& lObjArgs )
1630 // TODO: use lObjArgs
1631 // for now this method is used only to switch readonly state
1633 ::osl::MutexGuard aGuard( m_aMutex );
1634 if ( m_bDisposed )
1635 throw lang::DisposedException(); // TODO
1637 if ( m_nObjectState == -1 )
1639 // the object is still not loaded
1640 throw embed::WrongStateException( "The object persistence is not initialized!",
1641 static_cast< ::cppu::OWeakObject* >(this) );
1644 if ( m_nObjectState != embed::EmbedStates::LOADED )
1646 // the object is still not loaded
1647 throw embed::WrongStateException(
1648 "The object must be in loaded state to be reloaded!",
1649 static_cast< ::cppu::OWeakObject* >(this) );
1652 if ( m_bWaitSaveCompleted )
1653 throw embed::WrongStateException(
1654 "The object waits for saveCompleted() call!",
1655 static_cast< ::cppu::OWeakObject* >(this) );
1657 if ( m_bIsLink )
1659 // reload of the link
1660 OUString aOldLinkFilter = m_aLinkFilterName;
1662 OUString aNewLinkFilter;
1663 for ( sal_Int32 nInd = 0; nInd < lArguments.getLength(); nInd++ )
1665 if ( lArguments[nInd].Name == "URL" )
1667 // the new URL
1668 lArguments[nInd].Value >>= m_aLinkURL;
1669 m_aLinkFilterName.clear();
1671 else if ( lArguments[nInd].Name == "FilterName" )
1673 lArguments[nInd].Value >>= aNewLinkFilter;
1674 m_aLinkFilterName.clear();
1678 ::comphelper::MimeConfigurationHelper aHelper( m_xContext );
1679 if ( m_aLinkFilterName.isEmpty() )
1681 if ( !aNewLinkFilter.isEmpty() )
1682 m_aLinkFilterName = aNewLinkFilter;
1683 else
1685 uno::Sequence< beans::PropertyValue > aArgs( 1 );
1686 aArgs[0].Name = "URL";
1687 aArgs[0].Value <<= m_aLinkURL;
1688 m_aLinkFilterName = aHelper.UpdateMediaDescriptorWithFilterName( aArgs, false );
1692 if ( aOldLinkFilter != m_aLinkFilterName )
1694 uno::Sequence< beans::NamedValue > aObject = aHelper.GetObjectPropsByFilter( m_aLinkFilterName );
1696 // TODO/LATER: probably the document holder could be cleaned explicitly as in the destructor
1697 m_xDocHolder.clear();
1699 LinkInit_Impl( aObject, lArguments, lObjArgs );
1703 m_aDocMediaDescriptor = GetValuableArgs_Impl( lArguments, true );
1705 // TODO: use lObjArgs for StoreVisualReplacement
1706 for ( sal_Int32 nObjInd = 0; nObjInd < lObjArgs.getLength(); nObjInd++ )
1707 if ( lObjArgs[nObjInd].Name == "OutplaceDispatchInterceptor" )
1709 uno::Reference< frame::XDispatchProviderInterceptor > xDispatchInterceptor;
1710 if ( lObjArgs[nObjInd].Value >>= xDispatchInterceptor )
1711 m_xDocHolder->SetOutplaceDispatchInterceptor( xDispatchInterceptor );
1713 break;
1716 // TODO:
1717 // when document allows reloading through API the object can be reloaded not only in loaded state
1719 bool bOldReadOnlyValue = m_bReadOnly;
1721 m_bReadOnly = false;
1722 for ( sal_Int32 nInd = 0; nInd < lArguments.getLength(); nInd++ )
1723 if ( lArguments[nInd].Name == "ReadOnly" )
1724 lArguments[nInd].Value >>= m_bReadOnly;
1726 if ( bOldReadOnlyValue != m_bReadOnly && !m_bIsLink )
1728 // close own storage
1729 try {
1730 if ( m_xObjectStorage.is() )
1731 m_xObjectStorage->dispose();
1733 catch ( const uno::Exception& )
1737 sal_Int32 nStorageMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
1738 m_xObjectStorage = m_xParentStorage->openStorageElement( m_aEntryName, nStorageMode );
1742 sal_Bool SAL_CALL OCommonEmbeddedObject::isStored()
1744 if (!m_xObjectStorage.is())
1745 return false;
1747 return m_xObjectStorage->getElementNames().hasElements();
1751 void SAL_CALL OCommonEmbeddedObject::breakLink( const uno::Reference< embed::XStorage >& xStorage,
1752 const OUString& sEntName )
1754 ::osl::ResettableMutexGuard aGuard( m_aMutex );
1755 if ( m_bDisposed )
1756 throw lang::DisposedException(); // TODO
1758 if (!m_bIsLink || m_nObjectState == -1)
1760 // it must be a linked initialized object
1761 throw embed::WrongStateException(
1762 "The object is not a valid linked object!",
1763 static_cast< ::cppu::OWeakObject* >(this) );
1765 // the current implementation of OOo links does not implement this method since it does not implement
1766 // all the set of interfaces required for OOo embedded object ( XEmbedPersist is not supported ).
1768 if ( !xStorage.is() )
1769 throw lang::IllegalArgumentException( "No parent storage is provided!",
1770 static_cast< ::cppu::OWeakObject* >(this),
1771 1 );
1773 if ( sEntName.isEmpty() )
1774 throw lang::IllegalArgumentException( "Empty element name is provided!",
1775 static_cast< ::cppu::OWeakObject* >(this),
1776 2 );
1778 if ( m_bWaitSaveCompleted )
1779 throw embed::WrongStateException(
1780 "The object waits for saveCompleted() call!",
1781 static_cast< ::cppu::OWeakObject* >(this) );
1783 uno::Reference< container::XNameAccess > xNameAccess( xStorage, uno::UNO_QUERY_THROW );
1785 m_bReadOnly = false;
1787 if ( m_xParentStorage != xStorage || m_aEntryName != sEntName )
1788 SwitchOwnPersistence( xStorage, sEntName );
1790 // for linked object it means that it becomes embedded object
1791 // the document must switch it's persistence also
1793 // TODO/LATER: handle the case when temp doc can not be created
1794 // the document is a new embedded object so it must be marked as modified
1795 uno::Reference< util::XCloseable > xDocument = CreateTempDocFromLink_Impl();
1796 uno::Reference< util::XModifiable > xModif( m_xDocHolder->GetComponent(), uno::UNO_QUERY_THROW );
1799 xModif->setModified( true );
1801 catch( const uno::Exception& )
1804 m_xDocHolder->SetComponent( xDocument, m_bReadOnly );
1805 SAL_WARN_IF( !m_xDocHolder->GetComponent().is(), "embeddedobj.common", "If document can't be created, an exception must be thrown!" );
1807 if ( m_nObjectState == embed::EmbedStates::LOADED )
1809 // the state is changed and can not be switched to loaded state back without saving
1810 m_nObjectState = embed::EmbedStates::RUNNING;
1811 StateChangeNotification_Impl( false, embed::EmbedStates::LOADED, m_nObjectState, aGuard );
1813 else if ( m_nObjectState == embed::EmbedStates::ACTIVE )
1814 m_xDocHolder->Show();
1816 m_bIsLink = false;
1817 m_aLinkFilterName.clear();
1818 m_aLinkURL.clear();
1822 sal_Bool SAL_CALL OCommonEmbeddedObject::isLink()
1824 ::osl::MutexGuard aGuard( m_aMutex );
1825 if ( m_bDisposed )
1826 throw lang::DisposedException(); // TODO
1828 return m_bIsLink;
1832 OUString SAL_CALL OCommonEmbeddedObject::getLinkURL()
1834 ::osl::MutexGuard aGuard( m_aMutex );
1835 if ( m_bDisposed )
1836 throw lang::DisposedException(); // TODO
1838 if ( !m_bIsLink )
1839 throw embed::WrongStateException(
1840 "The object is not a link object!",
1841 static_cast< ::cppu::OWeakObject* >(this) );
1843 return m_aLinkURL;
1846 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */