Version 4.2.0.1, tag libreoffice-4.2.0.1
[LibreOffice.git] / embeddedobj / source / commonembedding / persistence.cxx
blobb3e920884fba1d067f7cac8817d8e72e73cf934f
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>
57 using namespace ::com::sun::star;
60 //------------------------------------------------------
61 uno::Sequence< beans::PropertyValue > GetValuableArgs_Impl( const uno::Sequence< beans::PropertyValue >& aMedDescr,
62 sal_Bool bCanUseDocumentBaseURL )
64 uno::Sequence< beans::PropertyValue > aResult;
65 sal_Int32 nResLen = 0;
67 for ( sal_Int32 nInd = 0; nInd < aMedDescr.getLength(); nInd++ )
69 if ( aMedDescr[nInd].Name == "ComponentData" || aMedDescr[nInd].Name == "DocumentTitle"
70 || aMedDescr[nInd].Name == "InteractionHandler" || aMedDescr[nInd].Name == "JumpMark"
71 // || aMedDescr[nInd].Name == "Password" // makes no sence for embedded objects
72 || aMedDescr[nInd].Name == "Preview" || aMedDescr[nInd].Name == "ReadOnly"
73 || aMedDescr[nInd].Name == "StartPresentation" || aMedDescr[nInd].Name == "RepairPackage"
74 || aMedDescr[nInd].Name == "StatusIndicator" || aMedDescr[nInd].Name == "ViewData"
75 || aMedDescr[nInd].Name == "ViewId" || aMedDescr[nInd].Name == "MacroExecutionMode"
76 || aMedDescr[nInd].Name == "UpdateDocMode"
77 || (aMedDescr[nInd].Name == "DocumentBaseURL" && bCanUseDocumentBaseURL) )
79 aResult.realloc( ++nResLen );
80 aResult[nResLen-1] = aMedDescr[nInd];
84 return aResult;
87 //------------------------------------------------------
88 uno::Sequence< beans::PropertyValue > addAsTemplate( const uno::Sequence< beans::PropertyValue >& aOrig )
90 sal_Bool bAsTemplateSet = sal_False;
91 sal_Int32 nLength = aOrig.getLength();
92 uno::Sequence< beans::PropertyValue > aResult( nLength );
94 for ( sal_Int32 nInd = 0; nInd < nLength; nInd++ )
96 aResult[nInd].Name = aOrig[nInd].Name;
97 if ( aResult[nInd].Name == "AsTemplate" )
99 aResult[nInd].Value <<= sal_True;
100 bAsTemplateSet = sal_True;
102 else
103 aResult[nInd].Value = aOrig[nInd].Value;
106 if ( !bAsTemplateSet )
108 aResult.realloc( nLength + 1 );
109 aResult[nLength].Name = "AsTemplate";
110 aResult[nLength].Value <<= sal_True;
113 return aResult;
116 //------------------------------------------------------
117 uno::Reference< io::XInputStream > createTempInpStreamFromStor(
118 const uno::Reference< embed::XStorage >& xStorage,
119 const uno::Reference< uno::XComponentContext >& xContext )
121 SAL_WARN_IF( !xStorage.is(), "embeddedobj.common", "The storage can not be empty!" );
123 uno::Reference< io::XInputStream > xResult;
125 uno::Reference < io::XStream > xTempStream( io::TempFile::create(xContext), uno::UNO_QUERY_THROW );
127 uno::Reference < lang::XSingleServiceFactory > xStorageFactory( embed::StorageFactory::create(xContext) );
129 uno::Sequence< uno::Any > aArgs( 2 );
130 aArgs[0] <<= xTempStream;
131 aArgs[1] <<= embed::ElementModes::READWRITE;
132 uno::Reference< embed::XStorage > xTempStorage( xStorageFactory->createInstanceWithArguments( aArgs ),
133 uno::UNO_QUERY );
134 if ( !xTempStorage.is() )
135 throw uno::RuntimeException(); // TODO:
139 xStorage->copyToStorage( xTempStorage );
140 } catch( const uno::Exception& e )
142 throw embed::StorageWrappedTargetException(
143 OUString( "Can't copy storage!" ),
144 uno::Reference< uno::XInterface >(),
145 uno::makeAny( e ) );
148 try {
149 uno::Reference< lang::XComponent > xComponent( xTempStorage, uno::UNO_QUERY );
150 SAL_WARN_IF( !xComponent.is(), "embeddedobj.common", "Wrong storage implementation!" );
151 if ( xComponent.is() )
152 xComponent->dispose();
154 catch ( const uno::Exception& )
158 try {
159 uno::Reference< io::XOutputStream > xTempOut = xTempStream->getOutputStream();
160 if ( xTempOut.is() )
161 xTempOut->closeOutput();
163 catch ( const uno::Exception& )
167 xResult = xTempStream->getInputStream();
169 return xResult;
173 //------------------------------------------------------
174 static void TransferMediaType( const uno::Reference< embed::XStorage >& i_rSource, const uno::Reference< embed::XStorage >& i_rTarget )
178 const uno::Reference< beans::XPropertySet > xSourceProps( i_rSource, uno::UNO_QUERY_THROW );
179 const uno::Reference< beans::XPropertySet > xTargetProps( i_rTarget, uno::UNO_QUERY_THROW );
180 const OUString sMediaTypePropName( "MediaType" );
181 xTargetProps->setPropertyValue( sMediaTypePropName, xSourceProps->getPropertyValue( sMediaTypePropName ) );
183 catch( const uno::Exception& )
185 DBG_UNHANDLED_EXCEPTION();
189 //------------------------------------------------------
190 static uno::Reference< util::XCloseable > CreateDocument( const uno::Reference< uno::XComponentContext >& _rxContext,
191 const OUString& _rDocumentServiceName, bool _bEmbeddedScriptSupport, const bool i_bDocumentRecoverySupport )
193 ::comphelper::NamedValueCollection aArguments;
194 aArguments.put( "EmbeddedObject", (sal_Bool)sal_True );
195 aArguments.put( "EmbeddedScriptSupport", (sal_Bool)_bEmbeddedScriptSupport );
196 aArguments.put( "DocumentRecoverySupport", (sal_Bool)i_bDocumentRecoverySupport );
198 uno::Reference< uno::XInterface > xDocument;
201 xDocument = _rxContext->getServiceManager()->createInstanceWithArgumentsAndContext(
202 _rDocumentServiceName, aArguments.getWrappedPropertyValues(), _rxContext );
204 catch( const uno::Exception& )
206 // if an embedded object implementation does not support XInitialization,
207 // the default factory from cppuhelper will throw an
208 // IllegalArgumentException when we try to create the instance with arguments.
209 // Okay, so we fall back to creating the instance without any arguments.
210 OSL_ASSERT("Consider implementing interface XInitialization to avoid duplicate construction");
211 xDocument = _rxContext->getServiceManager()->createInstanceWithContext( _rDocumentServiceName, _rxContext );
214 SAL_WARN_IF(!xDocument.is(), "embeddedobj.common", "Service " << _rDocumentServiceName << " is not available?");
215 return uno::Reference< util::XCloseable >( xDocument, uno::UNO_QUERY );
218 //------------------------------------------------------
219 static void SetDocToEmbedded( const uno::Reference< frame::XModel > xDocument, const OUString& aModuleName )
221 if ( xDocument.is() )
223 uno::Sequence< beans::PropertyValue > aSeq( 1 );
224 aSeq[0].Name = "SetEmbedded";
225 aSeq[0].Value <<= sal_True;
226 xDocument->attachResource( OUString(), aSeq );
228 if ( !aModuleName.isEmpty() )
232 uno::Reference< frame::XModule > xModule( xDocument, uno::UNO_QUERY_THROW );
233 xModule->setIdentifier( aModuleName );
235 catch( const uno::Exception& )
241 //------------------------------------------------------
242 void OCommonEmbeddedObject::SwitchOwnPersistence( const uno::Reference< embed::XStorage >& xNewParentStorage,
243 const uno::Reference< embed::XStorage >& xNewObjectStorage,
244 const OUString& aNewName )
246 if ( xNewParentStorage == m_xParentStorage && aNewName.equals( m_aEntryName ) )
248 SAL_WARN_IF( xNewObjectStorage != m_xObjectStorage, "embeddedobj.common", "The storage must be the same!" );
249 return;
252 uno::Reference< lang::XComponent > xComponent( m_xObjectStorage, uno::UNO_QUERY );
253 OSL_ENSURE( !m_xObjectStorage.is() || xComponent.is(), "Wrong storage implementation!" );
255 m_xObjectStorage = xNewObjectStorage;
256 m_xParentStorage = xNewParentStorage;
257 m_aEntryName = aNewName;
259 // the linked document should not be switched
260 if ( !m_bIsLink )
262 uno::Reference< document::XStorageBasedDocument > xDoc( m_pDocHolder->GetComponent(), uno::UNO_QUERY );
263 if ( xDoc.is() )
264 SwitchDocToStorage_Impl( xDoc, m_xObjectStorage );
267 try {
268 if ( xComponent.is() )
269 xComponent->dispose();
271 catch ( const uno::Exception& )
276 //------------------------------------------------------
277 void OCommonEmbeddedObject::SwitchOwnPersistence( const uno::Reference< embed::XStorage >& xNewParentStorage,
278 const OUString& aNewName )
280 if ( xNewParentStorage == m_xParentStorage && aNewName.equals( m_aEntryName ) )
281 return;
283 sal_Int32 nStorageMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
285 uno::Reference< embed::XStorage > xNewOwnStorage = xNewParentStorage->openStorageElement( aNewName, nStorageMode );
286 SAL_WARN_IF( !xNewOwnStorage.is(), "embeddedobj.common", "The method can not return empty reference!" );
288 SwitchOwnPersistence( xNewParentStorage, xNewOwnStorage, aNewName );
291 //------------------------------------------------------
292 void OCommonEmbeddedObject::EmbedAndReparentDoc_Impl( const uno::Reference< util::XCloseable >& i_rxDocument ) const
294 SetDocToEmbedded( uno::Reference< frame::XModel >( i_rxDocument, uno::UNO_QUERY ), m_aModuleName );
298 uno::Reference < container::XChild > xChild( i_rxDocument, uno::UNO_QUERY );
299 if ( xChild.is() )
300 xChild->setParent( m_xParent );
302 catch( const lang::NoSupportException & )
304 SAL_WARN( "embeddedobj.common", "OCommonEmbeddedObject::EmbedAndReparentDoc: cannot set parent at document!" );
308 //------------------------------------------------------
309 uno::Reference< util::XCloseable > OCommonEmbeddedObject::InitNewDocument_Impl()
311 uno::Reference< util::XCloseable > xDocument( CreateDocument( m_xContext, GetDocumentServiceName(),
312 m_bEmbeddedScriptSupport, m_bDocumentRecoverySupport ) );
314 uno::Reference< frame::XModel > xModel( xDocument, uno::UNO_QUERY );
315 uno::Reference< frame::XLoadable > xLoadable( xModel, uno::UNO_QUERY );
316 if ( !xLoadable.is() )
317 throw uno::RuntimeException();
321 // set the document mode to embedded as the first action on document!!!
322 EmbedAndReparentDoc_Impl( xDocument );
324 // if we have a storage to recover the document from, do not use initNew, but instead load from that storage
325 bool bInitNew = true;
326 if ( m_xRecoveryStorage.is() )
328 uno::Reference< document::XStorageBasedDocument > xDoc( xLoadable, uno::UNO_QUERY );
329 SAL_WARN_IF( !xDoc.is(), "embeddedobj.common", "OCommonEmbeddedObject::InitNewDocument_Impl: cannot recover from a storage when the document is not storage based!" );
330 if ( xDoc.is() )
332 ::comphelper::NamedValueCollection aLoadArgs;
333 FillDefaultLoadArgs_Impl( m_xRecoveryStorage, aLoadArgs );
335 xDoc->loadFromStorage( m_xRecoveryStorage, aLoadArgs.getPropertyValues() );
336 SwitchDocToStorage_Impl( xDoc, m_xObjectStorage );
337 bInitNew = false;
341 if ( bInitNew )
343 // init document as a new
344 xLoadable->initNew();
346 xModel->attachResource( xModel->getURL(), m_aDocMediaDescriptor );
348 catch( const uno::Exception& )
350 uno::Reference< util::XCloseable > xCloseable( xDocument, uno::UNO_QUERY );
351 if ( xCloseable.is() )
355 xCloseable->close( sal_True );
357 catch( const uno::Exception& )
362 throw; // TODO
365 return xDocument;
368 //------------------------------------------------------
369 uno::Reference< util::XCloseable > OCommonEmbeddedObject::LoadLink_Impl()
371 uno::Reference< util::XCloseable > xDocument( CreateDocument( m_xContext, GetDocumentServiceName(),
372 m_bEmbeddedScriptSupport, m_bDocumentRecoverySupport ) );
374 uno::Reference< frame::XLoadable > xLoadable( xDocument, uno::UNO_QUERY );
375 if ( !xLoadable.is() )
376 throw uno::RuntimeException();
378 sal_Int32 nLen = 2;
379 uno::Sequence< beans::PropertyValue > aArgs( nLen );
380 aArgs[0].Name = "URL";
381 aArgs[0].Value <<= m_aLinkURL;
382 aArgs[1].Name = "FilterName";
383 aArgs[1].Value <<= m_aLinkFilterName;
384 if ( m_bLinkHasPassword )
386 aArgs.realloc( ++nLen );
387 aArgs[nLen-1].Name = "Password";
388 aArgs[nLen-1].Value <<= m_aLinkPassword;
391 aArgs.realloc( m_aDocMediaDescriptor.getLength() + nLen );
392 for ( sal_Int32 nInd = 0; nInd < m_aDocMediaDescriptor.getLength(); nInd++ )
394 aArgs[nInd+nLen].Name = m_aDocMediaDescriptor[nInd].Name;
395 aArgs[nInd+nLen].Value = m_aDocMediaDescriptor[nInd].Value;
400 // the document is not really an embedded one, it is a link
401 EmbedAndReparentDoc_Impl( xDocument );
403 // load the document
404 xLoadable->load( aArgs );
406 if ( !m_bLinkHasPassword )
408 // check if there is a password to cache
409 uno::Reference< frame::XModel > xModel( xLoadable, uno::UNO_QUERY_THROW );
410 uno::Sequence< beans::PropertyValue > aProps = xModel->getArgs();
411 for ( sal_Int32 nInd = 0; nInd < aProps.getLength(); nInd++ )
412 if ( aProps[nInd].Name == "Password" && ( aProps[nInd].Value >>= m_aLinkPassword ) )
414 m_bLinkHasPassword = sal_True;
415 break;
419 catch( const uno::Exception& )
421 uno::Reference< util::XCloseable > xCloseable( xDocument, uno::UNO_QUERY );
422 if ( xCloseable.is() )
426 xCloseable->close( sal_True );
428 catch( const uno::Exception& )
433 throw; // TODO
436 return xDocument;
440 //------------------------------------------------------
441 OUString OCommonEmbeddedObject::GetFilterName( sal_Int32 nVersion ) const
443 OUString aFilterName = GetPresetFilterName();
444 if ( aFilterName.isEmpty() )
446 try {
447 ::comphelper::MimeConfigurationHelper aHelper( m_xContext );
448 aFilterName = aHelper.GetDefaultFilterFromServiceName( GetDocumentServiceName(), nVersion );
449 } catch( const uno::Exception& )
453 return aFilterName;
456 //------------------------------------------------------
457 void OCommonEmbeddedObject::FillDefaultLoadArgs_Impl( const uno::Reference< embed::XStorage >& i_rxStorage,
458 ::comphelper::NamedValueCollection& o_rLoadArgs ) const
460 o_rLoadArgs.put( "DocumentBaseURL", GetBaseURL_Impl() );
461 o_rLoadArgs.put( "HierarchicalDocumentName", m_aEntryName );
462 o_rLoadArgs.put( "ReadOnly", m_bReadOnly );
464 OUString aFilterName = GetFilterName( ::comphelper::OStorageHelper::GetXStorageFormat( i_rxStorage ) );
465 SAL_WARN_IF( aFilterName.isEmpty(), "embeddedobj.common", "OCommonEmbeddedObject::FillDefaultLoadArgs_Impl: Wrong document service name!" );
466 if ( aFilterName.isEmpty() )
467 throw io::IOException(); // TODO: error message/code
469 o_rLoadArgs.put( "FilterName", aFilterName );
472 //------------------------------------------------------
473 uno::Reference< util::XCloseable > OCommonEmbeddedObject::LoadDocumentFromStorage_Impl()
475 ENSURE_OR_THROW( m_xObjectStorage.is(), "no object storage" );
477 const uno::Reference< embed::XStorage > xSourceStorage( m_xRecoveryStorage.is() ? m_xRecoveryStorage : m_xObjectStorage );
479 uno::Reference< util::XCloseable > xDocument( CreateDocument( m_xContext, GetDocumentServiceName(),
480 m_bEmbeddedScriptSupport, m_bDocumentRecoverySupport ) );
482 //#i103460# ODF: take the size given from the parent frame as default
483 uno::Reference< chart2::XChartDocument > xChart( xDocument, uno::UNO_QUERY );
484 if( xChart.is() )
486 uno::Reference< embed::XVisualObject > xChartVisualObject( xChart, uno::UNO_QUERY );
487 if( xChartVisualObject.is() )
488 xChartVisualObject->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT, m_aDefaultSizeForChart_In_100TH_MM );
491 uno::Reference< frame::XLoadable > xLoadable( xDocument, uno::UNO_QUERY );
492 uno::Reference< document::XStorageBasedDocument > xDoc( xDocument, uno::UNO_QUERY );
493 if ( !xDoc.is() && !xLoadable.is() ) ///BUG: This should be || instead of && ?
494 throw uno::RuntimeException();
496 ::comphelper::NamedValueCollection aLoadArgs;
497 FillDefaultLoadArgs_Impl( xSourceStorage, aLoadArgs );
499 uno::Reference< io::XInputStream > xTempInpStream;
500 if ( !xDoc.is() )
502 xTempInpStream = createTempInpStreamFromStor( xSourceStorage, m_xContext );
503 if ( !xTempInpStream.is() )
504 throw uno::RuntimeException();
506 OUString aTempFileURL;
509 // no need to let the file stay after the stream is removed since the embedded document
510 // can not be stored directly
511 uno::Reference< beans::XPropertySet > xTempStreamProps( xTempInpStream, uno::UNO_QUERY_THROW );
512 xTempStreamProps->getPropertyValue("Uri") >>= aTempFileURL;
514 catch( const uno::Exception& )
518 SAL_WARN_IF( aTempFileURL.isEmpty(), "embeddedobj.common", "Coudn't retrieve temporary file URL!" );
520 aLoadArgs.put( "URL", aTempFileURL );
521 aLoadArgs.put( "InputStream", xTempInpStream );
525 aLoadArgs.merge( m_aDocMediaDescriptor, true );
529 // set the document mode to embedded as the first step!!!
530 EmbedAndReparentDoc_Impl( xDocument );
532 if ( xDoc.is() )
534 xDoc->loadFromStorage( xSourceStorage, aLoadArgs.getPropertyValues() );
535 if ( xSourceStorage != m_xObjectStorage )
536 SwitchDocToStorage_Impl( xDoc, m_xObjectStorage );
538 else
539 xLoadable->load( aLoadArgs.getPropertyValues() );
541 catch( const uno::Exception& )
543 uno::Reference< util::XCloseable > xCloseable( xDocument, uno::UNO_QUERY );
544 if ( xCloseable.is() )
548 xCloseable->close( sal_True );
550 catch( const uno::Exception& )
552 DBG_UNHANDLED_EXCEPTION();
556 throw; // TODO
559 return xDocument;
562 //------------------------------------------------------
563 uno::Reference< io::XInputStream > OCommonEmbeddedObject::StoreDocumentToTempStream_Impl(
564 sal_Int32 nStorageFormat,
565 const OUString& aBaseURL,
566 const OUString& aHierarchName )
568 uno::Reference < io::XOutputStream > xTempOut(
569 io::TempFile::create(m_xContext),
570 uno::UNO_QUERY_THROW );
571 uno::Reference< io::XInputStream > aResult( xTempOut, uno::UNO_QUERY );
573 if ( !aResult.is() )
574 throw uno::RuntimeException(); // TODO:
576 uno::Reference< frame::XStorable > xStorable;
578 osl::MutexGuard aGuard( m_aMutex );
579 if ( m_pDocHolder )
580 xStorable = uno::Reference< frame::XStorable > ( m_pDocHolder->GetComponent(), uno::UNO_QUERY );
583 if( !xStorable.is() )
584 throw uno::RuntimeException(); // TODO:
586 OUString aFilterName = GetFilterName( nStorageFormat );
588 SAL_WARN_IF( aFilterName.isEmpty(), "embeddedobj.common", "Wrong document service name!" );
589 if ( aFilterName.isEmpty() )
590 throw io::IOException(); // TODO:
592 uno::Sequence< beans::PropertyValue > aArgs( 4 );
593 aArgs[0].Name = "FilterName";
594 aArgs[0].Value <<= aFilterName;
595 aArgs[1].Name = "OutputStream";
596 aArgs[1].Value <<= xTempOut;
597 aArgs[2].Name = "DocumentBaseURL";
598 aArgs[2].Value <<= aBaseURL;
599 aArgs[3].Name = "HierarchicalDocumentName";
600 aArgs[3].Value <<= aHierarchName;
602 xStorable->storeToURL( OUString( "private:stream" ), aArgs );
605 xTempOut->closeOutput();
607 catch( const uno::Exception& )
609 SAL_WARN( "embeddedobj.common", "Looks like stream was closed already" );
612 return aResult;
615 //------------------------------------------------------
616 void OCommonEmbeddedObject::SaveObject_Impl()
618 if ( m_xClientSite.is() )
622 // check whether the component is modified,
623 // if not there is no need for storing
624 uno::Reference< util::XModifiable > xModifiable( m_pDocHolder->GetComponent(), uno::UNO_QUERY );
625 if ( xModifiable.is() && !xModifiable->isModified() )
626 return;
628 catch( const uno::Exception& )
631 try {
632 m_xClientSite->saveObject();
634 catch( const uno::Exception& )
636 SAL_WARN( "embeddedobj.common", "The object was not stored!" );
641 //------------------------------------------------------
642 OUString OCommonEmbeddedObject::GetBaseURL_Impl() const
644 OUString aBaseURL;
645 sal_Int32 nInd = 0;
647 if ( m_xClientSite.is() )
651 uno::Reference< frame::XModel > xParentModel( m_xClientSite->getComponent(), uno::UNO_QUERY_THROW );
652 uno::Sequence< beans::PropertyValue > aModelProps = xParentModel->getArgs();
653 for ( nInd = 0; nInd < aModelProps.getLength(); nInd++ )
654 if ( aModelProps[nInd].Name.equals(
655 OUString( "DocumentBaseURL" ) ) )
657 aModelProps[nInd].Value >>= aBaseURL;
658 break;
663 catch( const uno::Exception& )
667 if ( aBaseURL.isEmpty() )
669 for ( nInd = 0; nInd < m_aDocMediaDescriptor.getLength(); nInd++ )
670 if ( m_aDocMediaDescriptor[nInd].Name.equals(
671 OUString( "DocumentBaseURL" ) ) )
673 m_aDocMediaDescriptor[nInd].Value >>= aBaseURL;
674 break;
678 if ( aBaseURL.isEmpty() )
679 aBaseURL = m_aDefaultParentBaseURL;
681 return aBaseURL;
684 //------------------------------------------------------
685 OUString OCommonEmbeddedObject::GetBaseURLFrom_Impl(
686 const uno::Sequence< beans::PropertyValue >& lArguments,
687 const uno::Sequence< beans::PropertyValue >& lObjArgs )
689 OUString aBaseURL;
690 sal_Int32 nInd = 0;
692 for ( nInd = 0; nInd < lArguments.getLength(); nInd++ )
693 if ( lArguments[nInd].Name == "DocumentBaseURL" )
695 lArguments[nInd].Value >>= aBaseURL;
696 break;
699 if ( aBaseURL.isEmpty() )
701 for ( nInd = 0; nInd < lObjArgs.getLength(); nInd++ )
702 if ( lObjArgs[nInd].Name == "DefaultParentBaseURL" )
704 lObjArgs[nInd].Value >>= aBaseURL;
705 break;
709 return aBaseURL;
713 //------------------------------------------------------
714 void OCommonEmbeddedObject::SwitchDocToStorage_Impl( const uno::Reference< document::XStorageBasedDocument >& xDoc, const uno::Reference< embed::XStorage >& xStorage )
716 xDoc->switchToStorage( xStorage );
718 uno::Reference< util::XModifiable > xModif( xDoc, uno::UNO_QUERY );
719 if ( xModif.is() )
720 xModif->setModified( sal_False );
722 if ( m_xRecoveryStorage.is() )
723 m_xRecoveryStorage.clear();
726 //------------------------------------------------------
727 void OCommonEmbeddedObject::StoreDocToStorage_Impl( const uno::Reference< embed::XStorage >& xStorage,
728 sal_Int32 nStorageFormat,
729 const OUString& aBaseURL,
730 const OUString& aHierarchName,
731 sal_Bool bAttachToTheStorage )
733 SAL_WARN_IF( !xStorage.is(), "embeddedobj.common", "No storage is provided for storing!" );
735 if ( !xStorage.is() )
736 throw uno::RuntimeException(); // TODO:
738 uno::Reference< document::XStorageBasedDocument > xDoc;
740 osl::MutexGuard aGuard( m_aMutex );
741 if ( m_pDocHolder )
742 xDoc = uno::Reference< document::XStorageBasedDocument >( m_pDocHolder->GetComponent(), uno::UNO_QUERY );
745 if ( xDoc.is() )
747 OUString aFilterName = GetFilterName( nStorageFormat );
749 SAL_WARN_IF( aFilterName.isEmpty(), "embeddedobj.common", "Wrong document service name!" );
750 if ( aFilterName.isEmpty() )
751 throw io::IOException(); // TODO:
753 uno::Sequence< beans::PropertyValue > aArgs( 3 );
754 aArgs[0].Name = "FilterName";
755 aArgs[0].Value <<= aFilterName;
756 aArgs[2].Name = "DocumentBaseURL";
757 aArgs[2].Value <<= aBaseURL;
758 aArgs[1].Name = "HierarchicalDocumentName";
759 aArgs[1].Value <<= aHierarchName;
761 xDoc->storeToStorage( xStorage, aArgs );
762 if ( bAttachToTheStorage )
763 SwitchDocToStorage_Impl( xDoc, xStorage );
765 else
767 // store document to temporary stream based on temporary file
768 uno::Reference < io::XInputStream > xTempIn = StoreDocumentToTempStream_Impl( nStorageFormat, aBaseURL, aHierarchName );
770 SAL_WARN_IF( !xTempIn.is(), "embeddedobj.common", "The stream reference can not be empty!" );
772 // open storage based on document temporary file for reading
773 uno::Reference < lang::XSingleServiceFactory > xStorageFactory = embed::StorageFactory::create(m_xContext);
775 uno::Sequence< uno::Any > aArgs(1);
776 aArgs[0] <<= xTempIn;
777 uno::Reference< embed::XStorage > xTempStorage( xStorageFactory->createInstanceWithArguments( aArgs ),
778 uno::UNO_QUERY );
779 if ( !xTempStorage.is() )
780 throw uno::RuntimeException(); // TODO:
782 // object storage must be commited automatically
783 xTempStorage->copyToStorage( xStorage );
787 //------------------------------------------------------
788 uno::Reference< util::XCloseable > OCommonEmbeddedObject::CreateDocFromMediaDescr_Impl(
789 const uno::Sequence< beans::PropertyValue >& aMedDescr )
791 uno::Reference< util::XCloseable > xDocument( CreateDocument( m_xContext, GetDocumentServiceName(),
792 m_bEmbeddedScriptSupport, m_bDocumentRecoverySupport ) );
794 uno::Reference< frame::XLoadable > xLoadable( xDocument, uno::UNO_QUERY );
795 if ( !xLoadable.is() )
796 throw uno::RuntimeException();
800 // set the document mode to embedded as the first action on the document!!!
801 EmbedAndReparentDoc_Impl( xDocument );
803 xLoadable->load( addAsTemplate( aMedDescr ) );
805 catch( const uno::Exception& )
807 uno::Reference< util::XCloseable > xCloseable( xDocument, uno::UNO_QUERY );
808 if ( xCloseable.is() )
812 xCloseable->close( sal_True );
814 catch( const uno::Exception& )
819 throw; // TODO
822 return xDocument;
825 //------------------------------------------------------
826 uno::Reference< util::XCloseable > OCommonEmbeddedObject::CreateTempDocFromLink_Impl()
828 uno::Reference< util::XCloseable > xResult;
830 SAL_WARN_IF( !m_bIsLink, "embeddedobj.common", "The object is not a linked one!" );
832 uno::Sequence< beans::PropertyValue > aTempMediaDescr;
834 sal_Int32 nStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
835 try {
836 nStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage );
838 catch ( const beans::IllegalTypeException& )
840 // the container just has an unknown type, use current file format
842 catch ( const uno::Exception& )
844 SAL_WARN( "embeddedobj.common", "Can not retrieve storage media type!" );
847 if ( m_pDocHolder->GetComponent().is() )
849 aTempMediaDescr.realloc( 4 );
851 // TODO/LATER: may be private:stream should be used as target URL
852 OUString aTempFileURL;
853 uno::Reference< io::XInputStream > xTempStream = StoreDocumentToTempStream_Impl( SOFFICE_FILEFORMAT_CURRENT,
854 OUString(),
855 OUString() );
858 // no need to let the file stay after the stream is removed since the embedded document
859 // can not be stored directly
860 uno::Reference< beans::XPropertySet > xTempStreamProps( xTempStream, uno::UNO_QUERY_THROW );
861 xTempStreamProps->getPropertyValue("Uri") >>= aTempFileURL;
863 catch( const uno::Exception& )
867 SAL_WARN_IF( aTempFileURL.isEmpty(), "embeddedobj.common", "Couldn't retrieve temporary file URL!" );
869 aTempMediaDescr[0].Name = "URL";
870 aTempMediaDescr[0].Value <<= aTempFileURL;
871 aTempMediaDescr[1].Name = "InputStream";
872 aTempMediaDescr[1].Value <<= xTempStream;
873 aTempMediaDescr[2].Name = "FilterName";
874 aTempMediaDescr[2].Value <<= GetFilterName( nStorageFormat );
875 aTempMediaDescr[3].Name = "AsTemplate";
876 aTempMediaDescr[3].Value <<= sal_True;
878 else
880 aTempMediaDescr.realloc( 2 );
881 aTempMediaDescr[0].Name = "URL";
882 aTempMediaDescr[0].Value <<= m_aLinkURL;
883 aTempMediaDescr[1].Name = "FilterName";
884 aTempMediaDescr[1].Value <<= m_aLinkFilterName;
887 xResult = CreateDocFromMediaDescr_Impl( aTempMediaDescr );
889 return xResult;
892 //------------------------------------------------------
893 void SAL_CALL OCommonEmbeddedObject::setPersistentEntry(
894 const uno::Reference< embed::XStorage >& xStorage,
895 const OUString& sEntName,
896 sal_Int32 nEntryConnectionMode,
897 const uno::Sequence< beans::PropertyValue >& lArguments,
898 const uno::Sequence< beans::PropertyValue >& lObjArgs )
899 throw ( lang::IllegalArgumentException,
900 embed::WrongStateException,
901 io::IOException,
902 uno::Exception,
903 uno::RuntimeException )
905 SAL_INFO( "embeddedobj.common", "embeddedobj (mv76033) OCommonEmbeddedObject::setPersistentEntry" );
907 // the type of the object must be already set
908 // a kind of typedetection should be done in the factory
910 ::osl::MutexGuard aGuard( m_aMutex );
911 if ( m_bDisposed )
912 throw lang::DisposedException(); // TODO
914 if ( !xStorage.is() )
915 throw lang::IllegalArgumentException( OUString( "No parent storage is provided!\n" ),
916 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ),
917 1 );
919 if ( sEntName.isEmpty() )
920 throw lang::IllegalArgumentException( OUString( "Empty element name is provided!\n" ),
921 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ),
922 2 );
924 // May be LOADED should be forbidden here ???
925 if ( ( m_nObjectState != -1 || nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
926 && ( m_nObjectState == -1 || nEntryConnectionMode != embed::EntryInitModes::NO_INIT ) )
928 // if the object is not loaded
929 // it can not get persistent representation without initialization
931 // if the object is loaded
932 // it can switch persistent representation only without initialization
934 throw embed::WrongStateException(
935 OUString( "Can't change persistent representation of activated object!\n" ),
936 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
939 if ( m_bWaitSaveCompleted )
941 if ( nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
943 // saveCompleted is expected, handle it accordingly
944 if ( m_xNewParentStorage == xStorage && m_aNewEntryName.equals( sEntName ) )
946 saveCompleted( sal_True );
947 return;
950 // if a completely different entry is provided, switch first back to the old persistence in saveCompleted
951 // and then switch to the target persistence
952 sal_Bool bSwitchFurther = ( m_xParentStorage != xStorage || !m_aEntryName.equals( sEntName ) );
953 saveCompleted( sal_False );
954 if ( !bSwitchFurther )
955 return;
957 else
958 throw embed::WrongStateException(
959 OUString( "The object waits for saveCompleted() call!\n" ),
960 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
963 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
964 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
965 // OSL_ENSURE( !m_bIsLink, "This method implementation must not be used for links!\n" );
966 if ( m_bIsLink )
968 m_aEntryName = sEntName;
969 return;
972 uno::Reference< container::XNameAccess > xNameAccess( xStorage, uno::UNO_QUERY );
973 if ( !xNameAccess.is() )
974 throw uno::RuntimeException(); //TODO
976 // detect entry existence
977 sal_Bool bElExists = xNameAccess->hasByName( sEntName );
979 m_aDocMediaDescriptor = GetValuableArgs_Impl( lArguments,
980 nEntryConnectionMode != embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT );
982 m_bReadOnly = sal_False;
983 for ( sal_Int32 nInd = 0; nInd < lArguments.getLength(); nInd++ )
984 if ( lArguments[nInd].Name == "ReadOnly" )
985 lArguments[nInd].Value >>= m_bReadOnly;
987 // TODO: use lObjArgs for StoreVisualReplacement
988 for ( sal_Int32 nObjInd = 0; nObjInd < lObjArgs.getLength(); nObjInd++ )
989 if ( lObjArgs[nObjInd].Name == "OutplaceDispatchInterceptor" )
991 uno::Reference< frame::XDispatchProviderInterceptor > xDispatchInterceptor;
992 if ( lObjArgs[nObjInd].Value >>= xDispatchInterceptor )
993 m_pDocHolder->SetOutplaceDispatchInterceptor( xDispatchInterceptor );
995 else if ( lObjArgs[nObjInd].Name == "DefaultParentBaseURL" )
997 lObjArgs[nObjInd].Value >>= m_aDefaultParentBaseURL;
999 else if ( lObjArgs[nObjInd].Name == "Parent" )
1001 lObjArgs[nObjInd].Value >>= m_xParent;
1003 else if ( lObjArgs[nObjInd].Name == "IndividualMiscStatus" )
1005 sal_Int64 nMiscStatus=0;
1006 lObjArgs[nObjInd].Value >>= nMiscStatus;
1007 m_nMiscStatus |= nMiscStatus;
1009 else if ( lObjArgs[nObjInd].Name == "CloneFrom" )
1011 uno::Reference < embed::XEmbeddedObject > xObj;
1012 lObjArgs[nObjInd].Value >>= xObj;
1013 if ( xObj.is() )
1015 m_bHasClonedSize = sal_True;
1016 m_aClonedSize = xObj->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT );
1017 m_nClonedMapUnit = xObj->getMapUnit( embed::Aspects::MSOLE_CONTENT );
1020 else if ( lObjArgs[nObjInd].Name == "OutplaceFrameProperties" )
1022 uno::Sequence< uno::Any > aOutFrameProps;
1023 uno::Sequence< beans::NamedValue > aOutFramePropsTyped;
1024 if ( lObjArgs[nObjInd].Value >>= aOutFrameProps )
1026 m_pDocHolder->SetOutplaceFrameProperties( aOutFrameProps );
1028 else if ( lObjArgs[nObjInd].Value >>= aOutFramePropsTyped )
1030 aOutFrameProps.realloc( aOutFramePropsTyped.getLength() );
1031 uno::Any* pProp = aOutFrameProps.getArray();
1032 for ( const beans::NamedValue* pTypedProp = aOutFramePropsTyped.getConstArray();
1033 pTypedProp != aOutFramePropsTyped.getConstArray() + aOutFramePropsTyped.getLength();
1034 ++pTypedProp, ++pProp
1037 *pProp <<= *pTypedProp;
1039 m_pDocHolder->SetOutplaceFrameProperties( aOutFrameProps );
1041 else
1042 SAL_WARN( "embeddedobj.common", "OCommonEmbeddedObject::setPersistentEntry: illegal type for argument 'OutplaceFrameProperties'!" );
1044 else if ( lObjArgs[nObjInd].Name == "ModuleName" )
1046 lObjArgs[nObjInd].Value >>= m_aModuleName;
1048 else if ( lObjArgs[nObjInd].Name == "EmbeddedScriptSupport" )
1050 OSL_VERIFY( lObjArgs[nObjInd].Value >>= m_bEmbeddedScriptSupport );
1052 else if ( lObjArgs[nObjInd].Name == "DocumentRecoverySupport" )
1054 OSL_VERIFY( lObjArgs[nObjInd].Value >>= m_bDocumentRecoverySupport );
1056 else if ( lObjArgs[nObjInd].Name == "RecoveryStorage" )
1058 OSL_VERIFY( lObjArgs[nObjInd].Value >>= m_xRecoveryStorage );
1062 sal_Int32 nStorageMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
1064 SwitchOwnPersistence( xStorage, sEntName );
1066 if ( nEntryConnectionMode == embed::EntryInitModes::DEFAULT_INIT )
1068 if ( bElExists )
1070 // the initialization from existing storage allows to leave object in loaded state
1071 m_nObjectState = embed::EmbedStates::LOADED;
1073 else
1075 m_pDocHolder->SetComponent( InitNewDocument_Impl(), m_bReadOnly );
1076 if ( !m_pDocHolder->GetComponent().is() )
1077 throw io::IOException(); // TODO: can not create document
1079 m_nObjectState = embed::EmbedStates::RUNNING;
1082 else
1084 if ( ( nStorageMode & embed::ElementModes::READWRITE ) != embed::ElementModes::READWRITE )
1085 throw io::IOException();
1087 if ( nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
1089 // the document just already changed its storage to store to
1090 // the links to OOo documents for now ignore this call
1091 // TODO: OOo links will have persistence so it will be switched here
1093 else if ( nEntryConnectionMode == embed::EntryInitModes::TRUNCATE_INIT )
1095 if ( m_xRecoveryStorage.is() )
1096 TransferMediaType( m_xRecoveryStorage, m_xObjectStorage );
1098 // TODO:
1099 m_pDocHolder->SetComponent( InitNewDocument_Impl(), m_bReadOnly );
1101 if ( !m_pDocHolder->GetComponent().is() )
1102 throw io::IOException(); // TODO: can not create document
1104 m_nObjectState = embed::EmbedStates::RUNNING;
1106 else if ( nEntryConnectionMode == embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT )
1108 m_pDocHolder->SetComponent( CreateDocFromMediaDescr_Impl( lArguments ), m_bReadOnly );
1109 m_nObjectState = embed::EmbedStates::RUNNING;
1111 //else if ( nEntryConnectionMode == embed::EntryInitModes::TRANSFERABLE_INIT )
1113 //TODO:
1115 else
1116 throw lang::IllegalArgumentException( OUString( "Wrong connection mode is provided!\n" ),
1117 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ),
1118 3 );
1122 //------------------------------------------------------
1123 void SAL_CALL OCommonEmbeddedObject::storeToEntry( const uno::Reference< embed::XStorage >& xStorage,
1124 const OUString& sEntName,
1125 const uno::Sequence< beans::PropertyValue >& lArguments,
1126 const uno::Sequence< beans::PropertyValue >& lObjArgs )
1127 throw ( lang::IllegalArgumentException,
1128 embed::WrongStateException,
1129 io::IOException,
1130 uno::Exception,
1131 uno::RuntimeException )
1133 SAL_INFO( "embeddedobj.common", "embeddedobj (mv76033) OCommonEmbeddedObject::storeToEntry" );
1135 ::osl::ResettableMutexGuard aGuard( m_aMutex );
1136 if ( m_bDisposed )
1137 throw lang::DisposedException(); // TODO
1139 if ( m_nObjectState == -1 )
1141 // the object is still not loaded
1142 throw embed::WrongStateException( OUString( "Can't store object without persistence!\n" ),
1143 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1146 if ( m_bWaitSaveCompleted )
1147 throw embed::WrongStateException(
1148 OUString( "The object waits for saveCompleted() call!\n" ),
1149 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1151 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1152 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1153 // OSL_ENSURE( !m_bIsLink, "This method implementation must not be used for links!\n" );
1154 if ( m_bIsLink )
1155 return;
1157 OSL_ENSURE( m_xParentStorage.is() && m_xObjectStorage.is(), "The object has no valid persistence!\n" );
1159 sal_Int32 nTargetStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1160 sal_Int32 nOriginalStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1161 try {
1162 nTargetStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( xStorage );
1164 catch ( const beans::IllegalTypeException& )
1166 // the container just has an unknown type, use current file format
1168 catch ( const uno::Exception& )
1170 SAL_WARN( "embeddedobj.common", "Can not retrieve target storage media type!" );
1175 nOriginalStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage );
1177 catch ( const beans::IllegalTypeException& )
1179 // the container just has an unknown type, use current file format
1181 catch ( const uno::Exception& )
1183 SAL_WARN( "embeddedobj.common", "Can not retrieve own storage media type!" );
1186 sal_Bool bTryOptimization = sal_False;
1187 for ( sal_Int32 nInd = 0; nInd < lObjArgs.getLength(); nInd++ )
1189 // StoreVisualReplacement and VisualReplacement args have no sence here
1190 if ( lObjArgs[nInd].Name == "CanTryOptimization" )
1191 lObjArgs[nInd].Value >>= bTryOptimization;
1194 sal_Bool bSwitchBackToLoaded = sal_False;
1196 // Storing to different format can be done only in running state.
1197 if ( m_nObjectState == embed::EmbedStates::LOADED )
1199 // TODO/LATER: copying is not legal for documents with relative links.
1200 if ( nTargetStorageFormat == nOriginalStorageFormat )
1202 sal_Bool bOptimizationWorks = sal_False;
1203 if ( bTryOptimization )
1207 // try to use optimized copying
1208 uno::Reference< embed::XOptimizedStorage > xSource( m_xParentStorage, uno::UNO_QUERY_THROW );
1209 uno::Reference< embed::XOptimizedStorage > xTarget( xStorage, uno::UNO_QUERY_THROW );
1210 xSource->copyElementDirectlyTo( m_aEntryName, xTarget, sEntName );
1211 bOptimizationWorks = sal_True;
1213 catch( const uno::Exception& )
1218 if ( !bOptimizationWorks )
1219 m_xParentStorage->copyElementTo( m_aEntryName, xStorage, sEntName );
1221 else
1223 changeState( embed::EmbedStates::RUNNING );
1224 bSwitchBackToLoaded = sal_True;
1228 if ( m_nObjectState != embed::EmbedStates::LOADED )
1230 uno::Reference< embed::XStorage > xSubStorage =
1231 xStorage->openStorageElement( sEntName, embed::ElementModes::READWRITE );
1233 if ( !xSubStorage.is() )
1234 throw uno::RuntimeException(); //TODO
1236 aGuard.clear();
1237 // TODO/LATER: support hierarchical name for embedded objects in embedded objects
1238 StoreDocToStorage_Impl( xSubStorage, nTargetStorageFormat, GetBaseURLFrom_Impl( lArguments, lObjArgs ), sEntName, sal_False );
1239 aGuard.reset();
1241 if ( bSwitchBackToLoaded )
1242 changeState( embed::EmbedStates::LOADED );
1245 // TODO: should the listener notification be done?
1248 //------------------------------------------------------
1249 void SAL_CALL OCommonEmbeddedObject::storeAsEntry( const uno::Reference< embed::XStorage >& xStorage,
1250 const OUString& sEntName,
1251 const uno::Sequence< beans::PropertyValue >& lArguments,
1252 const uno::Sequence< beans::PropertyValue >& lObjArgs )
1253 throw ( lang::IllegalArgumentException,
1254 embed::WrongStateException,
1255 io::IOException,
1256 uno::Exception,
1257 uno::RuntimeException )
1259 SAL_INFO( "embeddedobj.common", "embeddedobj (mv76033) OCommonEmbeddedObject::storeAsEntry" );
1261 // TODO: use lObjArgs
1263 ::osl::ResettableMutexGuard aGuard( m_aMutex );
1264 if ( m_bDisposed )
1265 throw lang::DisposedException(); // TODO
1267 if ( m_nObjectState == -1 )
1269 // the object is still not loaded
1270 throw embed::WrongStateException( OUString( "Can't store object without persistence!\n" ),
1271 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1274 if ( m_bWaitSaveCompleted )
1275 throw embed::WrongStateException(
1276 OUString( "The object waits for saveCompleted() call!\n" ),
1277 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1279 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1280 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1281 // OSL_ENSURE( !m_bIsLink, "This method implementation must not be used for links!\n" );
1282 if ( m_bIsLink )
1284 m_aNewEntryName = sEntName;
1285 return;
1288 OSL_ENSURE( m_xParentStorage.is() && m_xObjectStorage.is(), "The object has no valid persistence!\n" );
1290 sal_Int32 nTargetStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1291 sal_Int32 nOriginalStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1292 try {
1293 nTargetStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( xStorage );
1295 catch ( const beans::IllegalTypeException& )
1297 // the container just has an unknown type, use current file format
1299 catch ( const uno::Exception& )
1301 SAL_WARN( "embeddedobj.common", "Can not retrieve target storage media type!" );
1306 nOriginalStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage );
1308 catch ( const beans::IllegalTypeException& )
1310 // the container just has an unknown type, use current file format
1312 catch ( const uno::Exception& )
1314 SAL_WARN( "embeddedobj.common", "Can not retrieve own storage media type!" );
1317 PostEvent_Impl( OUString( "OnSaveAs" ) );
1319 sal_Bool bTryOptimization = sal_False;
1320 for ( sal_Int32 nInd = 0; nInd < lObjArgs.getLength(); nInd++ )
1322 // StoreVisualReplacement and VisualReplacement args have no sence here
1323 if ( lObjArgs[nInd].Name == "CanTryOptimization" )
1324 lObjArgs[nInd].Value >>= bTryOptimization;
1327 sal_Bool bSwitchBackToLoaded = sal_False;
1329 // Storing to different format can be done only in running state.
1330 if ( m_nObjectState == embed::EmbedStates::LOADED )
1332 // TODO/LATER: copying is not legal for documents with relative links.
1333 if ( nTargetStorageFormat == nOriginalStorageFormat )
1335 sal_Bool bOptimizationWorks = sal_False;
1336 if ( bTryOptimization )
1340 // try to use optimized copying
1341 uno::Reference< embed::XOptimizedStorage > xSource( m_xParentStorage, uno::UNO_QUERY_THROW );
1342 uno::Reference< embed::XOptimizedStorage > xTarget( xStorage, uno::UNO_QUERY_THROW );
1343 xSource->copyElementDirectlyTo( m_aEntryName, xTarget, sEntName );
1344 bOptimizationWorks = sal_True;
1346 catch( const uno::Exception& )
1351 if ( !bOptimizationWorks )
1352 m_xParentStorage->copyElementTo( m_aEntryName, xStorage, sEntName );
1354 else
1356 changeState( embed::EmbedStates::RUNNING );
1357 bSwitchBackToLoaded = sal_True;
1361 uno::Reference< embed::XStorage > xSubStorage =
1362 xStorage->openStorageElement( sEntName, embed::ElementModes::READWRITE );
1364 if ( !xSubStorage.is() )
1365 throw uno::RuntimeException(); //TODO
1367 if ( m_nObjectState != embed::EmbedStates::LOADED )
1369 aGuard.clear();
1370 // TODO/LATER: support hierarchical name for embedded objects in embedded objects
1371 StoreDocToStorage_Impl( xSubStorage, nTargetStorageFormat, GetBaseURLFrom_Impl( lArguments, lObjArgs ), sEntName, sal_False );
1372 aGuard.reset();
1374 if ( bSwitchBackToLoaded )
1375 changeState( embed::EmbedStates::LOADED );
1378 m_bWaitSaveCompleted = sal_True;
1379 m_xNewObjectStorage = xSubStorage;
1380 m_xNewParentStorage = xStorage;
1381 m_aNewEntryName = sEntName;
1382 m_aNewDocMediaDescriptor = GetValuableArgs_Impl( lArguments, sal_True );
1384 // TODO: register listeners for storages above, in case thay are disposed
1385 // an exception will be thrown on saveCompleted( true )
1387 // TODO: should the listener notification be done here or in saveCompleted?
1390 //------------------------------------------------------
1391 void SAL_CALL OCommonEmbeddedObject::saveCompleted( sal_Bool bUseNew )
1392 throw ( embed::WrongStateException,
1393 uno::Exception,
1394 uno::RuntimeException )
1396 SAL_INFO( "embeddedobj.common", "embeddedobj (mv76033) OCommonEmbeddedObject::saveCompleted" );
1398 ::osl::MutexGuard aGuard( m_aMutex );
1399 if ( m_bDisposed )
1400 throw lang::DisposedException(); // TODO
1402 if ( m_nObjectState == -1 )
1404 // the object is still not loaded
1405 throw embed::WrongStateException( OUString( "Can't store object without persistence!\n" ),
1406 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1409 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1410 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1411 // OSL_ENSURE( !m_bIsLink, "This method implementation must not be used for links!\n" );
1412 if ( m_bIsLink )
1414 if ( bUseNew )
1415 m_aEntryName = m_aNewEntryName;
1416 m_aNewEntryName = OUString();
1417 return;
1420 // it is allowed to call saveCompleted( false ) for nonstored objects
1421 if ( !m_bWaitSaveCompleted && !bUseNew )
1422 return;
1424 SAL_WARN_IF( !m_bWaitSaveCompleted, "embeddedobj.common", "Unexpected saveCompleted() call!" );
1425 if ( !m_bWaitSaveCompleted )
1426 throw io::IOException(); // TODO: illegal call
1428 OSL_ENSURE( m_xNewObjectStorage.is() && m_xNewParentStorage.is() , "Internal object information is broken!\n" );
1429 if ( !m_xNewObjectStorage.is() || !m_xNewParentStorage.is() )
1430 throw uno::RuntimeException(); // TODO: broken internal information
1432 if ( bUseNew )
1434 SwitchOwnPersistence( m_xNewParentStorage, m_xNewObjectStorage, m_aNewEntryName );
1435 m_aDocMediaDescriptor = m_aNewDocMediaDescriptor;
1437 uno::Reference< util::XModifiable > xModif( m_pDocHolder->GetComponent(), uno::UNO_QUERY );
1438 if ( xModif.is() )
1439 xModif->setModified( sal_False );
1441 PostEvent_Impl( OUString( "OnSaveAsDone" ));
1443 else
1445 try {
1446 uno::Reference< lang::XComponent > xComponent( m_xNewObjectStorage, uno::UNO_QUERY );
1447 SAL_WARN_IF( !xComponent.is(), "embeddedobj.common", "Wrong storage implementation!" );
1448 if ( xComponent.is() )
1449 xComponent->dispose();
1451 catch ( const uno::Exception& )
1456 m_xNewObjectStorage = uno::Reference< embed::XStorage >();
1457 m_xNewParentStorage = uno::Reference< embed::XStorage >();
1458 m_aNewEntryName = OUString();
1459 m_aNewDocMediaDescriptor.realloc( 0 );
1460 m_bWaitSaveCompleted = sal_False;
1462 if ( bUseNew )
1464 // TODO: notify listeners
1466 if ( m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE )
1468 // TODO: update visual representation
1473 //------------------------------------------------------
1474 sal_Bool SAL_CALL OCommonEmbeddedObject::hasEntry()
1475 throw ( embed::WrongStateException,
1476 uno::RuntimeException )
1478 ::osl::MutexGuard aGuard( m_aMutex );
1479 if ( m_bDisposed )
1480 throw lang::DisposedException(); // TODO
1482 if ( m_bWaitSaveCompleted )
1483 throw embed::WrongStateException(
1484 OUString( "The object waits for saveCompleted() call!\n" ),
1485 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1487 if ( m_xObjectStorage.is() )
1488 return sal_True;
1490 return sal_False;
1493 //------------------------------------------------------
1494 OUString SAL_CALL OCommonEmbeddedObject::getEntryName()
1495 throw ( embed::WrongStateException,
1496 uno::RuntimeException )
1498 ::osl::MutexGuard aGuard( m_aMutex );
1499 if ( m_bDisposed )
1500 throw lang::DisposedException(); // TODO
1502 if ( m_nObjectState == -1 )
1504 // the object is still not loaded
1505 throw embed::WrongStateException( OUString( "The object persistence is not initialized!\n" ),
1506 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1509 if ( m_bWaitSaveCompleted )
1510 throw embed::WrongStateException(
1511 OUString( "The object waits for saveCompleted() call!\n" ),
1512 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1514 return m_aEntryName;
1517 //------------------------------------------------------
1518 void SAL_CALL OCommonEmbeddedObject::storeOwn()
1519 throw ( embed::WrongStateException,
1520 io::IOException,
1521 uno::Exception,
1522 uno::RuntimeException )
1524 SAL_INFO( "embeddedobj.common", "embeddedobj (mv76033) OCommonEmbeddedObject::storeOwn" );
1526 // during switching from Activated to Running and from Running to Loaded states the object will
1527 // ask container to store the object, the container has to make decision
1528 // to do so or not
1530 ::osl::ResettableMutexGuard aGuard( m_aMutex );
1531 if ( m_bDisposed )
1532 throw lang::DisposedException(); // TODO
1534 if ( m_nObjectState == -1 )
1536 // the object is still not loaded
1537 throw embed::WrongStateException( OUString( "Can't store object without persistence!\n" ),
1538 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1541 if ( m_bWaitSaveCompleted )
1542 throw embed::WrongStateException(
1543 OUString( "The object waits for saveCompleted() call!\n" ),
1544 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1546 if ( m_bReadOnly )
1547 throw io::IOException(); // TODO: access denied
1549 // nothing to do, if the object is in loaded state
1550 if ( m_nObjectState == embed::EmbedStates::LOADED )
1551 return;
1553 PostEvent_Impl( OUString( "OnSave" ) );
1555 SAL_WARN_IF( !m_pDocHolder->GetComponent().is(), "embeddedobj.common", "If an object is activated or in running state it must have a document!" );
1556 if ( !m_pDocHolder->GetComponent().is() )
1557 throw uno::RuntimeException();
1559 if ( m_bIsLink )
1561 // TODO: just store the document to it's location
1562 uno::Reference< frame::XStorable > xStorable( m_pDocHolder->GetComponent(), uno::UNO_QUERY );
1563 if ( !xStorable.is() )
1564 throw uno::RuntimeException(); // TODO
1566 // free the main mutex for the storing time
1567 aGuard.clear();
1569 xStorable->store();
1571 aGuard.reset();
1573 else
1575 OSL_ENSURE( m_xParentStorage.is() && m_xObjectStorage.is(), "The object has no valid persistence!\n" );
1577 if ( !m_xObjectStorage.is() )
1578 throw io::IOException(); //TODO: access denied
1580 sal_Int32 nStorageFormat = SOFFICE_FILEFORMAT_CURRENT;
1581 try {
1582 nStorageFormat = ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage );
1584 catch ( const beans::IllegalTypeException& )
1586 // the container just has an unknown type, use current file format
1588 catch ( const uno::Exception& )
1590 SAL_WARN( "embeddedobj.common", "Can not retrieve storage media type!" );
1593 aGuard.clear();
1594 StoreDocToStorage_Impl( m_xObjectStorage, nStorageFormat, GetBaseURL_Impl(), m_aEntryName, sal_True );
1595 aGuard.reset();
1598 uno::Reference< util::XModifiable > xModif( m_pDocHolder->GetComponent(), uno::UNO_QUERY );
1599 if ( xModif.is() )
1600 xModif->setModified( sal_False );
1602 PostEvent_Impl( OUString( "OnSaveDone" ) );
1605 //------------------------------------------------------
1606 sal_Bool SAL_CALL OCommonEmbeddedObject::isReadonly()
1607 throw ( embed::WrongStateException,
1608 uno::RuntimeException )
1610 ::osl::MutexGuard aGuard( m_aMutex );
1611 if ( m_bDisposed )
1612 throw lang::DisposedException(); // TODO
1614 if ( m_nObjectState == -1 )
1616 // the object is still not loaded
1617 throw embed::WrongStateException( OUString( "The object persistence is not initialized!\n" ),
1618 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1621 if ( m_bWaitSaveCompleted )
1622 throw embed::WrongStateException(
1623 OUString( "The object waits for saveCompleted() call!\n" ),
1624 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1626 return m_bReadOnly;
1629 //------------------------------------------------------
1630 void SAL_CALL OCommonEmbeddedObject::reload(
1631 const uno::Sequence< beans::PropertyValue >& lArguments,
1632 const uno::Sequence< beans::PropertyValue >& lObjArgs )
1633 throw ( lang::IllegalArgumentException,
1634 embed::WrongStateException,
1635 io::IOException,
1636 uno::Exception,
1637 uno::RuntimeException )
1639 // TODO: use lObjArgs
1640 // for now this method is used only to switch readonly state
1642 ::osl::MutexGuard aGuard( m_aMutex );
1643 if ( m_bDisposed )
1644 throw lang::DisposedException(); // TODO
1646 if ( m_nObjectState == -1 )
1648 // the object is still not loaded
1649 throw embed::WrongStateException( OUString( "The object persistence is not initialized!\n" ),
1650 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1653 if ( m_nObjectState != embed::EmbedStates::LOADED )
1655 // the object is still not loaded
1656 throw embed::WrongStateException(
1657 OUString( "The object must be in loaded state to be reloaded!\n" ),
1658 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1661 if ( m_bWaitSaveCompleted )
1662 throw embed::WrongStateException(
1663 OUString( "The object waits for saveCompleted() call!\n" ),
1664 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1666 if ( m_bIsLink )
1668 // reload of the link
1669 OUString aOldLinkFilter = m_aLinkFilterName;
1671 OUString aNewLinkFilter;
1672 for ( sal_Int32 nInd = 0; nInd < lArguments.getLength(); nInd++ )
1674 if ( lArguments[nInd].Name == "URL" )
1676 // the new URL
1677 lArguments[nInd].Value >>= m_aLinkURL;
1678 m_aLinkFilterName = OUString();
1680 else if ( lArguments[nInd].Name == "FilterName" )
1682 lArguments[nInd].Value >>= aNewLinkFilter;
1683 m_aLinkFilterName = OUString();
1687 ::comphelper::MimeConfigurationHelper aHelper( m_xContext );
1688 if ( m_aLinkFilterName.isEmpty() )
1690 if ( !aNewLinkFilter.isEmpty() )
1691 m_aLinkFilterName = aNewLinkFilter;
1692 else
1694 uno::Sequence< beans::PropertyValue > aArgs( 1 );
1695 aArgs[0].Name = "URL";
1696 aArgs[0].Value <<= m_aLinkURL;
1697 m_aLinkFilterName = aHelper.UpdateMediaDescriptorWithFilterName( aArgs, sal_False );
1701 if ( !aOldLinkFilter.equals( m_aLinkFilterName ) )
1703 uno::Sequence< beans::NamedValue > aObject = aHelper.GetObjectPropsByFilter( m_aLinkFilterName );
1705 // TODO/LATER: probably the document holder could be cleaned explicitly as in the destructor
1706 m_pDocHolder->release();
1707 m_pDocHolder = NULL;
1709 LinkInit_Impl( aObject, lArguments, lObjArgs );
1713 m_aDocMediaDescriptor = GetValuableArgs_Impl( lArguments, sal_True );
1715 // TODO: use lObjArgs for StoreVisualReplacement
1716 for ( sal_Int32 nObjInd = 0; nObjInd < lObjArgs.getLength(); nObjInd++ )
1717 if ( lObjArgs[nObjInd].Name == "OutplaceDispatchInterceptor" )
1719 uno::Reference< frame::XDispatchProviderInterceptor > xDispatchInterceptor;
1720 if ( lObjArgs[nObjInd].Value >>= xDispatchInterceptor )
1721 m_pDocHolder->SetOutplaceDispatchInterceptor( xDispatchInterceptor );
1723 break;
1726 // TODO:
1727 // when document allows reloading through API the object can be reloaded not only in loaded state
1729 sal_Bool bOldReadOnlyValue = m_bReadOnly;
1731 m_bReadOnly = sal_False;
1732 for ( sal_Int32 nInd = 0; nInd < lArguments.getLength(); nInd++ )
1733 if ( lArguments[nInd].Name == "ReadOnly" )
1734 lArguments[nInd].Value >>= m_bReadOnly;
1736 if ( bOldReadOnlyValue != m_bReadOnly && !m_bIsLink )
1738 // close own storage
1739 try {
1740 uno::Reference< lang::XComponent > xComponent( m_xObjectStorage, uno::UNO_QUERY );
1741 OSL_ENSURE( !m_xObjectStorage.is() || xComponent.is(), "Wrong storage implementation!" );
1742 if ( xComponent.is() )
1743 xComponent->dispose();
1745 catch ( const uno::Exception& )
1749 sal_Int32 nStorageMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
1750 m_xObjectStorage = m_xParentStorage->openStorageElement( m_aEntryName, nStorageMode );
1754 //------------------------------------------------------
1755 void SAL_CALL OCommonEmbeddedObject::breakLink( const uno::Reference< embed::XStorage >& xStorage,
1756 const OUString& sEntName )
1757 throw ( lang::IllegalArgumentException,
1758 embed::WrongStateException,
1759 io::IOException,
1760 uno::Exception,
1761 uno::RuntimeException )
1763 ::osl::ResettableMutexGuard aGuard( m_aMutex );
1764 if ( m_bDisposed )
1765 throw lang::DisposedException(); // TODO
1767 if ( !m_bIsLink )
1769 // it must be a linked initialized object
1770 throw embed::WrongStateException(
1771 OUString( "The object is not a valid linked object!\n" ),
1772 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1774 else
1776 // the current implementation of OOo links does not implement this method since it does not implement
1777 // all the set of interfaces required for OOo embedded object ( XEmbedPersist is not supported ).
1780 if ( !xStorage.is() )
1781 throw lang::IllegalArgumentException( OUString( "No parent storage is provided!\n" ),
1782 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ),
1783 1 );
1785 if ( sEntName.isEmpty() )
1786 throw lang::IllegalArgumentException( OUString( "Empty element name is provided!\n" ),
1787 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ),
1788 2 );
1790 if ( !m_bIsLink || m_nObjectState == -1 )
1792 // it must be a linked initialized object
1793 throw embed::WrongStateException(
1794 OUString( "The object is not a valid linked object!\n" ),
1795 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1798 if ( m_bWaitSaveCompleted )
1799 throw embed::WrongStateException(
1800 OUString( "The object waits for saveCompleted() call!\n" ),
1801 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1803 uno::Reference< container::XNameAccess > xNameAccess( xStorage, uno::UNO_QUERY );
1804 if ( !xNameAccess.is() )
1805 throw uno::RuntimeException(); //TODO
1807 // detect entry existence
1808 /*sal_Bool bElExists =*/ xNameAccess->hasByName( sEntName );
1810 m_bReadOnly = sal_False;
1812 if ( m_xParentStorage != xStorage || !m_aEntryName.equals( sEntName ) )
1813 SwitchOwnPersistence( xStorage, sEntName );
1815 // for linked object it means that it becomes embedded object
1816 // the document must switch it's persistence also
1818 // TODO/LATER: handle the case when temp doc can not be created
1819 // the document is a new embedded object so it must be marked as modified
1820 uno::Reference< util::XCloseable > xDocument = CreateTempDocFromLink_Impl();
1821 uno::Reference< util::XModifiable > xModif( m_pDocHolder->GetComponent(), uno::UNO_QUERY );
1822 if ( !xModif.is() )
1823 throw uno::RuntimeException();
1826 xModif->setModified( sal_True );
1828 catch( const uno::Exception& )
1831 m_pDocHolder->SetComponent( xDocument, m_bReadOnly );
1832 SAL_WARN_IF( !m_pDocHolder->GetComponent().is(), "embeddedobj.common", "If document cant be created, an exception must be thrown!" );
1834 if ( m_nObjectState == embed::EmbedStates::LOADED )
1836 // the state is changed and can not be switched to loaded state back without saving
1837 m_nObjectState = embed::EmbedStates::RUNNING;
1838 StateChangeNotification_Impl( sal_False, embed::EmbedStates::LOADED, m_nObjectState, aGuard );
1840 else if ( m_nObjectState == embed::EmbedStates::ACTIVE )
1841 m_pDocHolder->Show();
1843 m_bIsLink = sal_False;
1844 m_aLinkFilterName = OUString();
1845 m_aLinkURL = OUString();
1848 //------------------------------------------------------
1849 sal_Bool SAL_CALL OCommonEmbeddedObject::isLink()
1850 throw ( embed::WrongStateException,
1851 uno::RuntimeException )
1853 ::osl::MutexGuard aGuard( m_aMutex );
1854 if ( m_bDisposed )
1855 throw lang::DisposedException(); // TODO
1857 return m_bIsLink;
1860 //------------------------------------------------------
1861 OUString SAL_CALL OCommonEmbeddedObject::getLinkURL()
1862 throw ( embed::WrongStateException,
1863 uno::Exception,
1864 uno::RuntimeException )
1866 ::osl::MutexGuard aGuard( m_aMutex );
1867 if ( m_bDisposed )
1868 throw lang::DisposedException(); // TODO
1870 if ( !m_bIsLink )
1871 throw embed::WrongStateException(
1872 OUString( "The object is not a link object!\n" ),
1873 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1875 return m_aLinkURL;
1878 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */