bump product version to 5.0.4.1
[LibreOffice.git] / embeddedobj / source / commonembedding / persistence.cxx
blob10a4485f4bbfdfdc6ba716c386d7391e5096278d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <commonembobj.hxx>
21 #include <com/sun/star/embed/Aspects.hpp>
22 #include <com/sun/star/document/XStorageBasedDocument.hpp>
23 #include <com/sun/star/embed/EmbedStates.hpp>
24 #include <com/sun/star/embed/EmbedVerbs.hpp>
25 #include <com/sun/star/embed/EntryInitModes.hpp>
26 #include <com/sun/star/embed/XStorage.hpp>
27 #include <com/sun/star/embed/XOptimizedStorage.hpp>
28 #include <com/sun/star/embed/ElementModes.hpp>
29 #include <com/sun/star/embed/EmbedUpdateModes.hpp>
30 #include <com/sun/star/embed/StorageFactory.hpp>
31 #include <com/sun/star/io/TempFile.hpp>
32 #include <com/sun/star/frame/XModel.hpp>
33 #include <com/sun/star/frame/XStorable.hpp>
34 #include <com/sun/star/frame/XLoadable.hpp>
35 #include <com/sun/star/frame/XComponentLoader.hpp>
36 #include <com/sun/star/frame/XModule.hpp>
37 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
38 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
39 #include <com/sun/star/lang/DisposedException.hpp>
40 #include <com/sun/star/util/XModifiable.hpp>
42 #include <com/sun/star/container/XNameAccess.hpp>
43 #include <com/sun/star/container/XChild.hpp>
44 #include <com/sun/star/util/XCloseable.hpp>
45 #include <com/sun/star/beans/XPropertySet.hpp>
46 #include <com/sun/star/beans/IllegalTypeException.hpp>
47 #include <com/sun/star/chart2/XChartDocument.hpp>
49 #include <comphelper/fileformat.h>
50 #include <comphelper/processfactory.hxx>
51 #include <comphelper/storagehelper.hxx>
52 #include <comphelper/mimeconfighelper.hxx>
53 #include <comphelper/namedvaluecollection.hxx>
55 #include <tools/diagnose_ex.h>
56 #include "persistence.hxx"
58 using namespace ::com::sun::star;
62 uno::Sequence< beans::PropertyValue > GetValuableArgs_Impl( const uno::Sequence< beans::PropertyValue >& aMedDescr,
63 bool bCanUseDocumentBaseURL )
65 uno::Sequence< beans::PropertyValue > aResult;
66 sal_Int32 nResLen = 0;
68 for ( sal_Int32 nInd = 0; nInd < aMedDescr.getLength(); nInd++ )
70 if ( aMedDescr[nInd].Name == "ComponentData" || aMedDescr[nInd].Name == "DocumentTitle"
71 || aMedDescr[nInd].Name == "InteractionHandler" || aMedDescr[nInd].Name == "JumpMark"
72 // || aMedDescr[nInd].Name == "Password" // makes no sense for embedded objects
73 || aMedDescr[nInd].Name == "Preview" || aMedDescr[nInd].Name == "ReadOnly"
74 || aMedDescr[nInd].Name == "StartPresentation" || aMedDescr[nInd].Name == "RepairPackage"
75 || aMedDescr[nInd].Name == "StatusIndicator" || aMedDescr[nInd].Name == "ViewData"
76 || aMedDescr[nInd].Name == "ViewId" || aMedDescr[nInd].Name == "MacroExecutionMode"
77 || aMedDescr[nInd].Name == "UpdateDocMode"
78 || (aMedDescr[nInd].Name == "DocumentBaseURL" && bCanUseDocumentBaseURL) )
80 aResult.realloc( ++nResLen );
81 aResult[nResLen-1] = aMedDescr[nInd];
85 return aResult;
89 uno::Sequence< beans::PropertyValue > addAsTemplate( const uno::Sequence< beans::PropertyValue >& aOrig )
91 bool bAsTemplateSet = false;
92 sal_Int32 nLength = aOrig.getLength();
93 uno::Sequence< beans::PropertyValue > aResult( nLength );
95 for ( sal_Int32 nInd = 0; nInd < nLength; nInd++ )
97 aResult[nInd].Name = aOrig[nInd].Name;
98 if ( aResult[nInd].Name == "AsTemplate" )
100 aResult[nInd].Value <<= sal_True;
101 bAsTemplateSet = true;
103 else
104 aResult[nInd].Value = aOrig[nInd].Value;
107 if ( !bAsTemplateSet )
109 aResult.realloc( nLength + 1 );
110 aResult[nLength].Name = "AsTemplate";
111 aResult[nLength].Value <<= sal_True;
114 return aResult;
118 uno::Reference< io::XInputStream > createTempInpStreamFromStor(
119 const uno::Reference< embed::XStorage >& xStorage,
120 const uno::Reference< uno::XComponentContext >& xContext )
122 SAL_WARN_IF( !xStorage.is(), "embeddedobj.common", "The storage can not be empty!" );
124 uno::Reference< io::XInputStream > xResult;
126 uno::Reference < io::XStream > xTempStream( io::TempFile::create(xContext), uno::UNO_QUERY_THROW );
128 uno::Reference < lang::XSingleServiceFactory > xStorageFactory( embed::StorageFactory::create(xContext) );
130 uno::Sequence< uno::Any > aArgs( 2 );
131 aArgs[0] <<= xTempStream;
132 aArgs[1] <<= embed::ElementModes::READWRITE;
133 uno::Reference< embed::XStorage > xTempStorage( xStorageFactory->createInstanceWithArguments( aArgs ),
134 uno::UNO_QUERY );
135 if ( !xTempStorage.is() )
136 throw uno::RuntimeException(); // TODO:
140 xStorage->copyToStorage( xTempStorage );
141 } catch( const uno::Exception& e )
143 throw embed::StorageWrappedTargetException(
144 "Can't copy storage!",
145 uno::Reference< uno::XInterface >(),
146 uno::makeAny( e ) );
149 try {
150 uno::Reference< lang::XComponent > xComponent( xTempStorage, uno::UNO_QUERY );
151 SAL_WARN_IF( !xComponent.is(), "embeddedobj.common", "Wrong storage implementation!" );
152 if ( xComponent.is() )
153 xComponent->dispose();
155 catch ( const uno::Exception& )
159 try {
160 uno::Reference< io::XOutputStream > xTempOut = xTempStream->getOutputStream();
161 if ( xTempOut.is() )
162 xTempOut->closeOutput();
164 catch ( const uno::Exception& )
168 xResult = xTempStream->getInputStream();
170 return xResult;
175 static void TransferMediaType( const uno::Reference< embed::XStorage >& i_rSource, const uno::Reference< embed::XStorage >& i_rTarget )
179 const uno::Reference< beans::XPropertySet > xSourceProps( i_rSource, uno::UNO_QUERY_THROW );
180 const uno::Reference< beans::XPropertySet > xTargetProps( i_rTarget, uno::UNO_QUERY_THROW );
181 const OUString sMediaTypePropName( "MediaType" );
182 xTargetProps->setPropertyValue( sMediaTypePropName, xSourceProps->getPropertyValue( sMediaTypePropName ) );
184 catch( const uno::Exception& )
186 DBG_UNHANDLED_EXCEPTION();
191 static uno::Reference< util::XCloseable > CreateDocument( const uno::Reference< uno::XComponentContext >& _rxContext,
192 const OUString& _rDocumentServiceName, bool _bEmbeddedScriptSupport, const bool i_bDocumentRecoverySupport )
194 ::comphelper::NamedValueCollection aArguments;
195 aArguments.put( "EmbeddedObject", true );
196 aArguments.put( "EmbeddedScriptSupport", _bEmbeddedScriptSupport );
197 aArguments.put( "DocumentRecoverySupport", i_bDocumentRecoverySupport );
199 uno::Reference< uno::XInterface > xDocument;
202 xDocument = _rxContext->getServiceManager()->createInstanceWithArgumentsAndContext(
203 _rDocumentServiceName, aArguments.getWrappedPropertyValues(), _rxContext );
205 catch( const uno::Exception& )
207 // if an embedded object implementation does not support XInitialization,
208 // the default factory from cppuhelper will throw an
209 // IllegalArgumentException when we try to create the instance with arguments.
210 // Okay, so we fall back to creating the instance without any arguments.
211 OSL_FAIL("Consider implementing interface XInitialization to avoid duplicate construction");
212 xDocument = _rxContext->getServiceManager()->createInstanceWithContext( _rDocumentServiceName, _rxContext );
215 SAL_WARN_IF(!xDocument.is(), "embeddedobj.common", "Service " << _rDocumentServiceName << " is not available?");
216 return uno::Reference< util::XCloseable >( xDocument, uno::UNO_QUERY );
220 static void SetDocToEmbedded( const uno::Reference< frame::XModel >& rDocument, const OUString& aModuleName )
222 if (rDocument.is())
224 uno::Sequence< beans::PropertyValue > aSeq( 1 );
225 aSeq[0].Name = "SetEmbedded";
226 aSeq[0].Value <<= sal_True;
227 rDocument->attachResource( OUString(), aSeq );
229 if ( !aModuleName.isEmpty() )
233 uno::Reference< frame::XModule > xModule( rDocument, uno::UNO_QUERY_THROW );
234 xModule->setIdentifier( aModuleName );
236 catch( const uno::Exception& )
243 void OCommonEmbeddedObject::SwitchOwnPersistence( const uno::Reference< embed::XStorage >& xNewParentStorage,
244 const uno::Reference< embed::XStorage >& xNewObjectStorage,
245 const OUString& aNewName )
247 if ( xNewParentStorage == m_xParentStorage && aNewName.equals( m_aEntryName ) )
249 SAL_WARN_IF( xNewObjectStorage != m_xObjectStorage, "embeddedobj.common", "The storage must be the same!" );
250 return;
253 uno::Reference< lang::XComponent > xComponent( m_xObjectStorage, uno::UNO_QUERY );
254 OSL_ENSURE( !m_xObjectStorage.is() || xComponent.is(), "Wrong storage implementation!" );
256 m_xObjectStorage = xNewObjectStorage;
257 m_xParentStorage = xNewParentStorage;
258 m_aEntryName = aNewName;
260 // the linked document should not be switched
261 if ( !m_bIsLink )
263 uno::Reference< document::XStorageBasedDocument > xDoc( m_pDocHolder->GetComponent(), uno::UNO_QUERY );
264 if ( xDoc.is() )
265 SwitchDocToStorage_Impl( xDoc, m_xObjectStorage );
268 try {
269 if ( xComponent.is() )
270 xComponent->dispose();
272 catch ( const uno::Exception& )
278 void OCommonEmbeddedObject::SwitchOwnPersistence( const uno::Reference< embed::XStorage >& xNewParentStorage,
279 const OUString& aNewName )
281 if ( xNewParentStorage == m_xParentStorage && aNewName.equals( m_aEntryName ) )
282 return;
284 sal_Int32 nStorageMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
286 uno::Reference< embed::XStorage > xNewOwnStorage = xNewParentStorage->openStorageElement( aNewName, nStorageMode );
287 SAL_WARN_IF( !xNewOwnStorage.is(), "embeddedobj.common", "The method can not return empty reference!" );
289 SwitchOwnPersistence( xNewParentStorage, xNewOwnStorage, aNewName );
293 void OCommonEmbeddedObject::EmbedAndReparentDoc_Impl( const uno::Reference< util::XCloseable >& i_rxDocument ) const
295 SetDocToEmbedded( uno::Reference< frame::XModel >( i_rxDocument, uno::UNO_QUERY ), m_aModuleName );
299 uno::Reference < container::XChild > xChild( i_rxDocument, uno::UNO_QUERY );
300 if ( xChild.is() )
301 xChild->setParent( m_xParent );
303 catch( const lang::NoSupportException & )
305 SAL_WARN( "embeddedobj.common", "OCommonEmbeddedObject::EmbedAndReparentDoc: cannot set parent at document!" );
310 uno::Reference< util::XCloseable > OCommonEmbeddedObject::InitNewDocument_Impl()
312 uno::Reference< util::XCloseable > xDocument( CreateDocument( m_xContext, GetDocumentServiceName(),
313 m_bEmbeddedScriptSupport, m_bDocumentRecoverySupport ) );
315 uno::Reference< frame::XModel > xModel( xDocument, uno::UNO_QUERY );
316 uno::Reference< frame::XLoadable > xLoadable( xModel, uno::UNO_QUERY );
317 if ( !xLoadable.is() )
318 throw uno::RuntimeException();
322 // set the document mode to embedded as the first action on document!!!
323 EmbedAndReparentDoc_Impl( xDocument );
325 // if we have a storage to recover the document from, do not use initNew, but instead load from that storage
326 bool bInitNew = true;
327 if ( m_xRecoveryStorage.is() )
329 uno::Reference< document::XStorageBasedDocument > xDoc( xLoadable, uno::UNO_QUERY );
330 SAL_WARN_IF( !xDoc.is(), "embeddedobj.common", "OCommonEmbeddedObject::InitNewDocument_Impl: cannot recover from a storage when the document is not storage based!" );
331 if ( xDoc.is() )
333 ::comphelper::NamedValueCollection aLoadArgs;
334 FillDefaultLoadArgs_Impl( m_xRecoveryStorage, aLoadArgs );
336 xDoc->loadFromStorage( m_xRecoveryStorage, aLoadArgs.getPropertyValues() );
337 SwitchDocToStorage_Impl( xDoc, m_xObjectStorage );
338 bInitNew = false;
342 if ( bInitNew )
344 // init document as a new
345 xLoadable->initNew();
347 xModel->attachResource( xModel->getURL(), m_aDocMediaDescriptor );
349 catch( const uno::Exception& )
351 uno::Reference< util::XCloseable > xCloseable( xDocument, uno::UNO_QUERY );
352 if ( xCloseable.is() )
356 xCloseable->close( sal_True );
358 catch( const uno::Exception& )
363 throw; // TODO
366 return xDocument;
370 uno::Reference< util::XCloseable > OCommonEmbeddedObject::LoadLink_Impl()
372 uno::Reference< util::XCloseable > xDocument( CreateDocument( m_xContext, GetDocumentServiceName(),
373 m_bEmbeddedScriptSupport, m_bDocumentRecoverySupport ) );
375 uno::Reference< frame::XLoadable > xLoadable( xDocument, uno::UNO_QUERY );
376 if ( !xLoadable.is() )
377 throw uno::RuntimeException();
379 sal_Int32 nLen = 2;
380 uno::Sequence< beans::PropertyValue > aArgs( nLen );
381 aArgs[0].Name = "URL";
382 aArgs[0].Value <<= m_aLinkURL;
383 aArgs[1].Name = "FilterName";
384 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 uno::Sequence< beans::PropertyValue > aProps = xModel->getArgs();
412 for ( sal_Int32 nInd = 0; nInd < aProps.getLength(); nInd++ )
413 if ( aProps[nInd].Name == "Password" && ( aProps[nInd].Value >>= m_aLinkPassword ) )
415 m_bLinkHasPassword = true;
416 break;
420 catch( const uno::Exception& )
422 uno::Reference< util::XCloseable > xCloseable( xDocument, uno::UNO_QUERY );
423 if ( xCloseable.is() )
427 xCloseable->close( sal_True );
429 catch( const uno::Exception& )
434 throw; // TODO
437 return xDocument;
442 OUString OCommonEmbeddedObject::GetFilterName( sal_Int32 nVersion ) const
444 OUString aFilterName = GetPresetFilterName();
445 if ( aFilterName.isEmpty() )
447 try {
448 ::comphelper::MimeConfigurationHelper aHelper( m_xContext );
449 aFilterName = aHelper.GetDefaultFilterFromServiceName( GetDocumentServiceName(), nVersion );
451 // If no filter is found, fall back to the FileFormatVersion=6200 filter, Base only has that.
452 if (aFilterName.isEmpty() && nVersion == SOFFICE_FILEFORMAT_CURRENT)
453 aFilterName = aHelper.GetDefaultFilterFromServiceName(GetDocumentServiceName(), SOFFICE_FILEFORMAT_60);
454 } catch( const uno::Exception& )
458 return aFilterName;
462 void OCommonEmbeddedObject::FillDefaultLoadArgs_Impl( const uno::Reference< embed::XStorage >& i_rxStorage,
463 ::comphelper::NamedValueCollection& o_rLoadArgs ) const
465 o_rLoadArgs.put( "DocumentBaseURL", GetBaseURL_Impl() );
466 o_rLoadArgs.put( "HierarchicalDocumentName", m_aEntryName );
467 o_rLoadArgs.put( "ReadOnly", m_bReadOnly );
469 OUString aFilterName = GetFilterName( ::comphelper::OStorageHelper::GetXStorageFormat( i_rxStorage ) );
470 SAL_WARN_IF( aFilterName.isEmpty(), "embeddedobj.common", "OCommonEmbeddedObject::FillDefaultLoadArgs_Impl: Wrong document service name!" );
471 if ( aFilterName.isEmpty() )
472 throw io::IOException(); // TODO: error message/code
474 o_rLoadArgs.put( "FilterName", aFilterName );
478 uno::Reference< util::XCloseable > OCommonEmbeddedObject::LoadDocumentFromStorage_Impl()
480 ENSURE_OR_THROW( m_xObjectStorage.is(), "no object storage" );
482 const uno::Reference< embed::XStorage > xSourceStorage( m_xRecoveryStorage.is() ? m_xRecoveryStorage : m_xObjectStorage );
484 uno::Reference< util::XCloseable > xDocument( CreateDocument( m_xContext, GetDocumentServiceName(),
485 m_bEmbeddedScriptSupport, m_bDocumentRecoverySupport ) );
487 //#i103460# ODF: take the size given from the parent frame as default
488 uno::Reference< chart2::XChartDocument > xChart( xDocument, uno::UNO_QUERY );
489 if( xChart.is() )
491 uno::Reference< embed::XVisualObject > xChartVisualObject( xChart, uno::UNO_QUERY );
492 if( xChartVisualObject.is() )
493 xChartVisualObject->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT, m_aDefaultSizeForChart_In_100TH_MM );
496 uno::Reference< frame::XLoadable > xLoadable( xDocument, uno::UNO_QUERY );
497 uno::Reference< document::XStorageBasedDocument > xDoc( xDocument, uno::UNO_QUERY );
498 if ( !xDoc.is() && !xLoadable.is() ) ///BUG: This should be || instead of && ?
499 throw uno::RuntimeException();
501 ::comphelper::NamedValueCollection aLoadArgs;
502 FillDefaultLoadArgs_Impl( xSourceStorage, aLoadArgs );
504 uno::Reference< io::XInputStream > xTempInpStream;
505 if ( !xDoc.is() )
507 xTempInpStream = createTempInpStreamFromStor( xSourceStorage, m_xContext );
508 if ( !xTempInpStream.is() )
509 throw uno::RuntimeException();
511 OUString aTempFileURL;
514 // no need to let the file stay after the stream is removed since the embedded document
515 // can not be stored directly
516 uno::Reference< beans::XPropertySet > xTempStreamProps( xTempInpStream, uno::UNO_QUERY_THROW );
517 xTempStreamProps->getPropertyValue("Uri") >>= aTempFileURL;
519 catch( const uno::Exception& )
523 SAL_WARN_IF( aTempFileURL.isEmpty(), "embeddedobj.common", "Coudn't retrieve temporary file URL!" );
525 aLoadArgs.put( "URL", aTempFileURL );
526 aLoadArgs.put( "InputStream", xTempInpStream );
530 aLoadArgs.merge( m_aDocMediaDescriptor, true );
534 // set the document mode to embedded as the first step!!!
535 EmbedAndReparentDoc_Impl( xDocument );
537 if ( xDoc.is() )
539 xDoc->loadFromStorage( xSourceStorage, aLoadArgs.getPropertyValues() );
540 if ( xSourceStorage != m_xObjectStorage )
541 SwitchDocToStorage_Impl( xDoc, m_xObjectStorage );
543 else
544 xLoadable->load( aLoadArgs.getPropertyValues() );
546 catch( const uno::Exception& )
548 uno::Reference< util::XCloseable > xCloseable( xDocument, uno::UNO_QUERY );
549 if ( xCloseable.is() )
553 xCloseable->close( sal_True );
555 catch( const uno::Exception& )
557 DBG_UNHANDLED_EXCEPTION();
561 throw; // TODO
564 return xDocument;
568 uno::Reference< io::XInputStream > OCommonEmbeddedObject::StoreDocumentToTempStream_Impl(
569 sal_Int32 nStorageFormat,
570 const OUString& aBaseURL,
571 const OUString& aHierarchName )
573 uno::Reference < io::XOutputStream > xTempOut(
574 io::TempFile::create(m_xContext),
575 uno::UNO_QUERY_THROW );
576 uno::Reference< io::XInputStream > aResult( xTempOut, uno::UNO_QUERY );
578 if ( !aResult.is() )
579 throw uno::RuntimeException(); // TODO:
581 uno::Reference< frame::XStorable > xStorable;
583 osl::MutexGuard aGuard( m_aMutex );
584 if ( m_pDocHolder )
585 xStorable = uno::Reference< frame::XStorable > ( m_pDocHolder->GetComponent(), uno::UNO_QUERY );
588 if( !xStorable.is() )
589 throw uno::RuntimeException(); // TODO:
591 OUString aFilterName = GetFilterName( nStorageFormat );
593 SAL_WARN_IF( aFilterName.isEmpty(), "embeddedobj.common", "Wrong document service name!" );
594 if ( aFilterName.isEmpty() )
595 throw io::IOException(); // TODO:
597 uno::Sequence< beans::PropertyValue > aArgs( 4 );
598 aArgs[0].Name = "FilterName";
599 aArgs[0].Value <<= aFilterName;
600 aArgs[1].Name = "OutputStream";
601 aArgs[1].Value <<= xTempOut;
602 aArgs[2].Name = "DocumentBaseURL";
603 aArgs[2].Value <<= aBaseURL;
604 aArgs[3].Name = "HierarchicalDocumentName";
605 aArgs[3].Value <<= aHierarchName;
607 xStorable->storeToURL( OUString( "private:stream" ), aArgs );
610 xTempOut->closeOutput();
612 catch( const uno::Exception& )
614 SAL_WARN( "embeddedobj.common", "Looks like stream was closed already" );
617 return aResult;
621 void OCommonEmbeddedObject::SaveObject_Impl()
623 if ( m_xClientSite.is() )
627 // check whether the component is modified,
628 // if not there is no need for storing
629 uno::Reference< util::XModifiable > xModifiable( m_pDocHolder->GetComponent(), uno::UNO_QUERY );
630 if ( xModifiable.is() && !xModifiable->isModified() )
631 return;
633 catch( const uno::Exception& )
636 try {
637 m_xClientSite->saveObject();
639 catch( const uno::Exception& )
641 SAL_WARN( "embeddedobj.common", "The object was not stored!" );
647 OUString OCommonEmbeddedObject::GetBaseURL_Impl() const
649 OUString aBaseURL;
650 sal_Int32 nInd = 0;
652 if ( m_xClientSite.is() )
656 uno::Reference< frame::XModel > xParentModel( m_xClientSite->getComponent(), uno::UNO_QUERY_THROW );
657 uno::Sequence< beans::PropertyValue > aModelProps = xParentModel->getArgs();
658 for ( nInd = 0; nInd < aModelProps.getLength(); nInd++ )
659 if ( aModelProps[nInd].Name == "DocumentBaseURL" )
661 aModelProps[nInd].Value >>= aBaseURL;
662 break;
667 catch( const uno::Exception& )
671 if ( aBaseURL.isEmpty() )
673 for ( nInd = 0; nInd < m_aDocMediaDescriptor.getLength(); nInd++ )
674 if ( m_aDocMediaDescriptor[nInd].Name == "DocumentBaseURL" )
676 m_aDocMediaDescriptor[nInd].Value >>= aBaseURL;
677 break;
681 if ( aBaseURL.isEmpty() )
682 aBaseURL = m_aDefaultParentBaseURL;
684 return aBaseURL;
688 OUString OCommonEmbeddedObject::GetBaseURLFrom_Impl(
689 const uno::Sequence< beans::PropertyValue >& lArguments,
690 const uno::Sequence< beans::PropertyValue >& lObjArgs )
692 OUString aBaseURL;
693 sal_Int32 nInd = 0;
695 for ( nInd = 0; nInd < lArguments.getLength(); nInd++ )
696 if ( lArguments[nInd].Name == "DocumentBaseURL" )
698 lArguments[nInd].Value >>= aBaseURL;
699 break;
702 if ( aBaseURL.isEmpty() )
704 for ( nInd = 0; nInd < lObjArgs.getLength(); nInd++ )
705 if ( lObjArgs[nInd].Name == "DefaultParentBaseURL" )
707 lObjArgs[nInd].Value >>= aBaseURL;
708 break;
712 return aBaseURL;
717 void OCommonEmbeddedObject::SwitchDocToStorage_Impl( const uno::Reference< document::XStorageBasedDocument >& xDoc, const uno::Reference< embed::XStorage >& xStorage )
719 xDoc->switchToStorage( xStorage );
721 uno::Reference< util::XModifiable > xModif( xDoc, uno::UNO_QUERY );
722 if ( xModif.is() )
723 xModif->setModified( sal_False );
725 if ( m_xRecoveryStorage.is() )
726 m_xRecoveryStorage.clear();
729 namespace {
731 OUString getStringPropertyValue( const uno::Sequence<beans::PropertyValue>& rProps, const OUString& rName )
733 OUString aStr;
735 for (sal_Int32 i = 0; i < rProps.getLength(); ++i)
737 if (rProps[i].Name == rName)
739 rProps[i].Value >>= aStr;
740 break;
744 return aStr;
749 void OCommonEmbeddedObject::StoreDocToStorage_Impl(
750 const uno::Reference<embed::XStorage>& xStorage,
751 const uno::Sequence<beans::PropertyValue>& rMediaArgs,
752 const uno::Sequence<beans::PropertyValue>& rObjArgs,
753 sal_Int32 nStorageFormat,
754 const OUString& aHierarchName,
755 bool bAttachToTheStorage )
757 SAL_WARN_IF( !xStorage.is(), "embeddedobj.common", "No storage is provided for storing!" );
759 if ( !xStorage.is() )
760 throw uno::RuntimeException(); // TODO:
762 uno::Reference< document::XStorageBasedDocument > xDoc;
764 osl::MutexGuard aGuard( m_aMutex );
765 if ( m_pDocHolder )
766 xDoc = uno::Reference< document::XStorageBasedDocument >( m_pDocHolder->GetComponent(), uno::UNO_QUERY );
769 OUString aBaseURL = GetBaseURLFrom_Impl(rMediaArgs, rObjArgs);
771 if ( xDoc.is() )
773 OUString aFilterName = GetFilterName( nStorageFormat );
775 // No filter found? Try the older format, e.g. Base has only that.
776 if (aFilterName.isEmpty() && nStorageFormat == SOFFICE_FILEFORMAT_CURRENT)
777 aFilterName = GetFilterName( SOFFICE_FILEFORMAT_60 );
779 SAL_WARN_IF( aFilterName.isEmpty(), "embeddedobj.common", "Wrong document service name!" );
780 if ( aFilterName.isEmpty() )
781 throw io::IOException(); // TODO:
783 uno::Sequence<beans::PropertyValue> aArgs(5);
784 aArgs[0].Name = "FilterName";
785 aArgs[0].Value <<= aFilterName;
786 aArgs[1].Name = "HierarchicalDocumentName";
787 aArgs[1].Value <<= aHierarchName;
788 aArgs[2].Name = "DocumentBaseURL";
789 aArgs[2].Value <<= aBaseURL;
790 aArgs[3].Name = "SourceShellID";
791 aArgs[3].Value <<= getStringPropertyValue(rObjArgs, "SourceShellID");
792 aArgs[4].Name = "DestinationShellID";
793 aArgs[4].Value <<= getStringPropertyValue(rObjArgs, "DestinationShellID");
795 xDoc->storeToStorage( xStorage, aArgs );
796 if ( bAttachToTheStorage )
797 SwitchDocToStorage_Impl( xDoc, xStorage );
799 else
801 // store document to temporary stream based on temporary file
802 uno::Reference < io::XInputStream > xTempIn = StoreDocumentToTempStream_Impl( nStorageFormat, aBaseURL, aHierarchName );
804 SAL_WARN_IF( !xTempIn.is(), "embeddedobj.common", "The stream reference can not be empty!" );
806 // open storage based on document temporary file for reading
807 uno::Reference < lang::XSingleServiceFactory > xStorageFactory = embed::StorageFactory::create(m_xContext);
809 uno::Sequence< uno::Any > aArgs(1);
810 aArgs[0] <<= xTempIn;
811 uno::Reference< embed::XStorage > xTempStorage( xStorageFactory->createInstanceWithArguments( aArgs ),
812 uno::UNO_QUERY );
813 if ( !xTempStorage.is() )
814 throw uno::RuntimeException(); // TODO:
816 // object storage must be committed automatically
817 xTempStorage->copyToStorage( xStorage );
822 uno::Reference< util::XCloseable > OCommonEmbeddedObject::CreateDocFromMediaDescr_Impl(
823 const uno::Sequence< beans::PropertyValue >& aMedDescr )
825 uno::Reference< util::XCloseable > xDocument( CreateDocument( m_xContext, GetDocumentServiceName(),
826 m_bEmbeddedScriptSupport, m_bDocumentRecoverySupport ) );
828 uno::Reference< frame::XLoadable > xLoadable( xDocument, uno::UNO_QUERY );
829 if ( !xLoadable.is() )
830 throw uno::RuntimeException();
834 // set the document mode to embedded as the first action on the document!!!
835 EmbedAndReparentDoc_Impl( xDocument );
837 xLoadable->load( addAsTemplate( aMedDescr ) );
839 catch( const uno::Exception& )
841 uno::Reference< util::XCloseable > xCloseable( xDocument, uno::UNO_QUERY );
842 if ( xCloseable.is() )
846 xCloseable->close( sal_True );
848 catch( const uno::Exception& )
853 throw; // TODO
856 return xDocument;
860 uno::Reference< util::XCloseable > OCommonEmbeddedObject::CreateTempDocFromLink_Impl()
862 uno::Reference< util::XCloseable > xResult;
864 SAL_WARN_IF( !m_bIsLink, "embeddedobj.common", "The object is not a linked one!" );
866 uno::Sequence< beans::PropertyValue > aTempMediaDescr;
868 sal_Int32 nStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
869 try {
870 nStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage );
872 catch ( const beans::IllegalTypeException& )
874 // the container just has an unknown type, use current file format
876 catch ( const uno::Exception& )
878 SAL_WARN( "embeddedobj.common", "Can not retrieve storage media type!" );
881 if ( m_pDocHolder->GetComponent().is() )
883 aTempMediaDescr.realloc( 4 );
885 // TODO/LATER: may be private:stream should be used as target URL
886 OUString aTempFileURL;
887 uno::Reference< io::XInputStream > xTempStream = StoreDocumentToTempStream_Impl( SOFFICE_FILEFORMAT_CURRENT,
888 OUString(),
889 OUString() );
892 // no need to let the file stay after the stream is removed since the embedded document
893 // can not be stored directly
894 uno::Reference< beans::XPropertySet > xTempStreamProps( xTempStream, uno::UNO_QUERY_THROW );
895 xTempStreamProps->getPropertyValue("Uri") >>= aTempFileURL;
897 catch( const uno::Exception& )
901 SAL_WARN_IF( aTempFileURL.isEmpty(), "embeddedobj.common", "Couldn't retrieve temporary file URL!" );
903 aTempMediaDescr[0].Name = "URL";
904 aTempMediaDescr[0].Value <<= aTempFileURL;
905 aTempMediaDescr[1].Name = "InputStream";
906 aTempMediaDescr[1].Value <<= xTempStream;
907 aTempMediaDescr[2].Name = "FilterName";
908 aTempMediaDescr[2].Value <<= GetFilterName( nStorageFormat );
909 aTempMediaDescr[3].Name = "AsTemplate";
910 aTempMediaDescr[3].Value <<= sal_True;
912 else
914 aTempMediaDescr.realloc( 2 );
915 aTempMediaDescr[0].Name = "URL";
916 aTempMediaDescr[0].Value <<= m_aLinkURL;
917 aTempMediaDescr[1].Name = "FilterName";
918 aTempMediaDescr[1].Value <<= m_aLinkFilterName;
921 xResult = CreateDocFromMediaDescr_Impl( aTempMediaDescr );
923 return xResult;
927 void SAL_CALL OCommonEmbeddedObject::setPersistentEntry(
928 const uno::Reference< embed::XStorage >& xStorage,
929 const OUString& sEntName,
930 sal_Int32 nEntryConnectionMode,
931 const uno::Sequence< beans::PropertyValue >& lArguments,
932 const uno::Sequence< beans::PropertyValue >& lObjArgs )
933 throw ( lang::IllegalArgumentException,
934 embed::WrongStateException,
935 io::IOException,
936 uno::Exception,
937 uno::RuntimeException, std::exception )
939 // the type of the object must be already set
940 // a kind of typedetection should be done in the factory
942 ::osl::MutexGuard aGuard( m_aMutex );
943 if ( m_bDisposed )
944 throw lang::DisposedException(); // TODO
946 if ( !xStorage.is() )
947 throw lang::IllegalArgumentException( "No parent storage is provided!",
948 static_cast< ::cppu::OWeakObject* >(this),
949 1 );
951 if ( sEntName.isEmpty() )
952 throw lang::IllegalArgumentException( "Empty element name is provided!",
953 static_cast< ::cppu::OWeakObject* >(this),
954 2 );
956 // May be LOADED should be forbidden here ???
957 if ( ( m_nObjectState != -1 || nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
958 && ( m_nObjectState == -1 || nEntryConnectionMode != embed::EntryInitModes::NO_INIT ) )
960 // if the object is not loaded
961 // it can not get persistent representation without initialization
963 // if the object is loaded
964 // it can switch persistent representation only without initialization
966 throw embed::WrongStateException(
967 "Can't change persistent representation of activated object!",
968 static_cast< ::cppu::OWeakObject* >(this) );
971 if ( m_bWaitSaveCompleted )
973 if ( nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
975 // saveCompleted is expected, handle it accordingly
976 if ( m_xNewParentStorage == xStorage && m_aNewEntryName.equals( sEntName ) )
978 saveCompleted( sal_True );
979 return;
982 // if a completely different entry is provided, switch first back to the old persistence in saveCompleted
983 // and then switch to the target persistence
984 bool bSwitchFurther = ( m_xParentStorage != xStorage || !m_aEntryName.equals( sEntName ) );
985 saveCompleted( sal_False );
986 if ( !bSwitchFurther )
987 return;
989 else
990 throw embed::WrongStateException(
991 "The object waits for saveCompleted() call!",
992 static_cast< ::cppu::OWeakObject* >(this) );
995 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
996 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
997 // OSL_ENSURE( !m_bIsLink, "This method implementation must not be used for links!\n" );
998 if ( m_bIsLink )
1000 m_aEntryName = sEntName;
1001 return;
1004 uno::Reference< container::XNameAccess > xNameAccess( xStorage, uno::UNO_QUERY );
1005 if ( !xNameAccess.is() )
1006 throw uno::RuntimeException(); //TODO
1008 // detect entry existence
1009 bool bElExists = xNameAccess->hasByName( sEntName );
1011 m_aDocMediaDescriptor = GetValuableArgs_Impl( lArguments,
1012 nEntryConnectionMode != embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT );
1014 m_bReadOnly = false;
1015 for ( sal_Int32 nInd = 0; nInd < lArguments.getLength(); nInd++ )
1016 if ( lArguments[nInd].Name == "ReadOnly" )
1017 lArguments[nInd].Value >>= m_bReadOnly;
1019 // TODO: use lObjArgs for StoreVisualReplacement
1020 for ( sal_Int32 nObjInd = 0; nObjInd < lObjArgs.getLength(); nObjInd++ )
1021 if ( lObjArgs[nObjInd].Name == "OutplaceDispatchInterceptor" )
1023 uno::Reference< frame::XDispatchProviderInterceptor > xDispatchInterceptor;
1024 if ( lObjArgs[nObjInd].Value >>= xDispatchInterceptor )
1025 m_pDocHolder->SetOutplaceDispatchInterceptor( xDispatchInterceptor );
1027 else if ( lObjArgs[nObjInd].Name == "DefaultParentBaseURL" )
1029 lObjArgs[nObjInd].Value >>= m_aDefaultParentBaseURL;
1031 else if ( lObjArgs[nObjInd].Name == "Parent" )
1033 lObjArgs[nObjInd].Value >>= m_xParent;
1035 else if ( lObjArgs[nObjInd].Name == "IndividualMiscStatus" )
1037 sal_Int64 nMiscStatus=0;
1038 lObjArgs[nObjInd].Value >>= nMiscStatus;
1039 m_nMiscStatus |= nMiscStatus;
1041 else if ( lObjArgs[nObjInd].Name == "CloneFrom" )
1043 uno::Reference < embed::XEmbeddedObject > xObj;
1044 lObjArgs[nObjInd].Value >>= xObj;
1045 if ( xObj.is() )
1047 m_bHasClonedSize = true;
1048 m_aClonedSize = xObj->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT );
1049 m_nClonedMapUnit = xObj->getMapUnit( embed::Aspects::MSOLE_CONTENT );
1052 else if ( lObjArgs[nObjInd].Name == "OutplaceFrameProperties" )
1054 uno::Sequence< uno::Any > aOutFrameProps;
1055 uno::Sequence< beans::NamedValue > aOutFramePropsTyped;
1056 if ( lObjArgs[nObjInd].Value >>= aOutFrameProps )
1058 m_pDocHolder->SetOutplaceFrameProperties( aOutFrameProps );
1060 else if ( lObjArgs[nObjInd].Value >>= aOutFramePropsTyped )
1062 aOutFrameProps.realloc( aOutFramePropsTyped.getLength() );
1063 uno::Any* pProp = aOutFrameProps.getArray();
1064 for ( const beans::NamedValue* pTypedProp = aOutFramePropsTyped.getConstArray();
1065 pTypedProp != aOutFramePropsTyped.getConstArray() + aOutFramePropsTyped.getLength();
1066 ++pTypedProp, ++pProp
1069 *pProp <<= *pTypedProp;
1071 m_pDocHolder->SetOutplaceFrameProperties( aOutFrameProps );
1073 else
1074 SAL_WARN( "embeddedobj.common", "OCommonEmbeddedObject::setPersistentEntry: illegal type for argument 'OutplaceFrameProperties'!" );
1076 else if ( lObjArgs[nObjInd].Name == "ModuleName" )
1078 lObjArgs[nObjInd].Value >>= m_aModuleName;
1080 else if ( lObjArgs[nObjInd].Name == "EmbeddedScriptSupport" )
1082 OSL_VERIFY( lObjArgs[nObjInd].Value >>= m_bEmbeddedScriptSupport );
1084 else if ( lObjArgs[nObjInd].Name == "DocumentRecoverySupport" )
1086 OSL_VERIFY( lObjArgs[nObjInd].Value >>= m_bDocumentRecoverySupport );
1088 else if ( lObjArgs[nObjInd].Name == "RecoveryStorage" )
1090 OSL_VERIFY( lObjArgs[nObjInd].Value >>= m_xRecoveryStorage );
1094 sal_Int32 nStorageMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
1096 SwitchOwnPersistence( xStorage, sEntName );
1098 if ( nEntryConnectionMode == embed::EntryInitModes::DEFAULT_INIT )
1100 if ( bElExists )
1102 // the initialization from existing storage allows to leave object in loaded state
1103 m_nObjectState = embed::EmbedStates::LOADED;
1105 else
1107 m_pDocHolder->SetComponent( InitNewDocument_Impl(), m_bReadOnly );
1108 if ( !m_pDocHolder->GetComponent().is() )
1109 throw io::IOException(); // TODO: can not create document
1111 m_nObjectState = embed::EmbedStates::RUNNING;
1114 else
1116 if ( ( nStorageMode & embed::ElementModes::READWRITE ) != embed::ElementModes::READWRITE )
1117 throw io::IOException();
1119 if ( nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
1121 // the document just already changed its storage to store to
1122 // the links to OOo documents for now ignore this call
1123 // TODO: OOo links will have persistence so it will be switched here
1125 else if ( nEntryConnectionMode == embed::EntryInitModes::TRUNCATE_INIT )
1127 if ( m_xRecoveryStorage.is() )
1128 TransferMediaType( m_xRecoveryStorage, m_xObjectStorage );
1130 // TODO:
1131 m_pDocHolder->SetComponent( InitNewDocument_Impl(), m_bReadOnly );
1133 if ( !m_pDocHolder->GetComponent().is() )
1134 throw io::IOException(); // TODO: can not create document
1136 m_nObjectState = embed::EmbedStates::RUNNING;
1138 else if ( nEntryConnectionMode == embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT )
1140 m_pDocHolder->SetComponent( CreateDocFromMediaDescr_Impl( lArguments ), m_bReadOnly );
1141 m_nObjectState = embed::EmbedStates::RUNNING;
1143 //else if ( nEntryConnectionMode == embed::EntryInitModes::TRANSFERABLE_INIT )
1145 //TODO:
1147 else
1148 throw lang::IllegalArgumentException( "Wrong connection mode is provided!",
1149 static_cast< ::cppu::OWeakObject* >(this),
1150 3 );
1155 void SAL_CALL OCommonEmbeddedObject::storeToEntry( const uno::Reference< embed::XStorage >& xStorage,
1156 const OUString& sEntName,
1157 const uno::Sequence< beans::PropertyValue >& lArguments,
1158 const uno::Sequence< beans::PropertyValue >& lObjArgs )
1159 throw ( lang::IllegalArgumentException,
1160 embed::WrongStateException,
1161 io::IOException,
1162 uno::Exception,
1163 uno::RuntimeException, std::exception )
1165 ::osl::ResettableMutexGuard aGuard( m_aMutex );
1166 if ( m_bDisposed )
1167 throw lang::DisposedException(); // TODO
1169 if ( m_nObjectState == -1 )
1171 // the object is still not loaded
1172 throw embed::WrongStateException( "Can't store object without persistence!",
1173 static_cast< ::cppu::OWeakObject* >(this) );
1176 if ( m_bWaitSaveCompleted )
1177 throw embed::WrongStateException(
1178 "The object waits for saveCompleted() call!",
1179 static_cast< ::cppu::OWeakObject* >(this) );
1181 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1182 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1183 // OSL_ENSURE( !m_bIsLink, "This method implementation must not be used for links!\n" );
1184 if ( m_bIsLink )
1185 return;
1187 OSL_ENSURE( m_xParentStorage.is() && m_xObjectStorage.is(), "The object has no valid persistence!\n" );
1189 sal_Int32 nTargetStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1190 sal_Int32 nOriginalStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1191 try {
1192 nTargetStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( xStorage );
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 target storage media type!" );
1202 if (nTargetStorageFormat == SOFFICE_FILEFORMAT_60)
1204 SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1205 nTargetStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1206 // setting MediaType is done later anyway, no need to do it here
1211 nOriginalStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage );
1213 catch ( const beans::IllegalTypeException& )
1215 // the container just has an unknown type, use current file format
1217 catch ( const uno::Exception& )
1219 SAL_WARN( "embeddedobj.common", "Can not retrieve own storage media type!" );
1222 bool bTryOptimization = false;
1223 for ( sal_Int32 nInd = 0; nInd < lObjArgs.getLength(); nInd++ )
1225 // StoreVisualReplacement and VisualReplacement args have no sense here
1226 if ( lObjArgs[nInd].Name == "CanTryOptimization" )
1227 lObjArgs[nInd].Value >>= bTryOptimization;
1230 bool bSwitchBackToLoaded = false;
1232 // Storing to different format can be done only in running state.
1233 if ( m_nObjectState == embed::EmbedStates::LOADED )
1235 // TODO/LATER: copying is not legal for documents with relative links.
1236 if ( nTargetStorageFormat == nOriginalStorageFormat )
1238 bool bOptimizationWorks = false;
1239 if ( bTryOptimization )
1243 // try to use optimized copying
1244 uno::Reference< embed::XOptimizedStorage > xSource( m_xParentStorage, uno::UNO_QUERY_THROW );
1245 uno::Reference< embed::XOptimizedStorage > xTarget( xStorage, uno::UNO_QUERY_THROW );
1246 xSource->copyElementDirectlyTo( m_aEntryName, xTarget, sEntName );
1247 bOptimizationWorks = true;
1249 catch( const uno::Exception& )
1254 if ( !bOptimizationWorks )
1255 m_xParentStorage->copyElementTo( m_aEntryName, xStorage, sEntName );
1257 else
1259 changeState( embed::EmbedStates::RUNNING );
1260 bSwitchBackToLoaded = true;
1264 if ( m_nObjectState != embed::EmbedStates::LOADED )
1266 uno::Reference< embed::XStorage > xSubStorage =
1267 xStorage->openStorageElement( sEntName, embed::ElementModes::READWRITE );
1269 if ( !xSubStorage.is() )
1270 throw uno::RuntimeException(); //TODO
1272 aGuard.clear();
1273 // TODO/LATER: support hierarchical name for embedded objects in embedded objects
1274 StoreDocToStorage_Impl(
1275 xSubStorage, lArguments, lObjArgs, nTargetStorageFormat, sEntName, false );
1276 aGuard.reset();
1278 if ( bSwitchBackToLoaded )
1279 changeState( embed::EmbedStates::LOADED );
1282 // TODO: should the listener notification be done?
1286 void SAL_CALL OCommonEmbeddedObject::storeAsEntry( const uno::Reference< embed::XStorage >& xStorage,
1287 const OUString& sEntName,
1288 const uno::Sequence< beans::PropertyValue >& lArguments,
1289 const uno::Sequence< beans::PropertyValue >& lObjArgs )
1290 throw ( lang::IllegalArgumentException,
1291 embed::WrongStateException,
1292 io::IOException,
1293 uno::Exception,
1294 uno::RuntimeException, std::exception )
1296 // TODO: use lObjArgs
1298 ::osl::ResettableMutexGuard aGuard( m_aMutex );
1299 if ( m_bDisposed )
1300 throw lang::DisposedException(); // TODO
1302 if ( m_nObjectState == -1 )
1304 // the object is still not loaded
1305 throw embed::WrongStateException( "Can't store object without persistence!",
1306 static_cast< ::cppu::OWeakObject* >(this) );
1309 if ( m_bWaitSaveCompleted )
1310 throw embed::WrongStateException(
1311 "The object waits for saveCompleted() call!",
1312 static_cast< ::cppu::OWeakObject* >(this) );
1314 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1315 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1316 // OSL_ENSURE( !m_bIsLink, "This method implementation must not be used for links!\n" );
1317 if ( m_bIsLink )
1319 m_aNewEntryName = sEntName;
1320 return;
1323 OSL_ENSURE( m_xParentStorage.is() && m_xObjectStorage.is(), "The object has no valid persistence!\n" );
1325 sal_Int32 nTargetStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1326 sal_Int32 nOriginalStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1327 try {
1328 nTargetStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( xStorage );
1330 catch ( const beans::IllegalTypeException& )
1332 // the container just has an unknown type, use current file format
1334 catch ( const uno::Exception& )
1336 SAL_WARN( "embeddedobj.common", "Can not retrieve target storage media type!" );
1338 if (nTargetStorageFormat == SOFFICE_FILEFORMAT_60)
1340 SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1341 nTargetStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1342 // setting MediaType is done later anyway, no need to do it here
1347 nOriginalStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage );
1349 catch ( const beans::IllegalTypeException& )
1351 // the container just has an unknown type, use current file format
1353 catch ( const uno::Exception& )
1355 SAL_WARN( "embeddedobj.common", "Can not retrieve own storage media type!" );
1358 PostEvent_Impl( OUString( "OnSaveAs" ) );
1360 bool bTryOptimization = false;
1361 for ( sal_Int32 nInd = 0; nInd < lObjArgs.getLength(); nInd++ )
1363 // StoreVisualReplacement and VisualReplacement args have no sense here
1364 if ( lObjArgs[nInd].Name == "CanTryOptimization" )
1365 lObjArgs[nInd].Value >>= bTryOptimization;
1368 bool bSwitchBackToLoaded = false;
1370 // Storing to different format can be done only in running state.
1371 if ( m_nObjectState == embed::EmbedStates::LOADED )
1373 // TODO/LATER: copying is not legal for documents with relative links.
1374 if ( nTargetStorageFormat == nOriginalStorageFormat )
1376 bool bOptimizationWorks = false;
1377 if ( bTryOptimization )
1381 // try to use optimized copying
1382 uno::Reference< embed::XOptimizedStorage > xSource( m_xParentStorage, uno::UNO_QUERY_THROW );
1383 uno::Reference< embed::XOptimizedStorage > xTarget( xStorage, uno::UNO_QUERY_THROW );
1384 xSource->copyElementDirectlyTo( m_aEntryName, xTarget, sEntName );
1385 bOptimizationWorks = true;
1387 catch( const uno::Exception& )
1392 if ( !bOptimizationWorks )
1393 m_xParentStorage->copyElementTo( m_aEntryName, xStorage, sEntName );
1395 else
1397 changeState( embed::EmbedStates::RUNNING );
1398 bSwitchBackToLoaded = true;
1402 uno::Reference< embed::XStorage > xSubStorage =
1403 xStorage->openStorageElement( sEntName, embed::ElementModes::READWRITE );
1405 if ( !xSubStorage.is() )
1406 throw uno::RuntimeException(); //TODO
1408 if ( m_nObjectState != embed::EmbedStates::LOADED )
1410 aGuard.clear();
1411 // TODO/LATER: support hierarchical name for embedded objects in embedded objects
1412 StoreDocToStorage_Impl(
1413 xSubStorage, lArguments, lObjArgs, nTargetStorageFormat, sEntName, false );
1414 aGuard.reset();
1416 if ( bSwitchBackToLoaded )
1417 changeState( embed::EmbedStates::LOADED );
1420 m_bWaitSaveCompleted = true;
1421 m_xNewObjectStorage = xSubStorage;
1422 m_xNewParentStorage = xStorage;
1423 m_aNewEntryName = sEntName;
1424 m_aNewDocMediaDescriptor = GetValuableArgs_Impl( lArguments, true );
1426 // TODO: register listeners for storages above, in case thay are disposed
1427 // an exception will be thrown on saveCompleted( true )
1429 // TODO: should the listener notification be done here or in saveCompleted?
1433 void SAL_CALL OCommonEmbeddedObject::saveCompleted( sal_Bool bUseNew )
1434 throw ( embed::WrongStateException,
1435 uno::Exception,
1436 uno::RuntimeException, std::exception )
1438 ::osl::MutexGuard aGuard( m_aMutex );
1439 if ( m_bDisposed )
1440 throw lang::DisposedException(); // TODO
1442 if ( m_nObjectState == -1 )
1444 // the object is still not loaded
1445 throw embed::WrongStateException( "Can't store object without persistence!",
1446 static_cast< ::cppu::OWeakObject* >(this) );
1449 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1450 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1451 // OSL_ENSURE( !m_bIsLink, "This method implementation must not be used for links!\n" );
1452 if ( m_bIsLink )
1454 if ( bUseNew )
1455 m_aEntryName = m_aNewEntryName;
1456 m_aNewEntryName.clear();
1457 return;
1460 // it is allowed to call saveCompleted( false ) for nonstored objects
1461 if ( !m_bWaitSaveCompleted && !bUseNew )
1462 return;
1464 SAL_WARN_IF( !m_bWaitSaveCompleted, "embeddedobj.common", "Unexpected saveCompleted() call!" );
1465 if ( !m_bWaitSaveCompleted )
1466 throw io::IOException(); // TODO: illegal call
1468 OSL_ENSURE( m_xNewObjectStorage.is() && m_xNewParentStorage.is() , "Internal object information is broken!\n" );
1469 if ( !m_xNewObjectStorage.is() || !m_xNewParentStorage.is() )
1470 throw uno::RuntimeException(); // TODO: broken internal information
1472 if ( bUseNew )
1474 SwitchOwnPersistence( m_xNewParentStorage, m_xNewObjectStorage, m_aNewEntryName );
1475 m_aDocMediaDescriptor = m_aNewDocMediaDescriptor;
1477 uno::Reference< util::XModifiable > xModif( m_pDocHolder->GetComponent(), uno::UNO_QUERY );
1478 if ( xModif.is() )
1479 xModif->setModified( sal_False );
1481 PostEvent_Impl( OUString( "OnSaveAsDone" ));
1483 else
1485 try {
1486 uno::Reference< lang::XComponent > xComponent( m_xNewObjectStorage, uno::UNO_QUERY );
1487 SAL_WARN_IF( !xComponent.is(), "embeddedobj.common", "Wrong storage implementation!" );
1488 if ( xComponent.is() )
1489 xComponent->dispose();
1491 catch ( const uno::Exception& )
1496 m_xNewObjectStorage = uno::Reference< embed::XStorage >();
1497 m_xNewParentStorage = uno::Reference< embed::XStorage >();
1498 m_aNewEntryName.clear();
1499 m_aNewDocMediaDescriptor.realloc( 0 );
1500 m_bWaitSaveCompleted = false;
1502 if ( bUseNew )
1504 // TODO: notify listeners
1506 if ( m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE )
1508 // TODO: update visual representation
1514 sal_Bool SAL_CALL OCommonEmbeddedObject::hasEntry()
1515 throw ( embed::WrongStateException,
1516 uno::RuntimeException, std::exception )
1518 ::osl::MutexGuard aGuard( m_aMutex );
1519 if ( m_bDisposed )
1520 throw lang::DisposedException(); // TODO
1522 if ( m_bWaitSaveCompleted )
1523 throw embed::WrongStateException(
1524 "The object waits for saveCompleted() call!",
1525 static_cast< ::cppu::OWeakObject* >(this) );
1527 if ( m_xObjectStorage.is() )
1528 return sal_True;
1530 return sal_False;
1534 OUString SAL_CALL OCommonEmbeddedObject::getEntryName()
1535 throw ( embed::WrongStateException,
1536 uno::RuntimeException, std::exception )
1538 ::osl::MutexGuard aGuard( m_aMutex );
1539 if ( m_bDisposed )
1540 throw lang::DisposedException(); // TODO
1542 if ( m_nObjectState == -1 )
1544 // the object is still not loaded
1545 throw embed::WrongStateException( "The object persistence is not initialized!",
1546 static_cast< ::cppu::OWeakObject* >(this) );
1549 if ( m_bWaitSaveCompleted )
1550 throw embed::WrongStateException(
1551 "The object waits for saveCompleted() call!",
1552 static_cast< ::cppu::OWeakObject* >(this) );
1554 return m_aEntryName;
1558 void SAL_CALL OCommonEmbeddedObject::storeOwn()
1559 throw ( embed::WrongStateException,
1560 io::IOException,
1561 uno::Exception,
1562 uno::RuntimeException, std::exception )
1564 // during switching from Activated to Running and from Running to Loaded states the object will
1565 // ask container to store the object, the container has to make decision
1566 // to do so or not
1568 ::osl::ResettableMutexGuard aGuard( m_aMutex );
1569 if ( m_bDisposed )
1570 throw lang::DisposedException(); // TODO
1572 if ( m_nObjectState == -1 )
1574 // the object is still not loaded
1575 throw embed::WrongStateException( "Can't store object without persistence!",
1576 static_cast< ::cppu::OWeakObject* >(this) );
1579 if ( m_bWaitSaveCompleted )
1580 throw embed::WrongStateException(
1581 "The object waits for saveCompleted() call!",
1582 static_cast< ::cppu::OWeakObject* >(this) );
1584 if ( m_bReadOnly )
1585 throw io::IOException(); // TODO: access denied
1587 // nothing to do, if the object is in loaded state
1588 if ( m_nObjectState == embed::EmbedStates::LOADED )
1589 return;
1591 PostEvent_Impl( OUString( "OnSave" ) );
1593 SAL_WARN_IF( !m_pDocHolder->GetComponent().is(), "embeddedobj.common", "If an object is activated or in running state it must have a document!" );
1594 if ( !m_pDocHolder->GetComponent().is() )
1595 throw uno::RuntimeException();
1597 if ( m_bIsLink )
1599 // TODO: just store the document to it's location
1600 uno::Reference< frame::XStorable > xStorable( m_pDocHolder->GetComponent(), uno::UNO_QUERY );
1601 if ( !xStorable.is() )
1602 throw uno::RuntimeException(); // TODO
1604 // free the main mutex for the storing time
1605 aGuard.clear();
1607 xStorable->store();
1609 aGuard.reset();
1611 else
1613 OSL_ENSURE( m_xParentStorage.is() && m_xObjectStorage.is(), "The object has no valid persistence!\n" );
1615 if ( !m_xObjectStorage.is() )
1616 throw io::IOException(); //TODO: access denied
1618 sal_Int32 nStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1619 try {
1620 nStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage );
1622 catch ( const beans::IllegalTypeException& )
1624 // the container just has an unknown type, use current file format
1626 catch ( const uno::Exception& )
1628 SAL_WARN( "embeddedobj.common", "Can not retrieve storage media type!" );
1630 if (nStorageFormat == SOFFICE_FILEFORMAT_60)
1632 SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1633 nStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1634 // setting MediaType is done later anyway, no need to do it here
1637 aGuard.clear();
1638 uno::Sequence<beans::PropertyValue> aEmpty;
1639 uno::Sequence<beans::PropertyValue> aMediaArgs(1);
1640 aMediaArgs[0].Name = "DocumentBaseURL";
1641 aMediaArgs[0].Value <<= GetBaseURL_Impl();
1642 StoreDocToStorage_Impl( m_xObjectStorage, aMediaArgs, aEmpty, nStorageFormat, m_aEntryName, true );
1643 aGuard.reset();
1646 uno::Reference< util::XModifiable > xModif( m_pDocHolder->GetComponent(), uno::UNO_QUERY );
1647 if ( xModif.is() )
1648 xModif->setModified( sal_False );
1650 PostEvent_Impl( OUString( "OnSaveDone" ) );
1654 sal_Bool SAL_CALL OCommonEmbeddedObject::isReadonly()
1655 throw ( embed::WrongStateException,
1656 uno::RuntimeException, std::exception )
1658 ::osl::MutexGuard aGuard( m_aMutex );
1659 if ( m_bDisposed )
1660 throw lang::DisposedException(); // TODO
1662 if ( m_nObjectState == -1 )
1664 // the object is still not loaded
1665 throw embed::WrongStateException( "The object persistence is not initialized!",
1666 static_cast< ::cppu::OWeakObject* >(this) );
1669 if ( m_bWaitSaveCompleted )
1670 throw embed::WrongStateException(
1671 "The object waits for saveCompleted() call!",
1672 static_cast< ::cppu::OWeakObject* >(this) );
1674 return m_bReadOnly;
1678 void SAL_CALL OCommonEmbeddedObject::reload(
1679 const uno::Sequence< beans::PropertyValue >& lArguments,
1680 const uno::Sequence< beans::PropertyValue >& lObjArgs )
1681 throw ( lang::IllegalArgumentException,
1682 embed::WrongStateException,
1683 io::IOException,
1684 uno::Exception,
1685 uno::RuntimeException, std::exception )
1687 // TODO: use lObjArgs
1688 // for now this method is used only to switch readonly state
1690 ::osl::MutexGuard aGuard( m_aMutex );
1691 if ( m_bDisposed )
1692 throw lang::DisposedException(); // TODO
1694 if ( m_nObjectState == -1 )
1696 // the object is still not loaded
1697 throw embed::WrongStateException( "The object persistence is not initialized!",
1698 static_cast< ::cppu::OWeakObject* >(this) );
1701 if ( m_nObjectState != embed::EmbedStates::LOADED )
1703 // the object is still not loaded
1704 throw embed::WrongStateException(
1705 "The object must be in loaded state to be reloaded!",
1706 static_cast< ::cppu::OWeakObject* >(this) );
1709 if ( m_bWaitSaveCompleted )
1710 throw embed::WrongStateException(
1711 "The object waits for saveCompleted() call!",
1712 static_cast< ::cppu::OWeakObject* >(this) );
1714 if ( m_bIsLink )
1716 // reload of the link
1717 OUString aOldLinkFilter = m_aLinkFilterName;
1719 OUString aNewLinkFilter;
1720 for ( sal_Int32 nInd = 0; nInd < lArguments.getLength(); nInd++ )
1722 if ( lArguments[nInd].Name == "URL" )
1724 // the new URL
1725 lArguments[nInd].Value >>= m_aLinkURL;
1726 m_aLinkFilterName.clear();
1728 else if ( lArguments[nInd].Name == "FilterName" )
1730 lArguments[nInd].Value >>= aNewLinkFilter;
1731 m_aLinkFilterName.clear();
1735 ::comphelper::MimeConfigurationHelper aHelper( m_xContext );
1736 if ( m_aLinkFilterName.isEmpty() )
1738 if ( !aNewLinkFilter.isEmpty() )
1739 m_aLinkFilterName = aNewLinkFilter;
1740 else
1742 uno::Sequence< beans::PropertyValue > aArgs( 1 );
1743 aArgs[0].Name = "URL";
1744 aArgs[0].Value <<= m_aLinkURL;
1745 m_aLinkFilterName = aHelper.UpdateMediaDescriptorWithFilterName( aArgs, false );
1749 if ( !aOldLinkFilter.equals( m_aLinkFilterName ) )
1751 uno::Sequence< beans::NamedValue > aObject = aHelper.GetObjectPropsByFilter( m_aLinkFilterName );
1753 // TODO/LATER: probably the document holder could be cleaned explicitly as in the destructor
1754 m_pDocHolder->release();
1755 m_pDocHolder = NULL;
1757 LinkInit_Impl( aObject, lArguments, lObjArgs );
1761 m_aDocMediaDescriptor = GetValuableArgs_Impl( lArguments, true );
1763 // TODO: use lObjArgs for StoreVisualReplacement
1764 for ( sal_Int32 nObjInd = 0; nObjInd < lObjArgs.getLength(); nObjInd++ )
1765 if ( lObjArgs[nObjInd].Name == "OutplaceDispatchInterceptor" )
1767 uno::Reference< frame::XDispatchProviderInterceptor > xDispatchInterceptor;
1768 if ( lObjArgs[nObjInd].Value >>= xDispatchInterceptor )
1769 m_pDocHolder->SetOutplaceDispatchInterceptor( xDispatchInterceptor );
1771 break;
1774 // TODO:
1775 // when document allows reloading through API the object can be reloaded not only in loaded state
1777 bool bOldReadOnlyValue = m_bReadOnly;
1779 m_bReadOnly = false;
1780 for ( sal_Int32 nInd = 0; nInd < lArguments.getLength(); nInd++ )
1781 if ( lArguments[nInd].Name == "ReadOnly" )
1782 lArguments[nInd].Value >>= m_bReadOnly;
1784 if ( bOldReadOnlyValue != m_bReadOnly && !m_bIsLink )
1786 // close own storage
1787 try {
1788 uno::Reference< lang::XComponent > xComponent( m_xObjectStorage, uno::UNO_QUERY );
1789 OSL_ENSURE( !m_xObjectStorage.is() || xComponent.is(), "Wrong storage implementation!" );
1790 if ( xComponent.is() )
1791 xComponent->dispose();
1793 catch ( const uno::Exception& )
1797 sal_Int32 nStorageMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
1798 m_xObjectStorage = m_xParentStorage->openStorageElement( m_aEntryName, nStorageMode );
1802 sal_Bool SAL_CALL OCommonEmbeddedObject::isStored() throw (css::uno::RuntimeException, std::exception)
1804 uno::Reference<container::XNameAccess> xNA(m_xObjectStorage, uno::UNO_QUERY);
1805 if (!xNA.is())
1806 return false;
1808 return xNA->getElementNames().getLength() > 0;
1812 void SAL_CALL OCommonEmbeddedObject::breakLink( const uno::Reference< embed::XStorage >& xStorage,
1813 const OUString& sEntName )
1814 throw ( lang::IllegalArgumentException,
1815 embed::WrongStateException,
1816 io::IOException,
1817 uno::Exception,
1818 uno::RuntimeException, std::exception )
1820 ::osl::ResettableMutexGuard aGuard( m_aMutex );
1821 if ( m_bDisposed )
1822 throw lang::DisposedException(); // TODO
1824 if ( !m_bIsLink )
1826 // it must be a linked initialized object
1827 throw embed::WrongStateException(
1828 "The object is not a valid linked object!",
1829 static_cast< ::cppu::OWeakObject* >(this) );
1831 else
1833 // the current implementation of OOo links does not implement this method since it does not implement
1834 // all the set of interfaces required for OOo embedded object ( XEmbedPersist is not supported ).
1837 if ( !xStorage.is() )
1838 throw lang::IllegalArgumentException( "No parent storage is provided!",
1839 static_cast< ::cppu::OWeakObject* >(this),
1840 1 );
1842 if ( sEntName.isEmpty() )
1843 throw lang::IllegalArgumentException( "Empty element name is provided!",
1844 static_cast< ::cppu::OWeakObject* >(this),
1845 2 );
1847 if ( !m_bIsLink || m_nObjectState == -1 )
1849 // it must be a linked initialized object
1850 throw embed::WrongStateException(
1851 "The object is not a valid linked object!",
1852 static_cast< ::cppu::OWeakObject* >(this) );
1855 if ( m_bWaitSaveCompleted )
1856 throw embed::WrongStateException(
1857 "The object waits for saveCompleted() call!",
1858 static_cast< ::cppu::OWeakObject* >(this) );
1860 uno::Reference< container::XNameAccess > xNameAccess( xStorage, uno::UNO_QUERY );
1861 if ( !xNameAccess.is() )
1862 throw uno::RuntimeException(); //TODO
1864 m_bReadOnly = false;
1866 if ( m_xParentStorage != xStorage || !m_aEntryName.equals( sEntName ) )
1867 SwitchOwnPersistence( xStorage, sEntName );
1869 // for linked object it means that it becomes embedded object
1870 // the document must switch it's persistence also
1872 // TODO/LATER: handle the case when temp doc can not be created
1873 // the document is a new embedded object so it must be marked as modified
1874 uno::Reference< util::XCloseable > xDocument = CreateTempDocFromLink_Impl();
1875 uno::Reference< util::XModifiable > xModif( m_pDocHolder->GetComponent(), uno::UNO_QUERY );
1876 if ( !xModif.is() )
1877 throw uno::RuntimeException();
1880 xModif->setModified( sal_True );
1882 catch( const uno::Exception& )
1885 m_pDocHolder->SetComponent( xDocument, m_bReadOnly );
1886 SAL_WARN_IF( !m_pDocHolder->GetComponent().is(), "embeddedobj.common", "If document can't be created, an exception must be thrown!" );
1888 if ( m_nObjectState == embed::EmbedStates::LOADED )
1890 // the state is changed and can not be switched to loaded state back without saving
1891 m_nObjectState = embed::EmbedStates::RUNNING;
1892 StateChangeNotification_Impl( false, embed::EmbedStates::LOADED, m_nObjectState, aGuard );
1894 else if ( m_nObjectState == embed::EmbedStates::ACTIVE )
1895 m_pDocHolder->Show();
1897 m_bIsLink = false;
1898 m_aLinkFilterName.clear();
1899 m_aLinkURL.clear();
1903 sal_Bool SAL_CALL OCommonEmbeddedObject::isLink()
1904 throw ( embed::WrongStateException,
1905 uno::RuntimeException, std::exception )
1907 ::osl::MutexGuard aGuard( m_aMutex );
1908 if ( m_bDisposed )
1909 throw lang::DisposedException(); // TODO
1911 return m_bIsLink;
1915 OUString SAL_CALL OCommonEmbeddedObject::getLinkURL()
1916 throw ( embed::WrongStateException,
1917 uno::Exception,
1918 uno::RuntimeException, std::exception )
1920 ::osl::MutexGuard aGuard( m_aMutex );
1921 if ( m_bDisposed )
1922 throw lang::DisposedException(); // TODO
1924 if ( !m_bIsLink )
1925 throw embed::WrongStateException(
1926 "The object is not a link object!",
1927 static_cast< ::cppu::OWeakObject* >(this) );
1929 return m_aLinkURL;
1932 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */