lok: vcl: fix multiple floatwin removal case more robustly.
[LibreOffice.git] / embeddedobj / source / commonembedding / persistence.cxx
blob06562ac3968264d0382e30920c56579db1820832
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/StorageWrappedTargetException.hpp>
27 #include <com/sun/star/embed/WrongStateException.hpp>
28 #include <com/sun/star/embed/XStorage.hpp>
29 #include <com/sun/star/embed/XOptimizedStorage.hpp>
30 #include <com/sun/star/embed/ElementModes.hpp>
31 #include <com/sun/star/embed/EmbedUpdateModes.hpp>
32 #include <com/sun/star/embed/StorageFactory.hpp>
33 #include <com/sun/star/io/IOException.hpp>
34 #include <com/sun/star/io/TempFile.hpp>
35 #include <com/sun/star/frame/XModel.hpp>
36 #include <com/sun/star/frame/XStorable.hpp>
37 #include <com/sun/star/frame/XLoadable.hpp>
38 #include <com/sun/star/frame/XModule.hpp>
39 #include <com/sun/star/lang/NoSupportException.hpp>
40 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
41 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
42 #include <com/sun/star/lang/DisposedException.hpp>
43 #include <com/sun/star/util/XModifiable.hpp>
45 #include <com/sun/star/container/XNameAccess.hpp>
46 #include <com/sun/star/container/XChild.hpp>
47 #include <com/sun/star/util/XCloseable.hpp>
48 #include <com/sun/star/beans/XPropertySet.hpp>
49 #include <com/sun/star/beans/IllegalTypeException.hpp>
50 #include <com/sun/star/chart2/XChartDocument.hpp>
52 #include <comphelper/fileformat.h>
53 #include <comphelper/storagehelper.hxx>
54 #include <comphelper/mimeconfighelper.hxx>
55 #include <comphelper/namedvaluecollection.hxx>
57 #include <tools/diagnose_ex.h>
58 #include <sal/log.hxx>
59 #include <unotools/configmgr.hxx>
60 #include "persistence.hxx"
62 using namespace ::com::sun::star;
65 uno::Sequence< beans::PropertyValue > GetValuableArgs_Impl( const uno::Sequence< beans::PropertyValue >& aMedDescr,
66 bool bCanUseDocumentBaseURL )
68 uno::Sequence< beans::PropertyValue > aResult;
69 sal_Int32 nResLen = 0;
71 for ( sal_Int32 nInd = 0; nInd < aMedDescr.getLength(); nInd++ )
73 if ( aMedDescr[nInd].Name == "ComponentData" || aMedDescr[nInd].Name == "DocumentTitle"
74 || aMedDescr[nInd].Name == "InteractionHandler" || aMedDescr[nInd].Name == "JumpMark"
75 // || aMedDescr[nInd].Name == "Password" // makes no sense for embedded objects
76 || aMedDescr[nInd].Name == "Preview" || aMedDescr[nInd].Name == "ReadOnly"
77 || aMedDescr[nInd].Name == "StartPresentation" || aMedDescr[nInd].Name == "RepairPackage"
78 || aMedDescr[nInd].Name == "StatusIndicator" || aMedDescr[nInd].Name == "ViewData"
79 || aMedDescr[nInd].Name == "ViewId" || aMedDescr[nInd].Name == "MacroExecutionMode"
80 || aMedDescr[nInd].Name == "UpdateDocMode"
81 || (aMedDescr[nInd].Name == "DocumentBaseURL" && bCanUseDocumentBaseURL) )
83 aResult.realloc( ++nResLen );
84 aResult[nResLen-1] = aMedDescr[nInd];
88 return aResult;
92 static uno::Sequence< beans::PropertyValue > addAsTemplate( const uno::Sequence< beans::PropertyValue >& aOrig )
94 bool bAsTemplateSet = false;
95 sal_Int32 nLength = aOrig.getLength();
96 uno::Sequence< beans::PropertyValue > aResult( nLength );
98 for ( sal_Int32 nInd = 0; nInd < nLength; nInd++ )
100 aResult[nInd].Name = aOrig[nInd].Name;
101 if ( aResult[nInd].Name == "AsTemplate" )
103 aResult[nInd].Value <<= true;
104 bAsTemplateSet = true;
106 else
107 aResult[nInd].Value = aOrig[nInd].Value;
110 if ( !bAsTemplateSet )
112 aResult.realloc( nLength + 1 );
113 aResult[nLength].Name = "AsTemplate";
114 aResult[nLength].Value <<= true;
117 return aResult;
121 static uno::Reference< io::XInputStream > createTempInpStreamFromStor(
122 const uno::Reference< embed::XStorage >& xStorage,
123 const uno::Reference< uno::XComponentContext >& xContext )
125 SAL_WARN_IF( !xStorage.is(), "embeddedobj.common", "The storage can not be empty!" );
127 uno::Reference< io::XInputStream > xResult;
129 uno::Reference < io::XStream > xTempStream( io::TempFile::create(xContext), uno::UNO_QUERY_THROW );
131 uno::Reference < lang::XSingleServiceFactory > xStorageFactory( embed::StorageFactory::create(xContext) );
133 uno::Sequence< uno::Any > aArgs( 2 );
134 aArgs[0] <<= xTempStream;
135 aArgs[1] <<= embed::ElementModes::READWRITE;
136 uno::Reference< embed::XStorage > xTempStorage( xStorageFactory->createInstanceWithArguments( aArgs ),
137 uno::UNO_QUERY_THROW );
141 xStorage->copyToStorage( xTempStorage );
142 } catch( const uno::Exception& )
144 css::uno::Any anyEx = cppu::getCaughtException();
145 throw embed::StorageWrappedTargetException(
146 "Can't copy storage!",
147 uno::Reference< uno::XInterface >(),
148 anyEx );
151 try {
152 uno::Reference< lang::XComponent > xComponent( xTempStorage, uno::UNO_QUERY );
153 SAL_WARN_IF( !xComponent.is(), "embeddedobj.common", "Wrong storage implementation!" );
154 if ( xComponent.is() )
155 xComponent->dispose();
157 catch ( const uno::Exception& )
161 try {
162 uno::Reference< io::XOutputStream > xTempOut = xTempStream->getOutputStream();
163 if ( xTempOut.is() )
164 xTempOut->closeOutput();
166 catch ( const uno::Exception& )
170 xResult = xTempStream->getInputStream();
172 return xResult;
177 static void TransferMediaType( const uno::Reference< embed::XStorage >& i_rSource, const uno::Reference< embed::XStorage >& i_rTarget )
181 const uno::Reference< beans::XPropertySet > xSourceProps( i_rSource, uno::UNO_QUERY_THROW );
182 const uno::Reference< beans::XPropertySet > xTargetProps( i_rTarget, uno::UNO_QUERY_THROW );
183 const OUString sMediaTypePropName( "MediaType" );
184 xTargetProps->setPropertyValue( sMediaTypePropName, xSourceProps->getPropertyValue( sMediaTypePropName ) );
186 catch( const uno::Exception& )
188 DBG_UNHANDLED_EXCEPTION("embeddedobj.common");
193 static uno::Reference< util::XCloseable > CreateDocument( const uno::Reference< uno::XComponentContext >& _rxContext,
194 const OUString& _rDocumentServiceName, bool _bEmbeddedScriptSupport, const bool i_bDocumentRecoverySupport )
196 ::comphelper::NamedValueCollection aArguments;
197 aArguments.put( "EmbeddedObject", true );
198 aArguments.put( "EmbeddedScriptSupport", _bEmbeddedScriptSupport );
199 aArguments.put( "DocumentRecoverySupport", i_bDocumentRecoverySupport );
201 uno::Reference< uno::XInterface > xDocument;
204 xDocument = _rxContext->getServiceManager()->createInstanceWithArgumentsAndContext(
205 _rDocumentServiceName, aArguments.getWrappedPropertyValues(), _rxContext );
207 catch( const uno::Exception& )
209 // if an embedded object implementation does not support XInitialization,
210 // the default factory from cppuhelper will throw an
211 // IllegalArgumentException when we try to create the instance with arguments.
212 // Okay, so we fall back to creating the instance without any arguments.
213 OSL_FAIL("Consider implementing interface XInitialization to avoid duplicate construction");
214 xDocument = _rxContext->getServiceManager()->createInstanceWithContext( _rDocumentServiceName, _rxContext );
217 SAL_WARN_IF(!xDocument.is(), "embeddedobj.common", "Service " << _rDocumentServiceName << " is not available?");
218 return uno::Reference< util::XCloseable >( xDocument, uno::UNO_QUERY );
222 static void SetDocToEmbedded( const uno::Reference< frame::XModel >& rDocument, const OUString& aModuleName )
224 if (rDocument.is())
226 uno::Sequence< beans::PropertyValue > aSeq( 1 );
227 aSeq[0].Name = "SetEmbedded";
228 aSeq[0].Value <<= true;
229 rDocument->attachResource( OUString(), aSeq );
231 if ( !aModuleName.isEmpty() )
235 uno::Reference< frame::XModule > xModule( rDocument, uno::UNO_QUERY_THROW );
236 xModule->setIdentifier( aModuleName );
238 catch( const uno::Exception& )
245 void OCommonEmbeddedObject::SwitchOwnPersistence( const uno::Reference< embed::XStorage >& xNewParentStorage,
246 const uno::Reference< embed::XStorage >& xNewObjectStorage,
247 const OUString& aNewName )
249 if ( xNewParentStorage == m_xParentStorage && aNewName == m_aEntryName )
251 SAL_WARN_IF( xNewObjectStorage != m_xObjectStorage, "embeddedobj.common", "The storage must be the same!" );
252 return;
255 uno::Reference< lang::XComponent > xComponent( m_xObjectStorage, uno::UNO_QUERY );
256 OSL_ENSURE( !m_xObjectStorage.is() || xComponent.is(), "Wrong storage implementation!" );
258 m_xObjectStorage = xNewObjectStorage;
259 m_xParentStorage = xNewParentStorage;
260 m_aEntryName = aNewName;
262 // the linked document should not be switched
263 if ( !m_bIsLink )
265 uno::Reference< document::XStorageBasedDocument > xDoc( m_xDocHolder->GetComponent(), uno::UNO_QUERY );
266 if ( xDoc.is() )
267 SwitchDocToStorage_Impl( xDoc, m_xObjectStorage );
270 try {
271 if ( xComponent.is() )
272 xComponent->dispose();
274 catch ( const uno::Exception& )
280 void OCommonEmbeddedObject::SwitchOwnPersistence( const uno::Reference< embed::XStorage >& xNewParentStorage,
281 const OUString& aNewName )
283 if ( xNewParentStorage == m_xParentStorage && aNewName == m_aEntryName )
284 return;
286 sal_Int32 nStorageMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
288 uno::Reference< embed::XStorage > xNewOwnStorage = xNewParentStorage->openStorageElement( aNewName, nStorageMode );
289 SAL_WARN_IF( !xNewOwnStorage.is(), "embeddedobj.common", "The method can not return empty reference!" );
291 SwitchOwnPersistence( xNewParentStorage, xNewOwnStorage, aNewName );
295 void OCommonEmbeddedObject::EmbedAndReparentDoc_Impl( const uno::Reference< util::XCloseable >& i_rxDocument ) const
297 SetDocToEmbedded( uno::Reference< frame::XModel >( i_rxDocument, uno::UNO_QUERY ), m_aModuleName );
301 uno::Reference < container::XChild > xChild( i_rxDocument, uno::UNO_QUERY );
302 if ( xChild.is() )
303 xChild->setParent( m_xParent );
305 catch( const lang::NoSupportException & )
307 SAL_WARN( "embeddedobj.common", "OCommonEmbeddedObject::EmbedAndReparentDoc: cannot set parent at document!" );
312 uno::Reference< util::XCloseable > OCommonEmbeddedObject::InitNewDocument_Impl()
314 uno::Reference< util::XCloseable > xDocument( CreateDocument( m_xContext, GetDocumentServiceName(),
315 m_bEmbeddedScriptSupport, m_bDocumentRecoverySupport ) );
317 uno::Reference< frame::XModel > xModel( xDocument, uno::UNO_QUERY );
318 uno::Reference< frame::XLoadable > xLoadable( xModel, uno::UNO_QUERY_THROW );
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( 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_THROW );
377 sal_Int32 nLen = 2;
378 uno::Sequence< beans::PropertyValue > aArgs( nLen );
379 aArgs[0].Name = "URL";
380 aArgs[0].Value <<= m_aLinkURL;
381 aArgs[1].Name = "FilterName";
382 aArgs[1].Value <<= m_aLinkFilterName;
383 if ( m_bLinkHasPassword )
385 aArgs.realloc( ++nLen );
386 aArgs[nLen-1].Name = "Password";
387 aArgs[nLen-1].Value <<= m_aLinkPassword;
390 aArgs.realloc( m_aDocMediaDescriptor.getLength() + nLen );
391 for ( sal_Int32 nInd = 0; nInd < m_aDocMediaDescriptor.getLength(); nInd++ )
393 aArgs[nInd+nLen].Name = m_aDocMediaDescriptor[nInd].Name;
394 aArgs[nInd+nLen].Value = m_aDocMediaDescriptor[nInd].Value;
399 // the document is not really an embedded one, it is a link
400 EmbedAndReparentDoc_Impl( xDocument );
402 // load the document
403 xLoadable->load( aArgs );
405 if ( !m_bLinkHasPassword )
407 // check if there is a password to cache
408 uno::Reference< frame::XModel > xModel( xLoadable, uno::UNO_QUERY_THROW );
409 uno::Sequence< beans::PropertyValue > aProps = xModel->getArgs();
410 for ( sal_Int32 nInd = 0; nInd < aProps.getLength(); nInd++ )
411 if ( aProps[nInd].Name == "Password" && ( aProps[nInd].Value >>= m_aLinkPassword ) )
413 m_bLinkHasPassword = true;
414 break;
418 catch( const uno::Exception& )
420 uno::Reference< util::XCloseable > xCloseable( xDocument, uno::UNO_QUERY );
421 if ( xCloseable.is() )
425 xCloseable->close( true );
427 catch( const uno::Exception& )
432 throw; // TODO
435 return xDocument;
440 OUString OCommonEmbeddedObject::GetFilterName( sal_Int32 nVersion ) const
442 OUString aFilterName = GetPresetFilterName();
443 if ( aFilterName.isEmpty() )
445 OUString sDocumentServiceName = GetDocumentServiceName();
446 if (utl::ConfigManager::IsFuzzing() && nVersion == SOFFICE_FILEFORMAT_CURRENT &&
447 sDocumentServiceName == "com.sun.star.chart2.ChartDocument")
449 return OUString("chart8");
451 try {
452 ::comphelper::MimeConfigurationHelper aHelper( m_xContext );
453 aFilterName = aHelper.GetDefaultFilterFromServiceName(sDocumentServiceName, nVersion);
455 // If no filter is found, fall back to the FileFormatVersion=6200 filter, Base only has that.
456 if (aFilterName.isEmpty() && nVersion == SOFFICE_FILEFORMAT_CURRENT)
457 aFilterName = aHelper.GetDefaultFilterFromServiceName(GetDocumentServiceName(), SOFFICE_FILEFORMAT_60);
458 } catch( const uno::Exception& )
462 return aFilterName;
466 void OCommonEmbeddedObject::FillDefaultLoadArgs_Impl( const uno::Reference< embed::XStorage >& i_rxStorage,
467 ::comphelper::NamedValueCollection& o_rLoadArgs ) const
469 o_rLoadArgs.put( "DocumentBaseURL", GetBaseURL_Impl() );
470 o_rLoadArgs.put( "HierarchicalDocumentName", m_aEntryName );
471 o_rLoadArgs.put( "ReadOnly", m_bReadOnly );
473 OUString aFilterName = GetFilterName( ::comphelper::OStorageHelper::GetXStorageFormat( i_rxStorage ) );
474 SAL_WARN_IF( aFilterName.isEmpty(), "embeddedobj.common", "OCommonEmbeddedObject::FillDefaultLoadArgs_Impl: Wrong document service name!" );
475 if ( aFilterName.isEmpty() )
476 throw io::IOException(); // TODO: error message/code
478 o_rLoadArgs.put( "FilterName", aFilterName );
482 uno::Reference< util::XCloseable > OCommonEmbeddedObject::LoadDocumentFromStorage_Impl()
484 ENSURE_OR_THROW( m_xObjectStorage.is(), "no object storage" );
486 const uno::Reference< embed::XStorage > xSourceStorage( m_xRecoveryStorage.is() ? m_xRecoveryStorage : m_xObjectStorage );
488 uno::Reference< util::XCloseable > xDocument( CreateDocument( m_xContext, GetDocumentServiceName(),
489 m_bEmbeddedScriptSupport, m_bDocumentRecoverySupport ) );
491 //#i103460# ODF: take the size given from the parent frame as default
492 uno::Reference< chart2::XChartDocument > xChart( xDocument, uno::UNO_QUERY );
493 if( xChart.is() )
495 uno::Reference< embed::XVisualObject > xChartVisualObject( xChart, uno::UNO_QUERY );
496 if( xChartVisualObject.is() )
497 xChartVisualObject->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT, m_aDefaultSizeForChart_In_100TH_MM );
500 uno::Reference< frame::XLoadable > xLoadable( xDocument, uno::UNO_QUERY );
501 uno::Reference< document::XStorageBasedDocument > xDoc( xDocument, uno::UNO_QUERY );
502 if ( !xDoc.is() && !xLoadable.is() )
503 throw uno::RuntimeException();
505 ::comphelper::NamedValueCollection aLoadArgs;
506 FillDefaultLoadArgs_Impl( xSourceStorage, aLoadArgs );
508 uno::Reference< io::XInputStream > xTempInpStream;
509 if ( !xDoc.is() )
511 xTempInpStream = createTempInpStreamFromStor( xSourceStorage, m_xContext );
512 if ( !xTempInpStream.is() )
513 throw uno::RuntimeException();
515 OUString aTempFileURL;
518 // no need to let the file stay after the stream is removed since the embedded document
519 // can not be stored directly
520 uno::Reference< beans::XPropertySet > xTempStreamProps( xTempInpStream, uno::UNO_QUERY_THROW );
521 xTempStreamProps->getPropertyValue("Uri") >>= aTempFileURL;
523 catch( const uno::Exception& )
527 SAL_WARN_IF( aTempFileURL.isEmpty(), "embeddedobj.common", "Couldn't retrieve temporary file URL!" );
529 aLoadArgs.put( "URL", aTempFileURL );
530 aLoadArgs.put( "InputStream", xTempInpStream );
534 aLoadArgs.merge( m_aDocMediaDescriptor, true );
538 // set the document mode to embedded as the first step!!!
539 EmbedAndReparentDoc_Impl( xDocument );
541 if ( xDoc.is() )
543 xDoc->loadFromStorage( xSourceStorage, aLoadArgs.getPropertyValues() );
544 if ( xSourceStorage != m_xObjectStorage )
545 SwitchDocToStorage_Impl( xDoc, m_xObjectStorage );
547 else
548 xLoadable->load( aLoadArgs.getPropertyValues() );
550 catch( const uno::Exception& )
552 uno::Reference< util::XCloseable > xCloseable( xDocument, uno::UNO_QUERY );
553 if ( xCloseable.is() )
557 xCloseable->close( true );
559 catch( const uno::Exception& )
561 DBG_UNHANDLED_EXCEPTION("embeddedobj.common");
565 throw; // TODO
568 return xDocument;
572 uno::Reference< io::XInputStream > OCommonEmbeddedObject::StoreDocumentToTempStream_Impl(
573 sal_Int32 nStorageFormat,
574 const OUString& aBaseURL,
575 const OUString& aHierarchName )
577 uno::Reference < io::XOutputStream > xTempOut(
578 io::TempFile::create(m_xContext),
579 uno::UNO_QUERY_THROW );
580 uno::Reference< io::XInputStream > aResult( xTempOut, uno::UNO_QUERY_THROW );
582 uno::Reference< frame::XStorable > xStorable;
584 osl::MutexGuard aGuard( m_aMutex );
585 if ( m_xDocHolder.is() )
586 xStorable.set( m_xDocHolder->GetComponent(), uno::UNO_QUERY );
589 if( !xStorable.is() )
590 throw uno::RuntimeException(); // TODO:
592 OUString aFilterName = GetFilterName( nStorageFormat );
594 SAL_WARN_IF( aFilterName.isEmpty(), "embeddedobj.common", "Wrong document service name!" );
595 if ( aFilterName.isEmpty() )
596 throw io::IOException(); // TODO:
598 uno::Sequence< beans::PropertyValue > aArgs( 4 );
599 aArgs[0].Name = "FilterName";
600 aArgs[0].Value <<= aFilterName;
601 aArgs[1].Name = "OutputStream";
602 aArgs[1].Value <<= xTempOut;
603 aArgs[2].Name = "DocumentBaseURL";
604 aArgs[2].Value <<= aBaseURL;
605 aArgs[3].Name = "HierarchicalDocumentName";
606 aArgs[3].Value <<= aHierarchName;
608 xStorable->storeToURL( "private:stream", aArgs );
611 xTempOut->closeOutput();
613 catch( const uno::Exception& )
615 SAL_WARN( "embeddedobj.common", "Looks like stream was closed already" );
618 return aResult;
622 void OCommonEmbeddedObject::SaveObject_Impl()
624 if ( m_xClientSite.is() )
628 // check whether the component is modified,
629 // if not there is no need for storing
630 uno::Reference< util::XModifiable > xModifiable( m_xDocHolder->GetComponent(), uno::UNO_QUERY );
631 if ( xModifiable.is() && !xModifiable->isModified() )
632 return;
634 catch( const uno::Exception& )
637 try {
638 m_xClientSite->saveObject();
640 catch( const uno::Exception& )
642 SAL_WARN( "embeddedobj.common", "The object was not stored!" );
648 OUString OCommonEmbeddedObject::GetBaseURL_Impl() const
650 OUString aBaseURL;
651 sal_Int32 nInd = 0;
653 if ( m_xClientSite.is() )
657 uno::Reference< frame::XModel > xParentModel( m_xClientSite->getComponent(), uno::UNO_QUERY_THROW );
658 uno::Sequence< beans::PropertyValue > aModelProps = xParentModel->getArgs();
659 for ( nInd = 0; nInd < aModelProps.getLength(); nInd++ )
660 if ( aModelProps[nInd].Name == "DocumentBaseURL" )
662 aModelProps[nInd].Value >>= aBaseURL;
663 break;
668 catch( const uno::Exception& )
672 if ( aBaseURL.isEmpty() )
674 for ( nInd = 0; nInd < m_aDocMediaDescriptor.getLength(); nInd++ )
675 if ( m_aDocMediaDescriptor[nInd].Name == "DocumentBaseURL" )
677 m_aDocMediaDescriptor[nInd].Value >>= aBaseURL;
678 break;
682 if ( aBaseURL.isEmpty() )
683 aBaseURL = m_aDefaultParentBaseURL;
685 return aBaseURL;
689 OUString OCommonEmbeddedObject::GetBaseURLFrom_Impl(
690 const uno::Sequence< beans::PropertyValue >& lArguments,
691 const uno::Sequence< beans::PropertyValue >& lObjArgs )
693 OUString aBaseURL;
694 sal_Int32 nInd = 0;
696 for ( nInd = 0; nInd < lArguments.getLength(); nInd++ )
697 if ( lArguments[nInd].Name == "DocumentBaseURL" )
699 lArguments[nInd].Value >>= aBaseURL;
700 break;
703 if ( aBaseURL.isEmpty() )
705 for ( nInd = 0; nInd < lObjArgs.getLength(); nInd++ )
706 if ( lObjArgs[nInd].Name == "DefaultParentBaseURL" )
708 lObjArgs[nInd].Value >>= aBaseURL;
709 break;
713 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( 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_xDocHolder.is() )
766 xDoc.set( m_xDocHolder->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_THROW );
814 // object storage must be committed automatically
815 xTempStorage->copyToStorage( xStorage );
820 uno::Reference< util::XCloseable > OCommonEmbeddedObject::CreateDocFromMediaDescr_Impl(
821 const uno::Sequence< beans::PropertyValue >& aMedDescr )
823 uno::Reference< util::XCloseable > xDocument( CreateDocument( m_xContext, GetDocumentServiceName(),
824 m_bEmbeddedScriptSupport, m_bDocumentRecoverySupport ) );
826 uno::Reference< frame::XLoadable > xLoadable( xDocument, uno::UNO_QUERY_THROW );
830 // set the document mode to embedded as the first action on the document!!!
831 EmbedAndReparentDoc_Impl( xDocument );
833 xLoadable->load( addAsTemplate( aMedDescr ) );
835 catch( const uno::Exception& )
837 uno::Reference< util::XCloseable > xCloseable( xDocument, uno::UNO_QUERY );
838 if ( xCloseable.is() )
842 xCloseable->close( true );
844 catch( const uno::Exception& )
849 throw; // TODO
852 return xDocument;
856 uno::Reference< util::XCloseable > OCommonEmbeddedObject::CreateTempDocFromLink_Impl()
858 uno::Reference< util::XCloseable > xResult;
860 SAL_WARN_IF( !m_bIsLink, "embeddedobj.common", "The object is not a linked one!" );
862 uno::Sequence< beans::PropertyValue > aTempMediaDescr;
864 sal_Int32 nStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
865 try {
866 nStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage );
868 catch ( const beans::IllegalTypeException& )
870 // the container just has an unknown type, use current file format
872 catch ( const uno::Exception& )
874 SAL_WARN( "embeddedobj.common", "Can not retrieve storage media type!" );
877 if ( m_xDocHolder->GetComponent().is() )
879 aTempMediaDescr.realloc( 4 );
881 // TODO/LATER: may be private:stream should be used as target URL
882 OUString aTempFileURL;
883 uno::Reference< io::XInputStream > xTempStream = StoreDocumentToTempStream_Impl( SOFFICE_FILEFORMAT_CURRENT,
884 OUString(),
885 OUString() );
888 // no need to let the file stay after the stream is removed since the embedded document
889 // can not be stored directly
890 uno::Reference< beans::XPropertySet > xTempStreamProps( xTempStream, uno::UNO_QUERY_THROW );
891 xTempStreamProps->getPropertyValue("Uri") >>= aTempFileURL;
893 catch( const uno::Exception& )
897 SAL_WARN_IF( aTempFileURL.isEmpty(), "embeddedobj.common", "Couldn't retrieve temporary file URL!" );
899 aTempMediaDescr[0].Name = "URL";
900 aTempMediaDescr[0].Value <<= aTempFileURL;
901 aTempMediaDescr[1].Name = "InputStream";
902 aTempMediaDescr[1].Value <<= xTempStream;
903 aTempMediaDescr[2].Name = "FilterName";
904 aTempMediaDescr[2].Value <<= GetFilterName( nStorageFormat );
905 aTempMediaDescr[3].Name = "AsTemplate";
906 aTempMediaDescr[3].Value <<= true;
908 else
910 aTempMediaDescr.realloc( 2 );
911 aTempMediaDescr[0].Name = "URL";
912 aTempMediaDescr[0].Value <<= m_aLinkURL;
913 aTempMediaDescr[1].Name = "FilterName";
914 aTempMediaDescr[1].Value <<= m_aLinkFilterName;
917 xResult = CreateDocFromMediaDescr_Impl( aTempMediaDescr );
919 return xResult;
923 void SAL_CALL OCommonEmbeddedObject::setPersistentEntry(
924 const uno::Reference< embed::XStorage >& xStorage,
925 const OUString& sEntName,
926 sal_Int32 nEntryConnectionMode,
927 const uno::Sequence< beans::PropertyValue >& lArguments,
928 const uno::Sequence< beans::PropertyValue >& lObjArgs )
930 // the type of the object must be already set
931 // a kind of typedetection should be done in the factory
933 ::osl::MutexGuard aGuard( m_aMutex );
934 if ( m_bDisposed )
935 throw lang::DisposedException(); // TODO
937 if ( !xStorage.is() )
938 throw lang::IllegalArgumentException( "No parent storage is provided!",
939 static_cast< ::cppu::OWeakObject* >(this),
940 1 );
942 if ( sEntName.isEmpty() )
943 throw lang::IllegalArgumentException( "Empty element name is provided!",
944 static_cast< ::cppu::OWeakObject* >(this),
945 2 );
947 // May be LOADED should be forbidden here ???
948 if ( ( m_nObjectState != -1 || nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
949 && ( m_nObjectState == -1 || nEntryConnectionMode != embed::EntryInitModes::NO_INIT ) )
951 // if the object is not loaded
952 // it can not get persistent representation without initialization
954 // if the object is loaded
955 // it can switch persistent representation only without initialization
957 throw embed::WrongStateException(
958 "Can't change persistent representation of activated object!",
959 static_cast< ::cppu::OWeakObject* >(this) );
962 if ( m_bWaitSaveCompleted )
964 if ( nEntryConnectionMode != embed::EntryInitModes::NO_INIT )
965 throw embed::WrongStateException(
966 "The object waits for saveCompleted() call!",
967 static_cast< ::cppu::OWeakObject* >(this) );
968 // saveCompleted is expected, handle it accordingly
969 if ( m_xNewParentStorage == xStorage && m_aNewEntryName == sEntName )
971 saveCompleted( true );
972 return;
975 // if a completely different entry is provided, switch first back to the old persistence in saveCompleted
976 // and then switch to the target persistence
977 bool bSwitchFurther = ( m_xParentStorage != xStorage || m_aEntryName != sEntName );
978 saveCompleted( false );
979 if ( !bSwitchFurther )
980 return;
983 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
984 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
985 // OSL_ENSURE( !m_bIsLink, "This method implementation must not be used for links!" );
986 if ( m_bIsLink )
988 m_aEntryName = sEntName;
989 return;
992 uno::Reference< container::XNameAccess > xNameAccess( xStorage, uno::UNO_QUERY_THROW );
994 // detect entry existence
995 bool bElExists = xNameAccess->hasByName( sEntName );
997 m_aDocMediaDescriptor = GetValuableArgs_Impl( lArguments,
998 nEntryConnectionMode != embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT );
1000 m_bReadOnly = false;
1001 for ( sal_Int32 nInd = 0; nInd < lArguments.getLength(); nInd++ )
1002 if ( lArguments[nInd].Name == "ReadOnly" )
1003 lArguments[nInd].Value >>= m_bReadOnly;
1005 // TODO: use lObjArgs for StoreVisualReplacement
1006 for ( sal_Int32 nObjInd = 0; nObjInd < lObjArgs.getLength(); nObjInd++ )
1007 if ( lObjArgs[nObjInd].Name == "OutplaceDispatchInterceptor" )
1009 uno::Reference< frame::XDispatchProviderInterceptor > xDispatchInterceptor;
1010 if ( lObjArgs[nObjInd].Value >>= xDispatchInterceptor )
1011 m_xDocHolder->SetOutplaceDispatchInterceptor( xDispatchInterceptor );
1013 else if ( lObjArgs[nObjInd].Name == "DefaultParentBaseURL" )
1015 lObjArgs[nObjInd].Value >>= m_aDefaultParentBaseURL;
1017 else if ( lObjArgs[nObjInd].Name == "Parent" )
1019 lObjArgs[nObjInd].Value >>= m_xParent;
1021 else if ( lObjArgs[nObjInd].Name == "IndividualMiscStatus" )
1023 sal_Int64 nMiscStatus=0;
1024 lObjArgs[nObjInd].Value >>= nMiscStatus;
1025 m_nMiscStatus |= nMiscStatus;
1027 else if ( lObjArgs[nObjInd].Name == "CloneFrom" )
1029 uno::Reference < embed::XEmbeddedObject > xObj;
1030 lObjArgs[nObjInd].Value >>= xObj;
1031 if ( xObj.is() )
1033 m_bHasClonedSize = true;
1034 m_aClonedSize = xObj->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT );
1035 m_nClonedMapUnit = xObj->getMapUnit( embed::Aspects::MSOLE_CONTENT );
1038 else if ( lObjArgs[nObjInd].Name == "OutplaceFrameProperties" )
1040 uno::Sequence< uno::Any > aOutFrameProps;
1041 uno::Sequence< beans::NamedValue > aOutFramePropsTyped;
1042 if ( lObjArgs[nObjInd].Value >>= aOutFrameProps )
1044 m_xDocHolder->SetOutplaceFrameProperties( aOutFrameProps );
1046 else if ( lObjArgs[nObjInd].Value >>= aOutFramePropsTyped )
1048 aOutFrameProps.realloc( aOutFramePropsTyped.getLength() );
1049 uno::Any* pProp = aOutFrameProps.getArray();
1050 for ( const beans::NamedValue* pTypedProp = aOutFramePropsTyped.getConstArray();
1051 pTypedProp != aOutFramePropsTyped.getConstArray() + aOutFramePropsTyped.getLength();
1052 ++pTypedProp, ++pProp
1055 *pProp <<= *pTypedProp;
1057 m_xDocHolder->SetOutplaceFrameProperties( aOutFrameProps );
1059 else
1060 SAL_WARN( "embeddedobj.common", "OCommonEmbeddedObject::setPersistentEntry: illegal type for argument 'OutplaceFrameProperties'!" );
1062 else if ( lObjArgs[nObjInd].Name == "ModuleName" )
1064 lObjArgs[nObjInd].Value >>= m_aModuleName;
1066 else if ( lObjArgs[nObjInd].Name == "EmbeddedScriptSupport" )
1068 OSL_VERIFY( lObjArgs[nObjInd].Value >>= m_bEmbeddedScriptSupport );
1070 else if ( lObjArgs[nObjInd].Name == "DocumentRecoverySupport" )
1072 OSL_VERIFY( lObjArgs[nObjInd].Value >>= m_bDocumentRecoverySupport );
1074 else if ( lObjArgs[nObjInd].Name == "RecoveryStorage" )
1076 OSL_VERIFY( lObjArgs[nObjInd].Value >>= m_xRecoveryStorage );
1080 sal_Int32 nStorageMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
1082 SwitchOwnPersistence( xStorage, sEntName );
1084 if ( nEntryConnectionMode == embed::EntryInitModes::DEFAULT_INIT )
1086 if ( bElExists )
1088 // the initialization from existing storage allows to leave object in loaded state
1089 m_nObjectState = embed::EmbedStates::LOADED;
1091 else
1093 m_xDocHolder->SetComponent( InitNewDocument_Impl(), m_bReadOnly );
1094 if ( !m_xDocHolder->GetComponent().is() )
1095 throw io::IOException(); // TODO: can not create document
1097 m_nObjectState = embed::EmbedStates::RUNNING;
1100 else
1102 if ( ( nStorageMode & embed::ElementModes::READWRITE ) != embed::ElementModes::READWRITE )
1103 throw io::IOException();
1105 if ( nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
1107 // the document just already changed its storage to store to
1108 // the links to OOo documents for now ignore this call
1109 // TODO: OOo links will have persistence so it will be switched here
1111 else if ( nEntryConnectionMode == embed::EntryInitModes::TRUNCATE_INIT )
1113 if ( m_xRecoveryStorage.is() )
1114 TransferMediaType( m_xRecoveryStorage, m_xObjectStorage );
1116 // TODO:
1117 m_xDocHolder->SetComponent( InitNewDocument_Impl(), m_bReadOnly );
1119 if ( !m_xDocHolder->GetComponent().is() )
1120 throw io::IOException(); // TODO: can not create document
1122 m_nObjectState = embed::EmbedStates::RUNNING;
1124 else if ( nEntryConnectionMode == embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT )
1126 m_xDocHolder->SetComponent( CreateDocFromMediaDescr_Impl( lArguments ), m_bReadOnly );
1127 m_nObjectState = embed::EmbedStates::RUNNING;
1129 //else if ( nEntryConnectionMode == embed::EntryInitModes::TRANSFERABLE_INIT )
1131 //TODO:
1133 else
1134 throw lang::IllegalArgumentException( "Wrong connection mode is provided!",
1135 static_cast< ::cppu::OWeakObject* >(this),
1136 3 );
1141 void SAL_CALL OCommonEmbeddedObject::storeToEntry( const uno::Reference< embed::XStorage >& xStorage,
1142 const OUString& sEntName,
1143 const uno::Sequence< beans::PropertyValue >& lArguments,
1144 const uno::Sequence< beans::PropertyValue >& lObjArgs )
1146 ::osl::ResettableMutexGuard aGuard( m_aMutex );
1147 if ( m_bDisposed )
1148 throw lang::DisposedException(); // TODO
1150 if ( m_nObjectState == -1 )
1152 // the object is still not loaded
1153 throw embed::WrongStateException( "Can't store object without persistence!",
1154 static_cast< ::cppu::OWeakObject* >(this) );
1157 if ( m_bWaitSaveCompleted )
1158 throw embed::WrongStateException(
1159 "The object waits for saveCompleted() call!",
1160 static_cast< ::cppu::OWeakObject* >(this) );
1162 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1163 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1164 // OSL_ENSURE( !m_bIsLink, "This method implementation must not be used for links!" );
1165 if ( m_bIsLink )
1166 return;
1168 OSL_ENSURE( m_xParentStorage.is() && m_xObjectStorage.is(), "The object has no valid persistence!" );
1170 sal_Int32 nTargetStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1171 sal_Int32 nOriginalStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1172 try {
1173 nTargetStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( xStorage );
1175 catch ( const beans::IllegalTypeException& )
1177 // the container just has an unknown type, use current file format
1179 catch ( const uno::Exception& )
1181 SAL_WARN( "embeddedobj.common", "Can not retrieve target storage media type!" );
1183 if (nTargetStorageFormat == SOFFICE_FILEFORMAT_60)
1185 SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1186 nTargetStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1187 // setting MediaType is done later anyway, no need to do it here
1192 nOriginalStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage );
1194 catch ( const beans::IllegalTypeException& )
1196 // the container just has an unknown type, use current file format
1198 catch ( const uno::Exception& )
1200 SAL_WARN( "embeddedobj.common", "Can not retrieve own storage media type!" );
1203 bool bTryOptimization = false;
1204 for ( sal_Int32 nInd = 0; nInd < lObjArgs.getLength(); nInd++ )
1206 // StoreVisualReplacement and VisualReplacement args have no sense here
1207 if ( lObjArgs[nInd].Name == "CanTryOptimization" )
1208 lObjArgs[nInd].Value >>= bTryOptimization;
1211 bool bSwitchBackToLoaded = false;
1213 // Storing to different format can be done only in running state.
1214 if ( m_nObjectState == embed::EmbedStates::LOADED )
1216 // TODO/LATER: copying is not legal for documents with relative links.
1217 if ( nTargetStorageFormat == nOriginalStorageFormat )
1219 bool bOptimizationWorks = false;
1220 if ( bTryOptimization )
1224 // try to use optimized copying
1225 uno::Reference< embed::XOptimizedStorage > xSource( m_xParentStorage, uno::UNO_QUERY_THROW );
1226 uno::Reference< embed::XOptimizedStorage > xTarget( xStorage, uno::UNO_QUERY_THROW );
1227 xSource->copyElementDirectlyTo( m_aEntryName, xTarget, sEntName );
1228 bOptimizationWorks = true;
1230 catch( const uno::Exception& )
1235 if ( !bOptimizationWorks )
1236 m_xParentStorage->copyElementTo( m_aEntryName, xStorage, sEntName );
1238 else
1240 changeState( embed::EmbedStates::RUNNING );
1241 bSwitchBackToLoaded = true;
1245 if ( m_nObjectState != embed::EmbedStates::LOADED )
1247 uno::Reference< embed::XStorage > xSubStorage =
1248 xStorage->openStorageElement( sEntName, embed::ElementModes::READWRITE );
1250 if ( !xSubStorage.is() )
1251 throw uno::RuntimeException(); //TODO
1253 aGuard.clear();
1254 // TODO/LATER: support hierarchical name for embedded objects in embedded objects
1255 StoreDocToStorage_Impl(
1256 xSubStorage, lArguments, lObjArgs, nTargetStorageFormat, sEntName, false );
1257 aGuard.reset();
1259 if ( bSwitchBackToLoaded )
1260 changeState( embed::EmbedStates::LOADED );
1263 // TODO: should the listener notification be done?
1267 void SAL_CALL OCommonEmbeddedObject::storeAsEntry( const uno::Reference< embed::XStorage >& xStorage,
1268 const OUString& sEntName,
1269 const uno::Sequence< beans::PropertyValue >& lArguments,
1270 const uno::Sequence< beans::PropertyValue >& lObjArgs )
1272 // TODO: use lObjArgs
1274 ::osl::ResettableMutexGuard aGuard( m_aMutex );
1275 if ( m_bDisposed )
1276 throw lang::DisposedException(); // TODO
1278 if ( m_nObjectState == -1 )
1280 // the object is still not loaded
1281 throw embed::WrongStateException( "Can't store object without persistence!",
1282 static_cast< ::cppu::OWeakObject* >(this) );
1285 if ( m_bWaitSaveCompleted )
1286 throw embed::WrongStateException(
1287 "The object waits for saveCompleted() call!",
1288 static_cast< ::cppu::OWeakObject* >(this) );
1290 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1291 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1292 // OSL_ENSURE( !m_bIsLink, "This method implementation must not be used for links!" );
1293 if ( m_bIsLink )
1295 m_aNewEntryName = sEntName;
1296 return;
1299 OSL_ENSURE( m_xParentStorage.is() && m_xObjectStorage.is(), "The object has no valid persistence!" );
1301 sal_Int32 nTargetStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1302 sal_Int32 nOriginalStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1303 try {
1304 nTargetStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( xStorage );
1306 catch ( const beans::IllegalTypeException& )
1308 // the container just has an unknown type, use current file format
1310 catch ( const uno::Exception& )
1312 SAL_WARN( "embeddedobj.common", "Can not retrieve target storage media type!" );
1314 if (nTargetStorageFormat == SOFFICE_FILEFORMAT_60)
1316 SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1317 nTargetStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1318 // setting MediaType is done later anyway, no need to do it here
1323 nOriginalStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage );
1325 catch ( const beans::IllegalTypeException& )
1327 // the container just has an unknown type, use current file format
1329 catch ( const uno::Exception& )
1331 SAL_WARN( "embeddedobj.common", "Can not retrieve own storage media type!" );
1334 PostEvent_Impl( "OnSaveAs" );
1336 bool bTryOptimization = false;
1337 for ( sal_Int32 nInd = 0; nInd < lObjArgs.getLength(); nInd++ )
1339 // StoreVisualReplacement and VisualReplacement args have no sense here
1340 if ( lObjArgs[nInd].Name == "CanTryOptimization" )
1341 lObjArgs[nInd].Value >>= bTryOptimization;
1344 bool bSwitchBackToLoaded = false;
1346 // Storing to different format can be done only in running state.
1347 if ( m_nObjectState == embed::EmbedStates::LOADED )
1349 // TODO/LATER: copying is not legal for documents with relative links.
1350 if ( nTargetStorageFormat == nOriginalStorageFormat )
1352 bool bOptimizationWorks = false;
1353 if ( bTryOptimization )
1357 // try to use optimized copying
1358 uno::Reference< embed::XOptimizedStorage > xSource( m_xParentStorage, uno::UNO_QUERY_THROW );
1359 uno::Reference< embed::XOptimizedStorage > xTarget( xStorage, uno::UNO_QUERY_THROW );
1360 xSource->copyElementDirectlyTo( m_aEntryName, xTarget, sEntName );
1361 bOptimizationWorks = true;
1363 catch( const uno::Exception& )
1368 if ( !bOptimizationWorks )
1369 m_xParentStorage->copyElementTo( m_aEntryName, xStorage, sEntName );
1371 else
1373 changeState( embed::EmbedStates::RUNNING );
1374 bSwitchBackToLoaded = true;
1378 uno::Reference< embed::XStorage > xSubStorage =
1379 xStorage->openStorageElement( sEntName, embed::ElementModes::READWRITE );
1381 if ( !xSubStorage.is() )
1382 throw uno::RuntimeException(); //TODO
1384 if ( m_nObjectState != embed::EmbedStates::LOADED )
1386 aGuard.clear();
1387 // TODO/LATER: support hierarchical name for embedded objects in embedded objects
1388 StoreDocToStorage_Impl(
1389 xSubStorage, lArguments, lObjArgs, nTargetStorageFormat, sEntName, false );
1390 aGuard.reset();
1392 if ( bSwitchBackToLoaded )
1393 changeState( embed::EmbedStates::LOADED );
1396 m_bWaitSaveCompleted = true;
1397 m_xNewObjectStorage = xSubStorage;
1398 m_xNewParentStorage = xStorage;
1399 m_aNewEntryName = sEntName;
1400 m_aNewDocMediaDescriptor = GetValuableArgs_Impl( lArguments, true );
1402 // TODO: register listeners for storages above, in case thay are disposed
1403 // an exception will be thrown on saveCompleted( true )
1405 // TODO: should the listener notification be done here or in saveCompleted?
1409 void SAL_CALL OCommonEmbeddedObject::saveCompleted( sal_Bool bUseNew )
1411 ::osl::MutexGuard aGuard( m_aMutex );
1412 if ( m_bDisposed )
1413 throw lang::DisposedException(); // TODO
1415 if ( m_nObjectState == -1 )
1417 // the object is still not loaded
1418 throw embed::WrongStateException( "Can't store object without persistence!",
1419 static_cast< ::cppu::OWeakObject* >(this) );
1422 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1423 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1424 // OSL_ENSURE( !m_bIsLink, "This method implementation must not be used for links!" );
1425 if ( m_bIsLink )
1427 if ( bUseNew )
1428 m_aEntryName = m_aNewEntryName;
1429 m_aNewEntryName.clear();
1430 return;
1433 // it is allowed to call saveCompleted( false ) for nonstored objects
1434 if ( !m_bWaitSaveCompleted && !bUseNew )
1435 return;
1437 SAL_WARN_IF( !m_bWaitSaveCompleted, "embeddedobj.common", "Unexpected saveCompleted() call!" );
1438 if ( !m_bWaitSaveCompleted )
1439 throw io::IOException(); // TODO: illegal call
1441 OSL_ENSURE( m_xNewObjectStorage.is() && m_xNewParentStorage.is() , "Internal object information is broken!" );
1442 if ( !m_xNewObjectStorage.is() || !m_xNewParentStorage.is() )
1443 throw uno::RuntimeException(); // TODO: broken internal information
1445 if ( bUseNew )
1447 SwitchOwnPersistence( m_xNewParentStorage, m_xNewObjectStorage, m_aNewEntryName );
1448 m_aDocMediaDescriptor = m_aNewDocMediaDescriptor;
1450 uno::Reference< util::XModifiable > xModif( m_xDocHolder->GetComponent(), uno::UNO_QUERY );
1451 if ( xModif.is() )
1452 xModif->setModified( false );
1454 PostEvent_Impl( "OnSaveAsDone");
1456 else
1458 try {
1459 uno::Reference< lang::XComponent > xComponent( m_xNewObjectStorage, uno::UNO_QUERY );
1460 SAL_WARN_IF( !xComponent.is(), "embeddedobj.common", "Wrong storage implementation!" );
1461 if ( xComponent.is() )
1462 xComponent->dispose();
1464 catch ( const uno::Exception& )
1469 m_xNewObjectStorage.clear();
1470 m_xNewParentStorage.clear();
1471 m_aNewEntryName.clear();
1472 m_aNewDocMediaDescriptor.realloc( 0 );
1473 m_bWaitSaveCompleted = false;
1475 if ( bUseNew )
1477 // TODO: notify listeners
1479 if ( m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE )
1481 // TODO: update visual representation
1487 sal_Bool SAL_CALL OCommonEmbeddedObject::hasEntry()
1489 ::osl::MutexGuard aGuard( m_aMutex );
1490 if ( m_bDisposed )
1491 throw lang::DisposedException(); // TODO
1493 if ( m_bWaitSaveCompleted )
1494 throw embed::WrongStateException(
1495 "The object waits for saveCompleted() call!",
1496 static_cast< ::cppu::OWeakObject* >(this) );
1498 if ( m_xObjectStorage.is() )
1499 return true;
1501 return false;
1505 OUString SAL_CALL OCommonEmbeddedObject::getEntryName()
1507 ::osl::MutexGuard aGuard( m_aMutex );
1508 if ( m_bDisposed )
1509 throw lang::DisposedException(); // TODO
1511 if ( m_nObjectState == -1 )
1513 // the object is still not loaded
1514 throw embed::WrongStateException( "The object persistence is not initialized!",
1515 static_cast< ::cppu::OWeakObject* >(this) );
1518 if ( m_bWaitSaveCompleted )
1519 throw embed::WrongStateException(
1520 "The object waits for saveCompleted() call!",
1521 static_cast< ::cppu::OWeakObject* >(this) );
1523 return m_aEntryName;
1527 void SAL_CALL OCommonEmbeddedObject::storeOwn()
1529 // during switching from Activated to Running and from Running to Loaded states the object will
1530 // ask container to store the object, the container has to make decision
1531 // to do so or not
1533 ::osl::ResettableMutexGuard aGuard( m_aMutex );
1534 if ( m_bDisposed )
1535 throw lang::DisposedException(); // TODO
1537 if ( m_nObjectState == -1 )
1539 // the object is still not loaded
1540 throw embed::WrongStateException( "Can't store object without persistence!",
1541 static_cast< ::cppu::OWeakObject* >(this) );
1544 if ( m_bWaitSaveCompleted )
1545 throw embed::WrongStateException(
1546 "The object waits for saveCompleted() call!",
1547 static_cast< ::cppu::OWeakObject* >(this) );
1549 if ( m_bReadOnly )
1550 throw io::IOException(); // TODO: access denied
1552 // nothing to do, if the object is in loaded state
1553 if ( m_nObjectState == embed::EmbedStates::LOADED )
1554 return;
1556 PostEvent_Impl( "OnSave" );
1558 SAL_WARN_IF( !m_xDocHolder->GetComponent().is(), "embeddedobj.common", "If an object is activated or in running state it must have a document!" );
1559 if ( !m_xDocHolder->GetComponent().is() )
1560 throw uno::RuntimeException();
1562 if ( m_bIsLink )
1564 // TODO: just store the document to its location
1565 uno::Reference< frame::XStorable > xStorable( m_xDocHolder->GetComponent(), uno::UNO_QUERY_THROW );
1567 // free the main mutex for the storing time
1568 aGuard.clear();
1570 xStorable->store();
1572 aGuard.reset();
1574 else
1576 OSL_ENSURE( m_xParentStorage.is() && m_xObjectStorage.is(), "The object has no valid persistence!" );
1578 if ( !m_xObjectStorage.is() )
1579 throw io::IOException(); //TODO: access denied
1581 sal_Int32 nStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1582 try {
1583 nStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage );
1585 catch ( const beans::IllegalTypeException& )
1587 // the container just has an unknown type, use current file format
1589 catch ( const uno::Exception& )
1591 SAL_WARN( "embeddedobj.common", "Can not retrieve storage media type!" );
1593 if (nStorageFormat == SOFFICE_FILEFORMAT_60)
1595 SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1596 nStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1597 // setting MediaType is done later anyway, no need to do it here
1600 aGuard.clear();
1601 uno::Sequence<beans::PropertyValue> aEmpty;
1602 uno::Sequence<beans::PropertyValue> aMediaArgs(1);
1603 aMediaArgs[0].Name = "DocumentBaseURL";
1604 aMediaArgs[0].Value <<= GetBaseURL_Impl();
1605 StoreDocToStorage_Impl( m_xObjectStorage, aMediaArgs, aEmpty, nStorageFormat, m_aEntryName, true );
1606 aGuard.reset();
1609 uno::Reference< util::XModifiable > xModif( m_xDocHolder->GetComponent(), uno::UNO_QUERY );
1610 if ( xModif.is() )
1611 xModif->setModified( false );
1613 PostEvent_Impl( "OnSaveDone" );
1617 sal_Bool SAL_CALL OCommonEmbeddedObject::isReadonly()
1619 ::osl::MutexGuard aGuard( m_aMutex );
1620 if ( m_bDisposed )
1621 throw lang::DisposedException(); // TODO
1623 if ( m_nObjectState == -1 )
1625 // the object is still not loaded
1626 throw embed::WrongStateException( "The object persistence is not initialized!",
1627 static_cast< ::cppu::OWeakObject* >(this) );
1630 if ( m_bWaitSaveCompleted )
1631 throw embed::WrongStateException(
1632 "The object waits for saveCompleted() call!",
1633 static_cast< ::cppu::OWeakObject* >(this) );
1635 return m_bReadOnly;
1639 void SAL_CALL OCommonEmbeddedObject::reload(
1640 const uno::Sequence< beans::PropertyValue >& lArguments,
1641 const uno::Sequence< beans::PropertyValue >& lObjArgs )
1643 // TODO: use lObjArgs
1644 // for now this method is used only to switch readonly state
1646 ::osl::MutexGuard aGuard( m_aMutex );
1647 if ( m_bDisposed )
1648 throw lang::DisposedException(); // TODO
1650 if ( m_nObjectState == -1 )
1652 // the object is still not loaded
1653 throw embed::WrongStateException( "The object persistence is not initialized!",
1654 static_cast< ::cppu::OWeakObject* >(this) );
1657 if ( m_nObjectState != embed::EmbedStates::LOADED )
1659 // the object is still not loaded
1660 throw embed::WrongStateException(
1661 "The object must be in loaded state to be reloaded!",
1662 static_cast< ::cppu::OWeakObject* >(this) );
1665 if ( m_bWaitSaveCompleted )
1666 throw embed::WrongStateException(
1667 "The object waits for saveCompleted() call!",
1668 static_cast< ::cppu::OWeakObject* >(this) );
1670 if ( m_bIsLink )
1672 // reload of the link
1673 OUString aOldLinkFilter = m_aLinkFilterName;
1675 OUString aNewLinkFilter;
1676 for ( sal_Int32 nInd = 0; nInd < lArguments.getLength(); nInd++ )
1678 if ( lArguments[nInd].Name == "URL" )
1680 // the new URL
1681 lArguments[nInd].Value >>= m_aLinkURL;
1682 m_aLinkFilterName.clear();
1684 else if ( lArguments[nInd].Name == "FilterName" )
1686 lArguments[nInd].Value >>= aNewLinkFilter;
1687 m_aLinkFilterName.clear();
1691 ::comphelper::MimeConfigurationHelper aHelper( m_xContext );
1692 if ( m_aLinkFilterName.isEmpty() )
1694 if ( !aNewLinkFilter.isEmpty() )
1695 m_aLinkFilterName = aNewLinkFilter;
1696 else
1698 uno::Sequence< beans::PropertyValue > aArgs( 1 );
1699 aArgs[0].Name = "URL";
1700 aArgs[0].Value <<= m_aLinkURL;
1701 m_aLinkFilterName = aHelper.UpdateMediaDescriptorWithFilterName( aArgs, false );
1705 if ( aOldLinkFilter != m_aLinkFilterName )
1707 uno::Sequence< beans::NamedValue > aObject = aHelper.GetObjectPropsByFilter( m_aLinkFilterName );
1709 // TODO/LATER: probably the document holder could be cleaned explicitly as in the destructor
1710 m_xDocHolder.clear();
1712 LinkInit_Impl( aObject, lArguments, lObjArgs );
1716 m_aDocMediaDescriptor = GetValuableArgs_Impl( lArguments, true );
1718 // TODO: use lObjArgs for StoreVisualReplacement
1719 for ( sal_Int32 nObjInd = 0; nObjInd < lObjArgs.getLength(); nObjInd++ )
1720 if ( lObjArgs[nObjInd].Name == "OutplaceDispatchInterceptor" )
1722 uno::Reference< frame::XDispatchProviderInterceptor > xDispatchInterceptor;
1723 if ( lObjArgs[nObjInd].Value >>= xDispatchInterceptor )
1724 m_xDocHolder->SetOutplaceDispatchInterceptor( xDispatchInterceptor );
1726 break;
1729 // TODO:
1730 // when document allows reloading through API the object can be reloaded not only in loaded state
1732 bool bOldReadOnlyValue = m_bReadOnly;
1734 m_bReadOnly = false;
1735 for ( sal_Int32 nInd = 0; nInd < lArguments.getLength(); nInd++ )
1736 if ( lArguments[nInd].Name == "ReadOnly" )
1737 lArguments[nInd].Value >>= m_bReadOnly;
1739 if ( bOldReadOnlyValue != m_bReadOnly && !m_bIsLink )
1741 // close own storage
1742 try {
1743 uno::Reference< lang::XComponent > xComponent( m_xObjectStorage, uno::UNO_QUERY );
1744 OSL_ENSURE( !m_xObjectStorage.is() || xComponent.is(), "Wrong storage implementation!" );
1745 if ( xComponent.is() )
1746 xComponent->dispose();
1748 catch ( const uno::Exception& )
1752 sal_Int32 nStorageMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
1753 m_xObjectStorage = m_xParentStorage->openStorageElement( m_aEntryName, nStorageMode );
1757 sal_Bool SAL_CALL OCommonEmbeddedObject::isStored()
1759 uno::Reference<container::XNameAccess> xNA(m_xObjectStorage, uno::UNO_QUERY);
1760 if (!xNA.is())
1761 return false;
1763 return xNA->getElementNames().getLength() > 0;
1767 void SAL_CALL OCommonEmbeddedObject::breakLink( const uno::Reference< embed::XStorage >& xStorage,
1768 const OUString& sEntName )
1770 ::osl::ResettableMutexGuard aGuard( m_aMutex );
1771 if ( m_bDisposed )
1772 throw lang::DisposedException(); // TODO
1774 if ( !m_bIsLink )
1776 // it must be a linked initialized object
1777 throw embed::WrongStateException(
1778 "The object is not a valid linked object!",
1779 static_cast< ::cppu::OWeakObject* >(this) );
1781 // the current implementation of OOo links does not implement this method since it does not implement
1782 // all the set of interfaces required for OOo embedded object ( XEmbedPersist is not supported ).
1784 if ( !xStorage.is() )
1785 throw lang::IllegalArgumentException( "No parent storage is provided!",
1786 static_cast< ::cppu::OWeakObject* >(this),
1787 1 );
1789 if ( sEntName.isEmpty() )
1790 throw lang::IllegalArgumentException( "Empty element name is provided!",
1791 static_cast< ::cppu::OWeakObject* >(this),
1792 2 );
1794 if ( !m_bIsLink || m_nObjectState == -1 )
1796 // it must be a linked initialized object
1797 throw embed::WrongStateException(
1798 "The object is not a valid linked object!",
1799 static_cast< ::cppu::OWeakObject* >(this) );
1802 if ( m_bWaitSaveCompleted )
1803 throw embed::WrongStateException(
1804 "The object waits for saveCompleted() call!",
1805 static_cast< ::cppu::OWeakObject* >(this) );
1807 uno::Reference< container::XNameAccess > xNameAccess( xStorage, uno::UNO_QUERY_THROW );
1809 m_bReadOnly = false;
1811 if ( m_xParentStorage != xStorage || m_aEntryName != sEntName )
1812 SwitchOwnPersistence( xStorage, sEntName );
1814 // for linked object it means that it becomes embedded object
1815 // the document must switch it's persistence also
1817 // TODO/LATER: handle the case when temp doc can not be created
1818 // the document is a new embedded object so it must be marked as modified
1819 uno::Reference< util::XCloseable > xDocument = CreateTempDocFromLink_Impl();
1820 uno::Reference< util::XModifiable > xModif( m_xDocHolder->GetComponent(), uno::UNO_QUERY_THROW );
1823 xModif->setModified( true );
1825 catch( const uno::Exception& )
1828 m_xDocHolder->SetComponent( xDocument, m_bReadOnly );
1829 SAL_WARN_IF( !m_xDocHolder->GetComponent().is(), "embeddedobj.common", "If document can't be created, an exception must be thrown!" );
1831 if ( m_nObjectState == embed::EmbedStates::LOADED )
1833 // the state is changed and can not be switched to loaded state back without saving
1834 m_nObjectState = embed::EmbedStates::RUNNING;
1835 StateChangeNotification_Impl( false, embed::EmbedStates::LOADED, m_nObjectState, aGuard );
1837 else if ( m_nObjectState == embed::EmbedStates::ACTIVE )
1838 m_xDocHolder->Show();
1840 m_bIsLink = false;
1841 m_aLinkFilterName.clear();
1842 m_aLinkURL.clear();
1846 sal_Bool SAL_CALL OCommonEmbeddedObject::isLink()
1848 ::osl::MutexGuard aGuard( m_aMutex );
1849 if ( m_bDisposed )
1850 throw lang::DisposedException(); // TODO
1852 return m_bIsLink;
1856 OUString SAL_CALL OCommonEmbeddedObject::getLinkURL()
1858 ::osl::MutexGuard aGuard( m_aMutex );
1859 if ( m_bDisposed )
1860 throw lang::DisposedException(); // TODO
1862 if ( !m_bIsLink )
1863 throw embed::WrongStateException(
1864 "The object is not a link object!",
1865 static_cast< ::cppu::OWeakObject* >(this) );
1867 return m_aLinkURL;
1870 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */