Version 3.6.0.4, tag libreoffice-3.6.0.4
[LibreOffice.git] / sfx2 / source / doc / objstor.cxx
blob3700d574a8b61ad7e02215ffe477b55ad808ab78
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include <vcl/msgbox.hxx>
31 #include <svl/eitem.hxx>
32 #include <svl/stritem.hxx>
33 #include <svl/intitem.hxx>
34 #include <com/sun/star/frame/XStorable.hpp>
35 #include <com/sun/star/frame/XModel.hpp>
36 #include <com/sun/star/frame/XFrame.hpp>
37 #include <com/sun/star/document/XFilter.hpp>
38 #include <com/sun/star/document/XImporter.hpp>
39 #include <com/sun/star/document/XExporter.hpp>
40 #include <com/sun/star/document/FilterOptionsRequest.hpp>
41 #include <com/sun/star/document/XInteractionFilterOptions.hpp>
42 #include <com/sun/star/task/XInteractionHandler.hpp>
43 #include <com/sun/star/task/XInteractionAskLater.hpp>
44 #include <com/sun/star/task/FutureDocumentVersionProductUpdateRequest.hpp>
45 #include <com/sun/star/task/InteractionClassification.hpp>
46 #include <com/sun/star/lang/XInitialization.hpp>
47 #include <com/sun/star/document/MacroExecMode.hpp>
48 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
49 #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
50 #include <com/sun/star/ui/dialogs/XFilePicker.hpp>
51 #include <com/sun/star/beans/XPropertySetInfo.hpp>
52 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
53 #include <com/sun/star/beans/XPropertyAccess.hpp>
54 #include <com/sun/star/beans/PropertyValue.hpp>
55 #include <com/sun/star/beans/XPropertySet.hpp>
56 #include <com/sun/star/container/XNameAccess.hpp>
57 #include <com/sun/star/container/XSet.hpp>
58 #include <com/sun/star/embed/ElementModes.hpp>
59 #include <com/sun/star/embed/EmbedStates.hpp>
60 #include <com/sun/star/embed/Aspects.hpp>
61 #include <com/sun/star/embed/XTransactedObject.hpp>
62 #include <com/sun/star/embed/XEmbedPersist.hpp>
63 #include <com/sun/star/embed/XLinkageSupport.hpp>
64 #include <com/sun/star/embed/EntryInitModes.hpp>
65 #include <com/sun/star/embed/XOptimizedStorage.hpp>
66 #include <com/sun/star/embed/XEncryptionProtectedStorage.hpp>
67 #include <com/sun/star/io/XTruncate.hpp>
68 #include <com/sun/star/util/XModifiable.hpp>
69 #include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
70 #include <com/sun/star/xml/crypto/CipherID.hpp>
71 #include <com/sun/star/xml/crypto/DigestID.hpp>
73 #include <com/sun/star/document/XDocumentProperties.hpp>
74 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
75 #include <comphelper/processfactory.hxx>
76 #include <comphelper/configurationhelper.hxx>
77 #include <comphelper/interaction.hxx>
78 #include <svtools/sfxecode.hxx>
79 #include <unotools/securityoptions.hxx>
80 #include <cppuhelper/weak.hxx>
81 #include <unotools/streamwrap.hxx>
83 #include <unotools/saveopt.hxx>
84 #include <unotools/useroptions.hxx>
85 #include <unotools/pathoptions.hxx>
86 #include <tools/urlobj.hxx>
87 #include <tools/diagnose_ex.h>
88 #include <unotools/localfilehelper.hxx>
89 #include <unotools/ucbhelper.hxx>
90 #include <unotools/tempfile.hxx>
91 #include <unotools/docinfohelper.hxx>
92 #include <ucbhelper/content.hxx>
93 #include <sot/storinfo.hxx>
94 #include <sot/exchange.hxx>
95 #include <sot/formats.hxx>
96 #include <comphelper/storagehelper.hxx>
97 #include <comphelper/seqstream.hxx>
98 #include <comphelper/documentconstants.hxx>
99 #include <comphelper/string.hxx>
100 #include <vcl/bitmapex.hxx>
101 #include <svtools/embedhlp.hxx>
102 #include <rtl/logfile.hxx>
103 #include <basic/modsizeexceeded.hxx>
104 #include <osl/file.hxx>
106 #include <sfx2/signaturestate.hxx>
107 #include <sfx2/app.hxx>
108 #include <sfx2/objsh.hxx>
109 #include <sfx2/childwin.hxx>
110 #include <sfx2/request.hxx>
111 #include "sfx2/sfxresid.hxx"
112 #include <sfx2/docfile.hxx>
113 #include "fltfnc.hxx"
114 #include <sfx2/docfilt.hxx>
115 #include <sfx2/docfac.hxx>
116 #include "objshimp.hxx"
117 #include "sfxtypes.hxx"
118 #include "doc.hrc"
119 #include <sfx2/sfxsids.hrc>
120 #include <sfx2/module.hxx>
121 #include <sfx2/dispatch.hxx>
122 #include "openflag.hxx"
123 #include "helper.hxx"
124 #include <sfx2/event.hxx>
125 #include "fltoptint.hxx"
126 #include <sfx2/viewfrm.hxx>
127 #include "graphhelp.hxx"
128 #include "appbaslib.hxx"
129 #include "appdata.hxx"
131 #include "../appl/app.hrc"
133 extern sal_uInt32 CheckPasswd_Impl( SfxObjectShell*, SfxItemPool&, SfxMedium* );
135 using namespace ::com::sun::star;
136 using namespace ::com::sun::star::container;
137 using namespace ::com::sun::star::lang;
138 using namespace ::com::sun::star::ui::dialogs;
139 using namespace ::com::sun::star::uno;
140 using namespace ::com::sun::star::beans;
141 using namespace ::com::sun::star::ucb;
142 using namespace ::com::sun::star::task;
143 using namespace ::com::sun::star::document;
144 using namespace ::rtl;
145 using namespace ::cppu;
147 namespace css = ::com::sun::star;
149 //=========================================================================
150 void impl_addToModelCollection(const css::uno::Reference< css::frame::XModel >& xModel)
152 if (!xModel.is())
153 return;
155 css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = ::comphelper::getProcessServiceFactory();
156 css::uno::Reference< css::container::XSet > xModelCollection(
157 xSMGR->createInstance(::rtl::OUString("com.sun.star.frame.GlobalEventBroadcaster")),
158 css::uno::UNO_QUERY);
159 if (xModelCollection.is())
163 xModelCollection->insert(css::uno::makeAny(xModel));
165 catch ( uno::Exception& )
167 OSL_FAIL( "The document seems to be in the collection already!\n" );
172 //=========================================================================
174 sal_Bool SfxObjectShell::Save()
176 return SaveChildren();
179 //--------------------------------------------------------------------------
181 sal_Bool SfxObjectShell::SaveAs( SfxMedium& rMedium )
183 return SaveAsChildren( rMedium );
186 //-------------------------------------------------------------------------
188 sal_Bool SfxObjectShell::QuerySlotExecutable( sal_uInt16 /*nSlotId*/ )
190 return sal_True;
193 //-------------------------------------------------------------------------
195 bool GetEncryptionData_Impl( const SfxItemSet* pSet, uno::Sequence< beans::NamedValue >& o_rEncryptionData )
197 bool bResult = false;
198 if ( pSet )
200 SFX_ITEMSET_ARG( pSet, pEncryptionDataItem, SfxUnoAnyItem, SID_ENCRYPTIONDATA, sal_False);
201 if ( pEncryptionDataItem )
203 pEncryptionDataItem->GetValue() >>= o_rEncryptionData;
204 bResult = true;
206 else
208 SFX_ITEMSET_ARG( pSet, pPasswordItem, SfxStringItem, SID_PASSWORD, sal_False);
209 if ( pPasswordItem )
211 ::rtl::OUString aPassword = pPasswordItem->GetValue();
212 o_rEncryptionData = ::comphelper::OStorageHelper::CreatePackageEncryptionData( aPassword );
213 bResult = true;
218 return bResult;
221 //-------------------------------------------------------------------------
222 sal_Bool SfxObjectShell::PutURLContentsToVersionStream_Impl(
223 ::rtl::OUString aURL,
224 const uno::Reference< embed::XStorage >& xDocStorage,
225 ::rtl::OUString aStreamName )
227 sal_Bool bResult = sal_False;
230 uno::Reference< embed::XStorage > xVersion = xDocStorage->openStorageElement(
231 ::rtl::OUString("Versions"),
232 embed::ElementModes::READWRITE );
234 DBG_ASSERT( xVersion.is(),
235 "The method must throw an exception if the storage can not be opened!\n" );
236 if ( !xVersion.is() )
237 throw uno::RuntimeException();
239 uno::Reference< io::XStream > xVerStream = xVersion->openStreamElement(
240 aStreamName,
241 embed::ElementModes::READWRITE );
242 DBG_ASSERT( xVerStream.is(), "The method must throw an exception if the storage can not be opened!\n" );
243 if ( !xVerStream.is() )
244 throw uno::RuntimeException();
246 uno::Reference< io::XOutputStream > xOutStream = xVerStream->getOutputStream();
247 uno::Reference< io::XTruncate > xTrunc( xOutStream, uno::UNO_QUERY );
249 DBG_ASSERT( xTrunc.is(), "The output stream must exist and implement XTruncate interface!\n" );
250 if ( !xTrunc.is() )
251 throw RuntimeException();
253 uno::Reference< io::XInputStream > xTmpInStream =
254 ::comphelper::OStorageHelper::GetInputStreamFromURL( aURL );
255 DBG_ASSERT( xTmpInStream.is(), "The method must create the stream or throw an exception!\n" );
256 if ( !xTmpInStream.is() )
257 throw uno::RuntimeException();
259 xTrunc->truncate();
260 ::comphelper::OStorageHelper::CopyInputToOutput( xTmpInStream, xOutStream );
261 xOutStream->closeOutput();
263 uno::Reference< embed::XTransactedObject > xTransact( xVersion, uno::UNO_QUERY );
264 DBG_ASSERT( xTransact.is(), "The storage must implement XTransacted interface!\n" );
265 if ( xTransact.is() )
266 xTransact->commit();
268 bResult = sal_True;
270 catch( uno::Exception& )
272 // TODO/LATER: handle the error depending on exception
273 SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( OSL_LOG_PREFIX ) );
276 return bResult;
279 //-------------------------------------------------------------------------
280 ::rtl::OUString SfxObjectShell::CreateTempCopyOfStorage_Impl( const uno::Reference< embed::XStorage >& xStorage )
282 ::rtl::OUString aTempURL = ::utl::TempFile().GetURL();
284 DBG_ASSERT( !aTempURL.isEmpty(), "Can't create a temporary file!\n" );
285 if ( !aTempURL.isEmpty() )
289 uno::Reference< embed::XStorage > xTempStorage =
290 ::comphelper::OStorageHelper::GetStorageFromURL( aTempURL, embed::ElementModes::READWRITE );
292 // the password will be transfered from the xStorage to xTempStorage by storage implemetation
293 xStorage->copyToStorage( xTempStorage );
295 // the temporary storage was commited by the previous method and it will die by refcount
297 catch ( uno::Exception& )
299 OSL_FAIL( "Creation of a storage copy is failed!" );
300 ::utl::UCBContentHelper::Kill( aTempURL );
302 aTempURL = ::rtl::OUString();
304 // TODO/LATER: may need error code setting based on exception
305 SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( OSL_LOG_PREFIX ) );
309 return aTempURL;
312 //-------------------------------------------------------------------------
313 SvGlobalName SfxObjectShell::GetClassName() const
315 return GetFactory().GetClassId();
318 //-------------------------------------------------------------------------
319 void SfxObjectShell::SetupStorage( const uno::Reference< embed::XStorage >& xStorage,
320 sal_Int32 nVersion,
321 sal_Bool bTemplate ) const
323 uno::Reference< beans::XPropertySet > xProps( xStorage, uno::UNO_QUERY );
325 if ( xProps.is() )
327 SvGlobalName aName;
328 String aFullTypeName, aShortTypeName, aAppName;
329 sal_uInt32 nClipFormat=0;
331 FillClass( &aName, &nClipFormat, &aAppName, &aFullTypeName, &aShortTypeName, nVersion, bTemplate );
332 if ( nClipFormat )
334 // basic doesn't have a ClipFormat
335 // without MediaType the storage is not really usable, but currently the BasicIDE still
336 // is an SfxObjectShell and so we can't take this as an error
337 datatransfer::DataFlavor aDataFlavor;
338 SotExchange::GetFormatDataFlavor( nClipFormat, aDataFlavor );
339 if ( !aDataFlavor.MimeType.isEmpty() )
343 xProps->setPropertyValue( ::rtl::OUString("MediaType"), uno::makeAny( aDataFlavor.MimeType ) );
345 catch( uno::Exception& )
347 const_cast<SfxObjectShell*>( this )->SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( OSL_LOG_PREFIX ) );
350 SvtSaveOptions aSaveOpt;
351 SvtSaveOptions::ODFDefaultVersion nDefVersion = aSaveOpt.GetODFDefaultVersion();
353 uno::Sequence< beans::NamedValue > aEncryptionAlgs( 3 );
354 aEncryptionAlgs[0].Name = ::rtl::OUString( "StartKeyGenerationAlgorithm" );
355 aEncryptionAlgs[1].Name = ::rtl::OUString( "EncryptionAlgorithm" );
356 aEncryptionAlgs[2].Name = ::rtl::OUString( "ChecksumAlgorithm" );
357 // the default values, that should be used for ODF1.1 and older formats
358 aEncryptionAlgs[0].Value <<= xml::crypto::DigestID::SHA1;
359 aEncryptionAlgs[1].Value <<= xml::crypto::CipherID::BLOWFISH_CFB_8;
360 aEncryptionAlgs[2].Value <<= xml::crypto::DigestID::SHA1_1K;
362 if ( nDefVersion >= SvtSaveOptions::ODFVER_012 )
366 // older versions can not have this property set, it exists only starting from ODF1.2
367 xProps->setPropertyValue( ::rtl::OUString("Version" ), uno::makeAny( ODFVER_012_TEXT ) );
369 catch( uno::Exception& )
373 if ( !aSaveOpt.IsUseSHA1InODF12() && nDefVersion != SvtSaveOptions::ODFVER_012_EXT_COMPAT )
375 aEncryptionAlgs[0].Value <<= xml::crypto::DigestID::SHA256;
376 aEncryptionAlgs[2].Value <<= xml::crypto::DigestID::SHA256_1K;
378 if ( !aSaveOpt.IsUseBlowfishInODF12() && nDefVersion != SvtSaveOptions::ODFVER_012_EXT_COMPAT )
379 aEncryptionAlgs[1].Value <<= xml::crypto::CipherID::AES_CBC_W3C_PADDING;
384 // set the encryption algorithms accordingly;
385 // the setting does not trigger encryption,
386 // it just provides the format for the case that contents should be encrypted
387 uno::Reference< embed::XEncryptionProtectedStorage > xEncr( xStorage, uno::UNO_QUERY_THROW );
388 xEncr->setEncryptionAlgorithms( aEncryptionAlgs );
390 catch( uno::Exception& )
392 const_cast<SfxObjectShell*>( this )->SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( OSL_LOG_PREFIX ) );
400 //-------------------------------------------------------------------------
401 void SfxObjectShell::PrepareSecondTryLoad_Impl()
403 // only for internal use
404 pImp->m_xDocStorage = uno::Reference< embed::XStorage >();
405 pImp->m_bIsInit = sal_False;
406 ResetError();
409 //-------------------------------------------------------------------------
410 sal_Bool SfxObjectShell::GeneralInit_Impl( const uno::Reference< embed::XStorage >& xStorage,
411 sal_Bool bTypeMustBeSetAlready )
413 if ( pImp->m_bIsInit )
414 return sal_False;
416 pImp->m_bIsInit = sal_True;
417 if ( xStorage.is() )
419 // no notification is required the storage is set the first time
420 pImp->m_xDocStorage = xStorage;
422 try {
423 uno::Reference < beans::XPropertySet > xPropSet( xStorage, uno::UNO_QUERY_THROW );
424 Any a = xPropSet->getPropertyValue( ::rtl::OUString("MediaType" ) );
425 ::rtl::OUString aMediaType;
426 if ( !(a>>=aMediaType) || aMediaType.isEmpty() )
428 if ( bTypeMustBeSetAlready )
430 SetError( ERRCODE_IO_BROKENPACKAGE, ::rtl::OUString( OSL_LOG_PREFIX ) );
431 return sal_False;
434 SetupStorage( xStorage, SOFFICE_FILEFORMAT_CURRENT, sal_False );
437 catch ( uno::Exception& )
439 OSL_FAIL( "Can't check storage's mediatype!\n" );
442 else
443 pImp->m_bCreateTempStor = sal_True;
445 return sal_True;
448 //-------------------------------------------------------------------------
449 sal_Bool SfxObjectShell::InitNew( const uno::Reference< embed::XStorage >& xStorage )
451 return GeneralInit_Impl( xStorage, sal_False );
454 //-------------------------------------------------------------------------
455 sal_Bool SfxObjectShell::Load( SfxMedium& rMedium )
457 return GeneralInit_Impl( rMedium.GetStorage(), sal_True );
460 sal_Bool SfxObjectShell::DoInitNew( SfxMedium* pMed )
461 /* [Description]
463 This from SvPersist inherited virtual method is called to initialize
464 the SfxObjectShell instance from a storage (PStore! = 0) or (PStore == 0)
466 Like with all Do...-methods there is a from a control, the actual
467 implementation is done by the virtual method in which also the
468 InitNew(SvStorate *) from the SfxObjectShell-Subclass is implemented.
470 For pStore == 0 the SfxObjectShell-instance is connected to an empty
471 SfxMedium, otherwise a SfxMedium, which refers to the SvStorage
472 passed as a parameter.
474 The object is only initialized correctly after InitNew() or Load().
476 [Return value]
477 sal_True The object has been initialized.
478 sal_False The object could not be initialized
482 ModifyBlocker_Impl aBlock( this );
483 pMedium = pMed;
484 if ( !pMedium )
486 bIsTmp = sal_True;
487 pMedium = new SfxMedium;
490 pMedium->CanDisposeStorage_Impl( sal_True );
492 if ( InitNew( pMed ? pMed->GetStorage() : uno::Reference < embed::XStorage >() ) )
494 // empty documents always get their macros from the user, so there is no reason to restrict access
495 pImp->aMacroMode.allowMacroExecution();
496 if ( SFX_CREATE_MODE_EMBEDDED == eCreateMode )
497 SetTitle( String( SfxResId( STR_NONAME ) ));
499 uno::Reference< frame::XModel > xModel ( GetModel(), uno::UNO_QUERY );
500 if ( xModel.is() )
502 SfxItemSet *pSet = GetMedium()->GetItemSet();
503 uno::Sequence< beans::PropertyValue > aArgs;
504 TransformItems( SID_OPENDOC, *pSet, aArgs );
505 sal_Int32 nLength = aArgs.getLength();
506 aArgs.realloc( nLength + 1 );
507 aArgs[nLength].Name = DEFINE_CONST_UNICODE("Title");
508 aArgs[nLength].Value <<= ::rtl::OUString( GetTitle( SFX_TITLE_DETECT ) );
509 xModel->attachResource( ::rtl::OUString(), aArgs );
510 impl_addToModelCollection(xModel);
513 SetInitialized_Impl( true );
514 return sal_True;
517 return sal_False;
520 //-------------------------------------------------------------------------
522 sal_Bool SfxObjectShell::ImportFromGeneratedStream_Impl(
523 const uno::Reference< io::XStream >& xStream,
524 const uno::Sequence< beans::PropertyValue >& aMediaDescr )
526 if ( !xStream.is() )
527 return sal_False;
529 if ( pMedium && pMedium->HasStorage_Impl() )
530 pMedium->CloseStorage();
532 sal_Bool bResult = sal_False;
536 uno::Reference< embed::XStorage > xStorage =
537 ::comphelper::OStorageHelper::GetStorageFromStream( xStream, embed::ElementModes::READWRITE );
539 if ( !xStorage.is() )
540 throw uno::RuntimeException();
542 if ( !pMedium )
543 pMedium = new SfxMedium( xStorage, String() );
544 else
545 pMedium->SetStorage_Impl( xStorage );
547 SfxAllItemSet aSet( SFX_APP()->GetPool() );
548 TransformParameters( SID_OPENDOC, aMediaDescr, aSet );
549 pMedium->GetItemSet()->Put( aSet );
550 pMedium->CanDisposeStorage_Impl( sal_False );
552 // allow the subfilter to reinit the model
553 if ( pImp->m_bIsInit )
554 pImp->m_bIsInit = sal_False;
556 if ( LoadOwnFormat( *pMedium ) )
558 bHasName = sal_True;
559 if ( !IsReadOnly() && IsLoadReadonly() )
560 SetReadOnlyUI();
562 bResult = sal_True;
563 OSL_ENSURE( pImp->m_xDocStorage == xStorage, "Wrong storage is used!\n" );
566 // now the medium can be disconnected from the storage
567 // the medium is not allowed to dispose the storage so CloseStorage() can be used
568 pMedium->CloseStorage();
570 catch( uno::Exception& )
574 return bResult;
577 //-------------------------------------------------------------------------
579 sal_Bool SfxObjectShell::DoLoad( SfxMedium *pMed )
581 ModifyBlocker_Impl aBlock( this );
583 if ( SFX_CREATE_MODE_EMBEDDED != eCreateMode )
584 GetpApp()->ShowStatusText( SfxResId(STR_DOC_LOADING) );
586 pMedium = pMed;
587 pMedium->CanDisposeStorage_Impl( sal_True );
589 sal_Bool bOk = sal_False;
590 const SfxFilter* pFilter = pMed->GetFilter();
591 SfxItemSet* pSet = pMedium->GetItemSet();
592 if( !pImp->nEventId )
594 SFX_ITEMSET_ARG(
595 pSet, pTemplateItem, SfxBoolItem,
596 SID_TEMPLATE, sal_False);
597 SetActivateEvent_Impl(
598 ( pTemplateItem && pTemplateItem->GetValue() )
599 ? SFX_EVENT_CREATEDOC : SFX_EVENT_OPENDOC );
603 SFX_ITEMSET_ARG( pSet, pBaseItem, SfxStringItem,
604 SID_BASEURL, sal_False);
605 rtl::OUString aBaseURL;
606 SFX_ITEMSET_ARG( pMedium->GetItemSet(), pSalvageItem, SfxStringItem, SID_DOC_SALVAGE, sal_False);
607 if( pBaseItem )
608 aBaseURL = pBaseItem->GetValue();
609 else
611 if ( pSalvageItem )
613 rtl::OUString aName( pMed->GetPhysicalName() );
614 ::utl::LocalFileHelper::ConvertPhysicalNameToURL( aName, aBaseURL );
616 else
617 aBaseURL = pMed->GetBaseURL();
619 pMed->GetItemSet()->Put( SfxStringItem( SID_DOC_BASEURL, aBaseURL ) );
621 pImp->nLoadedFlags = 0;
622 pImp->bModelInitialized = sal_False;
624 //TODO/LATER: make a clear strategy how to handle "UsesStorage" etc.
625 sal_Bool bOwnStorageFormat = IsOwnStorageFormat_Impl( *pMedium );
626 sal_Bool bHasStorage = IsPackageStorageFormat_Impl( *pMedium );
627 if ( pMedium->GetFilter() )
629 sal_uInt32 nError = HandleFilter( pMedium, this );
630 if ( nError != ERRCODE_NONE )
631 SetError( nError, ::rtl::OUString( OSL_LOG_PREFIX ) );
633 if (pMedium->GetFilter()->GetFilterFlags() & SFX_FILTER_STARTPRESENTATION)
634 pSet->Put( SfxBoolItem( SID_DOC_STARTPRESENTATION, sal_True) );
637 EnableSetModified( sal_False );
639 pMedium->LockOrigFileOnDemand( sal_True, sal_False );
640 if ( GetError() == ERRCODE_NONE && bOwnStorageFormat && ( !pFilter || !( pFilter->GetFilterFlags() & SFX_FILTER_STARONEFILTER ) ) )
642 uno::Reference< embed::XStorage > xStorage;
643 if ( pMedium->GetError() == ERRCODE_NONE )
644 xStorage = pMedium->GetStorage();
646 if( xStorage.is() && pMedium->GetLastStorageCreationState() == ERRCODE_NONE )
648 DBG_ASSERT( pFilter, "No filter for storage found!" );
652 sal_Bool bWarnMediaTypeFallback = sal_False;
653 SFX_ITEMSET_ARG( pMedium->GetItemSet(), pRepairPackageItem, SfxBoolItem, SID_REPAIRPACKAGE, sal_False);
655 // treat the package as broken if the mediatype was retrieved as a fallback
656 uno::Reference< beans::XPropertySet > xStorProps( xStorage, uno::UNO_QUERY_THROW );
657 xStorProps->getPropertyValue( ::rtl::OUString( "MediaTypeFallbackUsed" ) )
658 >>= bWarnMediaTypeFallback;
660 if ( pRepairPackageItem && pRepairPackageItem->GetValue() )
662 // the macros in repaired documents should be disabled
663 pMedium->GetItemSet()->Put( SfxUInt16Item( SID_MACROEXECMODE, document::MacroExecMode::NEVER_EXECUTE ) );
665 // the mediatype was retrieved by using fallback solution but this is a repairing mode
666 // so it is acceptable to open the document if there is no contents that required manifest.xml
667 bWarnMediaTypeFallback = sal_False;
670 if ( bWarnMediaTypeFallback || !xStorage->getElementNames().getLength() )
671 SetError( ERRCODE_IO_BROKENPACKAGE, ::rtl::OUString( OSL_LOG_PREFIX ) );
673 catch( uno::Exception& )
675 // TODO/LATER: may need error code setting based on exception
676 SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( OSL_LOG_PREFIX ) );
679 // Load
680 if ( !GetError() )
682 pImp->nLoadedFlags = 0;
683 pImp->bModelInitialized = sal_False;
684 bOk = xStorage.is() && LoadOwnFormat( *pMed );
685 if ( bOk )
687 // the document loaded from template has no name
688 SFX_ITEMSET_ARG( pMedium->GetItemSet(), pTemplateItem, SfxBoolItem, SID_TEMPLATE, sal_False);
689 if ( !pTemplateItem || !pTemplateItem->GetValue() )
690 bHasName = sal_True;
692 else
693 SetError( ERRCODE_ABORT, ::rtl::OUString( OSL_LOG_PREFIX ) );
696 else
697 SetError( pMed->GetLastStorageCreationState(), ::rtl::OUString( OSL_LOG_PREFIX ) );
699 else if ( GetError() == ERRCODE_NONE && InitNew(0) )
701 // Name vor ConvertFrom setzen, damit GetSbxObject() schon funktioniert
702 bHasName = sal_True;
703 SetName( SfxResId( STR_NONAME ) );
705 if( !bHasStorage )
706 pMedium->GetInStream();
707 else
708 pMedium->GetStorage();
710 if ( GetError() == ERRCODE_NONE )
712 pImp->nLoadedFlags = 0;
713 pImp->bModelInitialized = sal_False;
714 if ( pMedium->GetFilter() && ( pMedium->GetFilter()->GetFilterFlags() & SFX_FILTER_STARONEFILTER ) )
716 uno::Reference < beans::XPropertySet > xSet( GetModel(), uno::UNO_QUERY );
717 ::rtl::OUString sLockUpdates("LockUpdates");
718 bool bSetProperty = true;
721 xSet->setPropertyValue( sLockUpdates, makeAny( (sal_Bool) sal_True ) );
723 catch(const beans::UnknownPropertyException& )
725 bSetProperty = false;
727 bOk = ImportFrom( *pMedium, false );
728 if(bSetProperty)
732 xSet->setPropertyValue( sLockUpdates, makeAny( (sal_Bool) sal_False ) );
734 catch(const beans::UnknownPropertyException& )
737 UpdateLinks();
738 FinishedLoading( SFX_LOADED_ALL );
740 else
742 bOk = ConvertFrom(*pMedium);
743 InitOwnModel_Impl();
748 if ( bOk )
750 if ( IsReadOnlyMedium() || IsLoadReadonly() )
751 SetReadOnlyUI();
755 ::ucbhelper::Content aContent( pMedium->GetName(), com::sun::star::uno::Reference < XCommandEnvironment >() );
756 com::sun::star::uno::Reference < XPropertySetInfo > xProps = aContent.getProperties();
757 if ( xProps.is() )
759 ::rtl::OUString aAuthor( "Author" );
760 ::rtl::OUString aKeywords( "Keywords" );
761 ::rtl::OUString aSubject( "Subject" );
762 Any aAny;
763 ::rtl::OUString aValue;
764 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
765 GetModel(), uno::UNO_QUERY_THROW);
766 uno::Reference<document::XDocumentProperties> xDocProps
767 = xDPS->getDocumentProperties();
768 if ( xProps->hasPropertyByName( aAuthor ) )
770 aAny = aContent.getPropertyValue( aAuthor );
771 if ( ( aAny >>= aValue ) )
772 xDocProps->setAuthor(aValue);
774 if ( xProps->hasPropertyByName( aKeywords ) )
776 aAny = aContent.getPropertyValue( aKeywords );
777 if ( ( aAny >>= aValue ) )
778 xDocProps->setKeywords(
779 ::comphelper::string::convertCommaSeparated(aValue));
782 if ( xProps->hasPropertyByName( aSubject ) )
784 aAny = aContent.getPropertyValue( aSubject );
785 if ( ( aAny >>= aValue ) ) {
786 xDocProps->setSubject(aValue);
791 catch( Exception& )
795 // If not loaded asynchronously call FinishedLoading
796 if ( !( pImp->nLoadedFlags & SFX_LOADED_MAINDOCUMENT ) &&
797 ( !pMedium->GetFilter() || pMedium->GetFilter()->UsesStorage() )
799 FinishedLoading( SFX_LOADED_MAINDOCUMENT );
801 if( IsOwnStorageFormat_Impl(*pMed) && pMed->GetFilter() )
804 Broadcast( SfxSimpleHint(SFX_HINT_NAMECHANGED) );
806 if ( SFX_CREATE_MODE_EMBEDDED != eCreateMode )
808 GetpApp()->HideStatusText();
810 SFX_ITEMSET_ARG( pMedium->GetItemSet(), pAsTempItem, SfxBoolItem, SID_TEMPLATE, sal_False);
811 SFX_ITEMSET_ARG( pMedium->GetItemSet(), pPreviewItem, SfxBoolItem, SID_PREVIEW, sal_False);
812 SFX_ITEMSET_ARG( pMedium->GetItemSet(), pHiddenItem, SfxBoolItem, SID_HIDDEN, sal_False);
813 if( bOk && pMedium->GetOrigURL().Len()
814 && !( pAsTempItem && pAsTempItem->GetValue() )
815 && !( pPreviewItem && pPreviewItem->GetValue() )
816 && !( pHiddenItem && pHiddenItem->GetValue() ) )
818 AddToRecentlyUsedList();
822 const SfxBoolItem* pDdeReconnectItem = static_cast<const SfxBoolItem*>(
823 SfxRequest::GetItem(pMedium->GetItemSet(), SID_DDE_RECONNECT_ONLOAD, false, TYPE(SfxBoolItem)));
825 bool bReconnectDde = true; // by default, we try to auto-connect DDE connections.
826 if (pDdeReconnectItem)
827 bReconnectDde = pDdeReconnectItem->GetValue();
829 if (bReconnectDde)
830 ReconnectDdeLinks(*this);
832 else
833 GetpApp()->HideStatusText();
835 return bOk;
838 sal_uInt32 SfxObjectShell::HandleFilter( SfxMedium* pMedium, SfxObjectShell* pDoc )
840 sal_uInt32 nError = ERRCODE_NONE;
841 SfxItemSet* pSet = pMedium->GetItemSet();
842 SFX_ITEMSET_ARG( pSet, pOptions, SfxStringItem, SID_FILE_FILTEROPTIONS, sal_False );
843 SFX_ITEMSET_ARG( pSet, pData, SfxUnoAnyItem, SID_FILTER_DATA, sal_False );
844 if ( !pData && !pOptions )
846 com::sun::star::uno::Reference< XMultiServiceFactory > xServiceManager = ::comphelper::getProcessServiceFactory();
847 com::sun::star::uno::Reference< XNameAccess > xFilterCFG;
848 if( xServiceManager.is() )
850 xFilterCFG = com::sun::star::uno::Reference< XNameAccess >(
851 xServiceManager->createInstance( ::rtl::OUString("com.sun.star.document.FilterFactory") ),
852 UNO_QUERY );
855 if( xFilterCFG.is() )
857 sal_Bool bAbort = sal_False;
858 try {
859 const SfxFilter* pFilter = pMedium->GetFilter();
860 Sequence < PropertyValue > aProps;
861 Any aAny = xFilterCFG->getByName( pFilter->GetName() );
862 if ( aAny >>= aProps )
864 sal_Int32 nPropertyCount = aProps.getLength();
865 for( sal_Int32 nProperty=0; nProperty < nPropertyCount; ++nProperty )
866 if( aProps[nProperty].Name == "UIComponent" )
868 ::rtl::OUString aServiceName;
869 aProps[nProperty].Value >>= aServiceName;
870 if( !aServiceName.isEmpty() )
872 com::sun::star::uno::Reference< XInteractionHandler > rHandler = pMedium->GetInteractionHandler();
873 if( rHandler.is() )
875 // we need some properties in the media descriptor, so we have to make sure that they are in
876 Any aStreamAny;
877 aStreamAny <<= pMedium->GetInputStream();
878 if ( pSet->GetItemState( SID_INPUTSTREAM ) < SFX_ITEM_SET )
879 pSet->Put( SfxUnoAnyItem( SID_INPUTSTREAM, aStreamAny ) );
880 if ( pSet->GetItemState( SID_FILE_NAME ) < SFX_ITEM_SET )
881 pSet->Put( SfxStringItem( SID_FILE_NAME, pMedium->GetName() ) );
882 if ( pSet->GetItemState( SID_FILTER_NAME ) < SFX_ITEM_SET )
883 pSet->Put( SfxStringItem( SID_FILTER_NAME, pFilter->GetName() ) );
885 Sequence< PropertyValue > rProperties;
886 TransformItems( SID_OPENDOC, *pSet, rProperties, NULL );
887 RequestFilterOptions* pFORequest = new RequestFilterOptions( pDoc->GetModel(), rProperties );
889 com::sun::star::uno::Reference< XInteractionRequest > rRequest( pFORequest );
890 rHandler->handle( rRequest );
892 if ( !pFORequest->isAbort() )
894 SfxAllItemSet aNewParams( pDoc->GetPool() );
895 TransformParameters( SID_OPENDOC,
896 pFORequest->getFilterOptions(),
897 aNewParams,
898 NULL );
900 SFX_ITEMSET_ARG( &aNewParams,
901 pFilterOptions,
902 SfxStringItem,
903 SID_FILE_FILTEROPTIONS,
904 sal_False );
905 if ( pFilterOptions )
906 pSet->Put( *pFilterOptions );
908 SFX_ITEMSET_ARG( &aNewParams,
909 pFilterData,
910 SfxUnoAnyItem,
911 SID_FILTER_DATA,
912 sal_False );
913 if ( pFilterData )
914 pSet->Put( *pFilterData );
916 else
917 bAbort = sal_True;
921 break;
925 if( bAbort )
927 // filter options were not entered
928 nError = ERRCODE_ABORT;
931 catch( NoSuchElementException& )
933 // the filter name is unknown
934 nError = ERRCODE_IO_INVALIDPARAMETER;
936 catch( Exception& )
938 nError = ERRCODE_ABORT;
943 return nError;
946 //-------------------------------------------------------------------------
948 sal_Bool SfxObjectShell::IsOwnStorageFormat_Impl(const SfxMedium &rMedium) const
950 return !rMedium.GetFilter() || // Embedded
951 ( rMedium.GetFilter()->IsOwnFormat() &&
952 rMedium.GetFilter()->UsesStorage() &&
953 rMedium.GetFilter()->GetVersion() >= SOFFICE_FILEFORMAT_60 );
956 //-------------------------------------------------------------------------
958 sal_Bool SfxObjectShell::IsPackageStorageFormat_Impl(const SfxMedium &rMedium) const
960 return !rMedium.GetFilter() || // Embedded
961 ( rMedium.GetFilter()->UsesStorage() &&
962 rMedium.GetFilter()->GetVersion() >= SOFFICE_FILEFORMAT_60 );
965 //-------------------------------------------------------------------------
967 sal_Bool SfxObjectShell::DoSave()
968 // DoSave is only invoked for OLE. Save your own documents in the SFX through
969 // DoSave_Impl order to allow for the creation of backups.
970 // Save in your own format again.
972 sal_Bool bOk = sal_False ;
974 ModifyBlocker_Impl aBlock( this );
976 pImp->bIsSaving = sal_True;
978 uno::Sequence< beans::NamedValue > aEncryptionData;
979 if ( IsPackageStorageFormat_Impl( *GetMedium() ) )
981 if ( GetEncryptionData_Impl( GetMedium()->GetItemSet(), aEncryptionData ) )
985 //TODO/MBA: GetOutputStorage?! Special mode, because it's "Save"?!
986 ::comphelper::OStorageHelper::SetCommonStorageEncryptionData( GetMedium()->GetStorage(), aEncryptionData );
987 bOk = sal_True;
989 catch( uno::Exception& )
991 SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( OSL_LOG_PREFIX ) );
994 DBG_ASSERT( bOk, "The root storage must allow to set common password!\n" );
996 else
997 bOk = sal_True;
998 #ifndef DISABLE_SCRIPTING
999 if ( HasBasic() )
1003 // The basic and dialogs related contents are still not able to proceed with save operation ( saveTo only )
1004 // so since the document storage is locked a workaround has to be used
1006 uno::Reference< embed::XStorage > xTmpStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
1007 DBG_ASSERT( xTmpStorage.is(), "If a storage can not be created an exception must be thrown!\n" );
1008 if ( !xTmpStorage.is() )
1009 throw uno::RuntimeException();
1011 ::rtl::OUString aBasicStorageName( "Basic" );
1012 ::rtl::OUString aDialogsStorageName( "Dialogs" );
1013 if ( GetMedium()->GetStorage()->hasByName( aBasicStorageName ) )
1014 GetMedium()->GetStorage()->copyElementTo( aBasicStorageName, xTmpStorage, aBasicStorageName );
1015 if ( GetMedium()->GetStorage()->hasByName( aDialogsStorageName ) )
1016 GetMedium()->GetStorage()->copyElementTo( aDialogsStorageName, xTmpStorage, aDialogsStorageName );
1018 GetBasicManager();
1020 // disconnect from the current storage
1021 pImp->pBasicManager->setStorage( xTmpStorage );
1023 // store to the current storage
1024 pImp->pBasicManager->storeLibrariesToStorage( GetMedium()->GetStorage() );
1026 // connect to the current storage back
1027 pImp->pBasicManager->setStorage( GetMedium()->GetStorage() );
1029 catch( uno::Exception& )
1031 SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( OSL_LOG_PREFIX ) );
1032 bOk = sal_False;
1035 #endif
1038 if ( bOk )
1039 bOk = Save();
1041 bOk = pMedium->Commit();
1044 return bOk;
1047 void Lock_Impl( SfxObjectShell* pDoc, sal_Bool bLock )
1049 SfxViewFrame *pFrame= SfxViewFrame::GetFirst( pDoc );
1050 while ( pFrame )
1052 pFrame->GetDispatcher()->Lock( bLock );
1053 pFrame->Enable( !bLock );
1054 pFrame = SfxViewFrame::GetNext( *pFrame, pDoc );
1059 //-------------------------------------------------------------------------
1061 sal_Bool SfxObjectShell::SaveTo_Impl
1063 SfxMedium &rMedium, // Medium, in which it will be stored
1064 const SfxItemSet* pSet
1067 /* [Description]
1069 Writes the current contents to the medium rMedium. If the target medium is
1070 no storage, then saving to a temporary storage, or directly if the medium
1071 is transacted, if we ourselves have opened it, and if we are a server
1072 either the container a transacted storage provides or created a
1073 temporary storage by one self.
1077 RTL_LOGFILE_PRODUCT_CONTEXT( aLog, "PERFORMANCE SfxObjectShell::SaveTo_Impl" );
1078 if( RTL_LOGFILE_HASLOGFILE() )
1080 rtl::OString aString(
1081 rtl::OUStringToOString(rMedium.GetName(), RTL_TEXTENCODING_ASCII_US));
1082 RTL_LOGFILE_PRODUCT_CONTEXT_TRACE1(aLog, "saving \"%s\"", aString.getStr());
1085 AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Begin" ) );
1087 ModifyBlocker_Impl aMod(this);
1089 const SfxFilter *pFilter = rMedium.GetFilter();
1090 if ( !pFilter )
1092 // if no filter was set, use the default filter
1093 // this should be changed in the feature, it should be an error!
1094 OSL_FAIL("No filter set!");
1095 pFilter = GetFactory().GetFilterContainer()->GetAnyFilter( SFX_FILTER_IMPORT | SFX_FILTER_EXPORT );
1096 rMedium.SetFilter(pFilter);
1099 sal_Bool bStorageBasedSource = IsPackageStorageFormat_Impl( *pMedium );
1100 sal_Bool bStorageBasedTarget = IsPackageStorageFormat_Impl( rMedium );
1101 sal_Bool bOwnSource = IsOwnStorageFormat_Impl( *pMedium );
1102 sal_Bool bOwnTarget = IsOwnStorageFormat_Impl( rMedium );
1104 // Examine target format to determine whether to query if any password
1105 // protected libraries exceed the size we can handler
1106 if ( bOwnTarget && !QuerySaveSizeExceededModules_Impl( rMedium.GetInteractionHandler() ) )
1108 SetError( ERRCODE_IO_ABORT, ::rtl::OUString( OSL_LOG_PREFIX ) );
1109 return sal_False;
1112 sal_Bool bNeedsDisconnectionOnFail = sal_False;
1114 sal_Bool bStoreToSameLocation = sal_False;
1116 // the detection whether the script is changed should be done before saving
1117 sal_Bool bTryToPreserveScriptSignature = sal_False;
1118 // no way to detect whether a filter is oasis format, have to wait for saving process
1119 sal_Bool bNoPreserveForOasis = sal_False;
1120 if ( bOwnSource && bOwnTarget
1121 && ( pImp->nScriptingSignatureState == SIGNATURESTATE_SIGNATURES_OK
1122 || pImp->nScriptingSignatureState == SIGNATURESTATE_SIGNATURES_NOTVALIDATED
1123 || pImp->nScriptingSignatureState == SIGNATURESTATE_SIGNATURES_INVALID ) )
1125 AddLog( ::rtl::OUString( OSL_LOG_PREFIX "MacroSignaturePreserving" ) );
1127 // the checking of the library modified state iterates over the libraries, should be done only when required
1128 // currently the check is commented out since it is broken, we have to check the signature every time we save
1129 // TODO/LATER: let isAnyContainerModified() work!
1130 bTryToPreserveScriptSignature = sal_True; // !pImp->pBasicManager->isAnyContainerModified();
1131 if ( bTryToPreserveScriptSignature )
1133 // check that the storage format stays the same
1134 SvtSaveOptions aSaveOpt;
1135 SvtSaveOptions::ODFDefaultVersion nVersion = aSaveOpt.GetODFDefaultVersion();
1137 ::rtl::OUString aODFVersion;
1140 uno::Reference < beans::XPropertySet > xPropSet( GetStorage(), uno::UNO_QUERY_THROW );
1141 xPropSet->getPropertyValue( ::rtl::OUString( "Version" ) ) >>= aODFVersion;
1143 catch( uno::Exception& )
1146 // preserve only if the same filter has been used
1147 bTryToPreserveScriptSignature = pMedium->GetFilter() && pFilter && pMedium->GetFilter()->GetFilterName() == pFilter->GetFilterName();
1149 bNoPreserveForOasis = (
1150 (aODFVersion.equals( ODFVER_012_TEXT ) && nVersion == SvtSaveOptions::ODFVER_011) ||
1151 (aODFVersion.isEmpty() && nVersion >= SvtSaveOptions::ODFVER_012)
1156 sal_Bool bCopyTo = sal_False;
1157 SfxItemSet *pMedSet = rMedium.GetItemSet();
1158 if( pMedSet )
1160 SFX_ITEMSET_ARG( pMedSet, pSaveToItem, SfxBoolItem, SID_SAVETO, sal_False );
1161 bCopyTo = GetCreateMode() == SFX_CREATE_MODE_EMBEDDED ||
1162 (pSaveToItem && pSaveToItem->GetValue());
1165 // use UCB for case sensitive/insensitive file name comparison
1166 if ( pMedium
1167 && pMedium->GetName().CompareIgnoreCaseToAscii( "private:stream", 14 ) != COMPARE_EQUAL
1168 && rMedium.GetName().CompareIgnoreCaseToAscii( "private:stream", 14 ) != COMPARE_EQUAL
1169 && ::utl::UCBContentHelper::EqualURLs( pMedium->GetName(), rMedium.GetName() ) )
1171 bStoreToSameLocation = sal_True;
1172 AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Save" ) );
1174 if ( pMedium->DocNeedsFileDateCheck() )
1175 rMedium.CheckFileDate( pMedium->GetInitFileDate( sal_False ) );
1177 if ( bCopyTo && GetCreateMode() != SFX_CREATE_MODE_EMBEDDED )
1179 // export to the same location is forbidden
1180 SetError( ERRCODE_IO_CANTWRITE, ::rtl::OUString( OSL_LOG_PREFIX ) );
1182 else
1184 // before we overwrite the original file, we will make a backup if there is a demand for that
1185 // if the backup is not created here it will be created internally and will be removed in case of successful saving
1186 const sal_Bool bDoBackup = SvtSaveOptions().IsBackup();
1187 if ( bDoBackup )
1189 AddLog( ::rtl::OUString( OSL_LOG_PREFIX "DoBackup" ) );
1190 rMedium.DoBackup_Impl();
1191 if ( rMedium.GetError() )
1193 SetError( rMedium.GetErrorCode(), ::rtl::OUString( OSL_LOG_PREFIX ) );
1194 rMedium.ResetError();
1198 if ( bStorageBasedSource && bStorageBasedTarget )
1200 // The active storage must be switched. The simple saving is not enough.
1201 // The problem is that the target medium contains target MediaDescriptor.
1203 // In future the switch of the persistance could be done on stream level:
1204 // a new wrapper service will be implemented that allows to exchange
1205 // persistance on the fly. So the real persistance will be set
1206 // to that stream only after successful commit of the storage.
1207 // TODO/LATER:
1208 // create wrapper stream based on the URL
1209 // create a new storage based on this stream
1210 // store to this new storage
1211 // commit the new storage
1212 // call saveCompleted based with this new storage ( get rid of old storage and "frees" URL )
1213 // commit the wrapper stream ( the stream will connect the URL only on commit, after that it will hold it )
1214 // if the last step is failed the stream should stay to be transacted and should be commited on any flush
1215 // so we can forget the stream in any way and the next storage commit will flush it
1217 AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Save: Own to Own" ) );
1219 bNeedsDisconnectionOnFail = DisconnectStorage_Impl(
1220 *pMedium, rMedium );
1221 if ( bNeedsDisconnectionOnFail
1222 || ConnectTmpStorage_Impl( pMedium->GetStorage(), pMedium ) )
1224 pMedium->CloseAndRelease();
1226 // TODO/LATER: for now the medium must be closed since it can already contain streams from old medium
1227 // in future those streams should not be copied in case a valid target url is provided,
1228 // if the url is not provided ( means the document is based on a stream ) this code is not
1229 // reachable.
1230 rMedium.CloseAndRelease();
1231 rMedium.GetOutputStorage();
1234 else if ( !bStorageBasedSource && !bStorageBasedTarget )
1236 // the source and the target formats are alien
1237 // just disconnect the stream from the source format
1238 // so that the target medium can use it
1240 AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Save: Alien to Alien" ) );
1242 pMedium->CloseAndRelease();
1243 rMedium.CloseAndRelease();
1244 rMedium.CreateTempFileNoCopy();
1245 rMedium.GetOutStream();
1247 else if ( !bStorageBasedSource && bStorageBasedTarget )
1249 // the source format is an alien one but the target
1250 // format is an own one so just disconnect the source
1251 // medium
1253 AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Save: Alien to Own" ) );
1255 pMedium->CloseAndRelease();
1256 rMedium.CloseAndRelease();
1257 rMedium.GetOutputStorage();
1259 else // means if ( bStorageBasedSource && !bStorageBasedTarget )
1261 // the source format is an own one but the target is
1262 // an alien format, just connect the source to temporary
1263 // storage
1265 AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Save: Own to Alien" ) );
1267 bNeedsDisconnectionOnFail = DisconnectStorage_Impl(
1268 *pMedium, rMedium );
1269 if ( bNeedsDisconnectionOnFail
1270 || ConnectTmpStorage_Impl( pMedium->GetStorage(), pMedium ) )
1272 pMedium->CloseAndRelease();
1273 rMedium.CloseAndRelease();
1274 rMedium.CreateTempFileNoCopy();
1275 rMedium.GetOutStream();
1280 else
1282 // This is SaveAs or export action, prepare the target medium
1283 // the alien filters still might write directly to the file, that is of course a bug,
1284 // but for now the framework has to be ready for it
1285 // TODO/LATER: let the medium be prepared for alien formats as well
1287 AddLog( ::rtl::OUString( OSL_LOG_PREFIX "SaveAs/Export" ) );
1289 rMedium.CloseAndRelease();
1290 if ( bStorageBasedTarget )
1292 rMedium.GetOutputStorage();
1296 // TODO/LATER: error handling
1297 if( rMedium.GetErrorCode() || pMedium->GetErrorCode() || GetErrorCode() )
1298 return sal_False;
1300 AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Locking" ) );
1302 rMedium.LockOrigFileOnDemand( sal_False, sal_False );
1304 if ( bStorageBasedTarget )
1306 if ( rMedium.GetErrorCode() )
1307 return sal_False;
1309 // If the filter is a "cross export" filter ( f.e. a filter for exporting an impress document from
1310 // a draw document ), the ClassId of the destination storage is different from the ClassId of this
1311 // document. It can be retrieved from the default filter for the desired target format
1312 long nFormat = rMedium.GetFilter()->GetFormat();
1313 SfxFilterMatcher& rMatcher = SFX_APP()->GetFilterMatcher();
1314 const SfxFilter *pFilt = rMatcher.GetFilter4ClipBoardId( nFormat );
1315 if ( pFilt )
1317 if ( pFilt->GetServiceName() != rMedium.GetFilter()->GetServiceName() )
1319 datatransfer::DataFlavor aDataFlavor;
1320 SotExchange::GetFormatDataFlavor( nFormat, aDataFlavor );
1324 uno::Reference< beans::XPropertySet > xProps( rMedium.GetStorage(), uno::UNO_QUERY );
1325 DBG_ASSERT( xProps.is(), "The storage implementation must implement XPropertySet!" );
1326 if ( !xProps.is() )
1327 throw uno::RuntimeException();
1329 xProps->setPropertyValue( ::rtl::OUString("MediaType"),
1330 uno::makeAny( aDataFlavor.MimeType ) );
1332 catch( uno::Exception& )
1339 // TODO/LATER: error handling
1340 if( rMedium.GetErrorCode() || pMedium->GetErrorCode() || GetErrorCode() )
1341 return sal_False;
1343 sal_Bool bOldStat = pImp->bForbidReload;
1344 pImp->bForbidReload = sal_True;
1346 // lock user interface while saving the document
1347 Lock_Impl( this, sal_True );
1349 sal_Bool bOk = sal_False;
1350 // TODO/LATER: get rid of bOk
1352 if( bOwnTarget && !( pFilter->GetFilterFlags() & SFX_FILTER_STARONEFILTER ) )
1354 AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Storing in own format." ) );
1355 uno::Reference< embed::XStorage > xMedStorage = rMedium.GetStorage();
1356 if ( !xMedStorage.is() )
1358 // no saving without storage, unlock UI and return
1359 Lock_Impl( this, sal_False );
1360 pImp->bForbidReload = bOldStat;
1361 AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Storing failed, still no error set." ) );
1362 return sal_False;
1365 // transfer password from the parameters to the storage
1366 uno::Sequence< beans::NamedValue > aEncryptionData;
1367 sal_Bool bPasswdProvided = sal_False;
1368 if ( GetEncryptionData_Impl( rMedium.GetItemSet(), aEncryptionData ) )
1370 bPasswdProvided = sal_True;
1371 try {
1372 ::comphelper::OStorageHelper::SetCommonStorageEncryptionData( xMedStorage, aEncryptionData );
1373 bOk = sal_True;
1375 catch( uno::Exception& )
1377 OSL_FAIL( "Setting of common encryption key failed!" );
1378 SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( OSL_LOG_PREFIX ) );
1381 else
1382 bOk = sal_True;
1384 pFilter = rMedium.GetFilter();
1386 const SfxStringItem *pVersionItem = pSet ? (const SfxStringItem*)
1387 SfxRequest::GetItem( pSet, SID_DOCINFO_COMMENTS, sal_False, TYPE(SfxStringItem) ) : NULL;
1388 ::rtl::OUString aTmpVersionURL;
1390 if ( bOk )
1392 bOk = sal_False;
1393 // currently the case that the storage is the same should be impossible
1394 if ( xMedStorage == GetStorage() )
1396 OSL_ENSURE( !pVersionItem, "This scenario is impossible currently!\n" );
1397 AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Should be impossible." ) );
1398 // usual save procedure
1399 bOk = Save();
1401 else
1403 // save to target
1404 AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Save as own format." ) );
1405 bOk = SaveAsOwnFormat( rMedium );
1406 if ( bOk && pVersionItem )
1408 AddLog( ::rtl::OUString( OSL_LOG_PREFIX "pVersionItem != NULL" ) );
1409 aTmpVersionURL = CreateTempCopyOfStorage_Impl( xMedStorage );
1410 bOk = !aTmpVersionURL.isEmpty();
1416 if ( bOk && GetCreateMode() != SFX_CREATE_MODE_EMBEDDED && !bPasswdProvided )
1418 // store the thumbnail representation image
1419 // the thumbnail is not stored in case of encrypted document
1420 AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Thumbnail creation." ) );
1421 if ( !GenerateAndStoreThumbnail( bPasswdProvided,
1422 sal_False,
1423 pFilter->IsOwnTemplateFormat(),
1424 xMedStorage ) )
1426 // TODO: error handling
1427 OSL_FAIL( "Couldn't store thumbnail representation!" );
1431 if ( bOk )
1433 if ( pImp->bIsSaving || pImp->bPreserveVersions )
1435 AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Preserve versions." ) );
1438 Sequence < util::RevisionTag > aVersions = rMedium.GetVersionList();
1439 if ( aVersions.getLength() )
1441 // copy the version streams
1442 ::rtl::OUString aVersionsName( "Versions" );
1443 uno::Reference< embed::XStorage > xNewVerStor = xMedStorage->openStorageElement(
1444 aVersionsName,
1445 embed::ElementModes::READWRITE );
1446 uno::Reference< embed::XStorage > xOldVerStor = GetStorage()->openStorageElement(
1447 aVersionsName,
1448 embed::ElementModes::READ );
1449 if ( !xNewVerStor.is() || !xOldVerStor.is() )
1450 throw uno::RuntimeException();
1452 for ( sal_Int32 n=0; n<aVersions.getLength(); n++ )
1454 if ( xOldVerStor->hasByName( aVersions[n].Identifier ) )
1455 xOldVerStor->copyElementTo( aVersions[n].Identifier, xNewVerStor, aVersions[n].Identifier );
1458 uno::Reference< embed::XTransactedObject > xTransact( xNewVerStor, uno::UNO_QUERY );
1459 if ( xTransact.is() )
1460 xTransact->commit();
1463 catch( uno::Exception& )
1465 AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Preserve versions has failed." ) );
1466 OSL_FAIL( "Couldn't copy versions!\n" );
1467 bOk = sal_False;
1468 // TODO/LATER: a specific error could be set
1472 if ( bOk && pVersionItem )
1474 // store a version also
1475 const SfxStringItem *pAuthorItem = pSet ? (const SfxStringItem*)
1476 SfxRequest::GetItem( pSet, SID_DOCINFO_AUTHOR, sal_False, TYPE(SfxStringItem) ) : NULL;
1478 // version comment
1479 util::RevisionTag aInfo;
1480 aInfo.Comment = pVersionItem->GetValue();
1482 // version author
1483 String aAuthor;
1484 if ( pAuthorItem )
1485 aInfo.Author = pAuthorItem->GetValue();
1486 else
1487 // if not transferred as a parameter, get it from user settings
1488 aInfo.Author = SvtUserOptions().GetFullName();
1490 DateTime aTime( DateTime::SYSTEM );
1491 aInfo.TimeStamp.Day = aTime.GetDay();
1492 aInfo.TimeStamp.Month = aTime.GetMonth();
1493 aInfo.TimeStamp.Year = aTime.GetYear();
1494 aInfo.TimeStamp.Hours = aTime.GetHour();
1495 aInfo.TimeStamp.Minutes = aTime.GetMin();
1496 aInfo.TimeStamp.Seconds = aTime.GetSec();
1498 if ( bOk )
1500 // add new version information into the versionlist and save the versionlist
1501 // the version list must have been transferred from the "old" medium before
1502 rMedium.AddVersion_Impl( aInfo );
1503 rMedium.SaveVersionList_Impl( sal_True );
1504 bOk = PutURLContentsToVersionStream_Impl( aTmpVersionURL, xMedStorage, aInfo.Identifier );
1507 else if ( bOk && ( pImp->bIsSaving || pImp->bPreserveVersions ) )
1509 rMedium.SaveVersionList_Impl( sal_True );
1513 if ( !aTmpVersionURL.isEmpty() )
1514 ::utl::UCBContentHelper::Kill( aTmpVersionURL );
1516 else
1518 AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Storing in alien format." ) );
1519 // it's a "SaveAs" in an alien format
1520 if ( rMedium.GetFilter() && ( rMedium.GetFilter()->GetFilterFlags() & SFX_FILTER_STARONEFILTER ) )
1521 bOk = ExportTo( rMedium );
1522 else
1523 bOk = ConvertTo( rMedium );
1525 // after saving the document, the temporary object storage must be updated
1526 // if the old object storage was not a temporary one, it will be updated also, because it will be used
1527 // as a source for copying the objects into the new temporary storage that will be created below
1528 // updating means: all child objects must be stored into it
1529 // ( same as on loading, where these objects are copied to the temporary storage )
1530 // but don't commit these changes, because in the case when the old object storage is not a temporary one,
1531 // all changes will be written into the original file !
1533 if( bOk && !bCopyTo )
1534 // we also don't touch any graphical replacements here
1535 bOk = SaveChildren( sal_True );
1538 if ( bOk )
1540 // if ODF version of oasis format changes on saving the signature should not be preserved
1541 if ( bOk && bTryToPreserveScriptSignature && bNoPreserveForOasis )
1542 bTryToPreserveScriptSignature = ( SotStorage::GetVersion( rMedium.GetStorage() ) == SOFFICE_FILEFORMAT_60 );
1544 uno::Reference< security::XDocumentDigitalSignatures > xDDSigns;
1545 if ( bOk && bTryToPreserveScriptSignature )
1547 AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Copying scripting signature." ) );
1549 // if the scripting code was not changed and it is signed the signature should be preserved
1550 // unfortunately at this point we have only information whether the basic code has changed or not
1551 // so the only way is to check the signature if the basic was not changed
1554 // get the ODF version of the new medium
1555 uno::Sequence< uno::Any > aArgs( 1 );
1556 aArgs[0] <<= ::rtl::OUString();
1559 uno::Reference < beans::XPropertySet > xPropSet( rMedium.GetStorage(), uno::UNO_QUERY_THROW );
1560 aArgs[0] = xPropSet->getPropertyValue( ::rtl::OUString( "Version" ) );
1562 catch( uno::Exception& )
1566 xDDSigns = uno::Reference< security::XDocumentDigitalSignatures >(
1567 comphelper::getProcessServiceFactory()->createInstanceWithArguments(
1568 rtl::OUString(
1569 "com.sun.star.security.DocumentDigitalSignatures" ),
1570 aArgs ),
1571 uno::UNO_QUERY_THROW );
1573 ::rtl::OUString aScriptSignName = xDDSigns->getScriptingContentSignatureDefaultStreamName();
1575 if ( !aScriptSignName.isEmpty() )
1577 pMedium->Close();
1579 // target medium is still not commited, it should not be closed
1580 // commit the package storage and close it, but leave the streams open
1581 rMedium.StorageCommit_Impl();
1582 rMedium.CloseStorage();
1584 uno::Reference< embed::XStorage > xReadOrig = pMedium->GetZipStorageToSign_Impl();
1585 if ( !xReadOrig.is() )
1586 throw uno::RuntimeException();
1587 uno::Reference< embed::XStorage > xMetaInf = xReadOrig->openStorageElement(
1588 ::rtl::OUString( "META-INF" ),
1589 embed::ElementModes::READ );
1591 uno::Reference< embed::XStorage > xTarget = rMedium.GetZipStorageToSign_Impl( sal_False );
1592 if ( !xTarget.is() )
1593 throw uno::RuntimeException();
1594 uno::Reference< embed::XStorage > xTargetMetaInf = xTarget->openStorageElement(
1595 ::rtl::OUString( "META-INF" ),
1596 embed::ElementModes::READWRITE );
1598 if ( xMetaInf.is() && xTargetMetaInf.is() )
1600 xMetaInf->copyElementTo( aScriptSignName, xTargetMetaInf, aScriptSignName );
1602 uno::Reference< embed::XTransactedObject > xTransact( xTargetMetaInf, uno::UNO_QUERY );
1603 if ( xTransact.is() )
1604 xTransact->commit();
1606 xTargetMetaInf->dispose();
1608 // now check the copied signature
1609 uno::Sequence< security::DocumentSignatureInformation > aInfos =
1610 xDDSigns->verifyScriptingContentSignatures( xTarget,
1611 uno::Reference< io::XInputStream >() );
1612 sal_uInt16 nState = ImplCheckSignaturesInformation( aInfos );
1613 if ( nState == SIGNATURESTATE_SIGNATURES_OK || nState == SIGNATURESTATE_SIGNATURES_NOTVALIDATED
1614 || nState == SIGNATURESTATE_SIGNATURES_PARTIAL_OK)
1616 rMedium.SetCachedSignatureState_Impl( nState );
1618 // commit the ZipStorage from target medium
1619 xTransact.set( xTarget, uno::UNO_QUERY );
1620 if ( xTransact.is() )
1621 xTransact->commit();
1623 else
1625 // it should not happen, the copies signature is invalid!
1626 // throw the changes away
1627 OSL_FAIL( "An invalid signature was copied!" );
1632 catch( uno::Exception& )
1636 pMedium->Close();
1637 rMedium.CloseZipStorage_Impl();
1640 AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Medium commit." ) );
1642 // transfer data to its destinated location
1643 // the medium commits the storage or the stream it is based on
1644 RegisterTransfer( rMedium );
1645 bOk = rMedium.Commit();
1647 if ( bOk )
1649 AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Storing is successful." ) );
1651 // if the target medium is an alien format and the "old" medium was an own format and the "old" medium
1652 // has a name, the object storage must be exchanged, because now we need a new temporary storage
1653 // as object storage
1654 if ( !bCopyTo && bStorageBasedSource && !bStorageBasedTarget )
1656 if ( bStoreToSameLocation )
1658 // if the old medium already disconnected from document storage, the storage still must
1659 // be switched if backup file is used
1660 if ( bNeedsDisconnectionOnFail )
1661 ConnectTmpStorage_Impl( pImp->m_xDocStorage, NULL );
1663 else if ( pMedium->GetName().Len()
1664 || ( pMedium->HasStorage_Impl() && pMedium->WillDisposeStorageOnClose_Impl() ) )
1666 OSL_ENSURE( pMedium->GetName().Len(), "Fallback is used, the medium without name should not dispose the storage!\n" );
1667 // copy storage of old medium to new temporary storage and take this over
1668 if( !ConnectTmpStorage_Impl( pMedium->GetStorage(), pMedium ) )
1670 AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Process after storing has failed." ) );
1671 bOk = sal_False;
1676 else
1678 AddLog( ::rtl::OUString( OSL_LOG_PREFIX "Storing has failed." ) );
1680 // in case the document storage was connected to backup temporarely it must be disconnected now
1681 if ( bNeedsDisconnectionOnFail )
1682 ConnectTmpStorage_Impl( pImp->m_xDocStorage, NULL );
1686 // unlock user interface
1687 Lock_Impl( this, sal_False );
1688 pImp->bForbidReload = bOldStat;
1690 if ( bOk )
1694 ::ucbhelper::Content aContent( rMedium.GetName(), com::sun::star::uno::Reference < XCommandEnvironment >() );
1695 com::sun::star::uno::Reference < XPropertySetInfo > xProps = aContent.getProperties();
1696 if ( xProps.is() )
1698 ::rtl::OUString aAuthor( "Author" );
1699 ::rtl::OUString aKeywords( "Keywords" );
1700 ::rtl::OUString aSubject( "Subject" );
1701 Any aAny;
1703 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
1704 GetModel(), uno::UNO_QUERY_THROW);
1705 uno::Reference<document::XDocumentProperties> xDocProps
1706 = xDPS->getDocumentProperties();
1708 if ( xProps->hasPropertyByName( aAuthor ) )
1710 aAny <<= xDocProps->getAuthor();
1711 aContent.setPropertyValue( aAuthor, aAny );
1713 if ( xProps->hasPropertyByName( aKeywords ) )
1715 aAny <<= ::comphelper::string::convertCommaSeparated(
1716 xDocProps->getKeywords());
1717 aContent.setPropertyValue( aKeywords, aAny );
1719 if ( xProps->hasPropertyByName( aSubject ) )
1721 aAny <<= xDocProps->getSubject();
1722 aContent.setPropertyValue( aSubject, aAny );
1726 catch( Exception& )
1731 return bOk;
1734 //------------------------------------------------------------------------
1735 sal_Bool SfxObjectShell::DisconnectStorage_Impl( SfxMedium& rSrcMedium, SfxMedium& rTargetMedium )
1737 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::DisconnectStorage_Impl" );
1739 // this method disconnects the storage from source medium, and attaches it to the backup created by the target medium
1741 uno::Reference< embed::XStorage > xStorage = rSrcMedium.GetStorage();
1743 sal_Bool bResult = sal_False;
1744 if ( xStorage == pImp->m_xDocStorage )
1748 uno::Reference< embed::XOptimizedStorage > xOptStorage( xStorage, uno::UNO_QUERY_THROW );
1749 ::rtl::OUString aBackupURL = rTargetMedium.GetBackup_Impl();
1750 if ( aBackupURL.isEmpty() )
1752 // the backup could not be created, try to disconnect the storage and close the source SfxMedium
1753 // in this case the optimization is not possible, connect storage to a temporary file
1754 rTargetMedium.ResetError();
1755 xOptStorage->writeAndAttachToStream( uno::Reference< io::XStream >() );
1756 rSrcMedium.CanDisposeStorage_Impl( sal_False );
1757 rSrcMedium.Close();
1759 // now try to create the backup
1760 rTargetMedium.GetBackup_Impl();
1762 else
1764 // the following call will only compare stream sizes
1765 // TODO/LATER: this is a very risky part, since if the URL contents are different from the storage
1766 // contents, the storag will be broken
1767 xOptStorage->attachToURL( aBackupURL, sal_True );
1769 // the storage is successfuly attached to backup, thus it it owned by the document not by the medium
1770 rSrcMedium.CanDisposeStorage_Impl( sal_False );
1771 bResult = sal_True;
1774 catch ( uno::Exception& )
1778 OSL_ENSURE( bResult, "Storage disconnecting has failed - affects performance!" );
1780 return bResult;
1783 //------------------------------------------------------------------------
1785 sal_Bool SfxObjectShell::ConnectTmpStorage_Impl(
1786 const uno::Reference< embed::XStorage >& xStorage,
1787 SfxMedium* pMediumArg )
1789 /* [Description]
1791 If the application operates on a temporary storage, then it may not take
1792 the temporary storage from the SaveCompleted. Therefore the new storage
1793 is connected already here in this case and SaveCompleted then does nothing.
1797 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::ConnectTmpStorage_Impl" );
1799 sal_Bool bResult = sal_False;
1801 if ( xStorage.is() )
1805 // the empty argument means that the storage will create temporary stream itself
1806 uno::Reference< embed::XOptimizedStorage > xOptStorage( xStorage, uno::UNO_QUERY_THROW );
1807 xOptStorage->writeAndAttachToStream( uno::Reference< io::XStream >() );
1809 // the storage is successfuly disconnected from the original sources, thus the medium must not dispose it
1810 if ( pMediumArg )
1811 pMediumArg->CanDisposeStorage_Impl( sal_False );
1813 bResult = sal_True;
1815 catch( uno::Exception& )
1819 // if switching of the storage does not work for any reason ( nonroot storage for example ) use the old method
1820 if ( !bResult ) try
1822 uno::Reference< embed::XStorage > xTmpStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
1824 DBG_ASSERT( xTmpStorage.is(), "If a storage can not be created an exception must be thrown!\n" );
1825 if ( !xTmpStorage.is() )
1826 throw uno::RuntimeException();
1828 // TODO/LATER: may be it should be done in SwitchPersistence also
1829 // TODO/LATER: find faster way to copy storage; perhaps sharing with backup?!
1830 xStorage->copyToStorage( xTmpStorage );
1831 bResult = SaveCompleted( xTmpStorage );
1833 if ( bResult )
1835 pImp->pBasicManager->setStorage( xTmpStorage );
1837 // Get rid of this workaround after issue i113914 is fixed
1840 uno::Reference< script::XStorageBasedLibraryContainer > xBasicLibraries( pImp->xBasicLibraries, uno::UNO_QUERY_THROW );
1841 xBasicLibraries->setRootStorage( xTmpStorage );
1843 catch( uno::Exception& )
1847 uno::Reference< script::XStorageBasedLibraryContainer > xDialogLibraries( pImp->xDialogLibraries, uno::UNO_QUERY_THROW );
1848 xDialogLibraries->setRootStorage( xTmpStorage );
1850 catch( uno::Exception& )
1854 catch( uno::Exception& )
1857 if ( !bResult )
1859 // TODO/LATER: may need error code setting based on exception
1860 SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( OSL_LOG_PREFIX ) );
1864 return bResult;
1867 //-------------------------------------------------------------------------
1869 sal_Bool SfxObjectShell::DoSaveObjectAs( SfxMedium& rMedium, sal_Bool bCommit )
1871 sal_Bool bOk = sal_False;
1873 ModifyBlocker_Impl aBlock( this );
1875 uno::Reference < embed::XStorage > xNewStor = rMedium.GetStorage();
1876 if ( !xNewStor.is() )
1877 return sal_False;
1879 uno::Reference < beans::XPropertySet > xPropSet( xNewStor, uno::UNO_QUERY );
1880 if ( xPropSet.is() )
1882 Any a = xPropSet->getPropertyValue( ::rtl::OUString("MediaType" ) );
1883 ::rtl::OUString aMediaType;
1884 if ( !(a>>=aMediaType) || aMediaType.isEmpty() )
1886 OSL_FAIL( "The mediatype must be set already!\n" );
1887 SetupStorage( xNewStor, SOFFICE_FILEFORMAT_CURRENT, sal_False );
1890 pImp->bIsSaving = sal_False;
1891 bOk = SaveAsOwnFormat( rMedium );
1893 if ( bCommit )
1895 try {
1896 uno::Reference< embed::XTransactedObject > xTransact( xNewStor, uno::UNO_QUERY_THROW );
1897 xTransact->commit();
1899 catch( uno::Exception& )
1901 OSL_FAIL( "The strotage was not commited on DoSaveAs!\n" );
1907 return bOk;
1910 //-------------------------------------------------------------------------
1911 // TODO/LATER: may be the call must be removed completelly
1912 sal_Bool SfxObjectShell::DoSaveAs( SfxMedium& rMedium )
1914 // here only root storages are included, which are stored via temp file
1915 rMedium.CreateTempFileNoCopy();
1916 SetError(rMedium.GetErrorCode(), ::rtl::OUString( OSL_LOG_PREFIX ) );
1917 if ( GetError() )
1918 return sal_False;
1920 // copy version list from "old" medium to target medium, so it can be used on saving
1921 if ( pImp->bPreserveVersions )
1922 rMedium.TransferVersionList_Impl( *pMedium );
1924 sal_Bool bRet = SaveTo_Impl( rMedium, NULL );
1925 if ( !bRet )
1926 SetError(rMedium.GetErrorCode(), ::rtl::OUString( OSL_LOG_PREFIX ) );
1927 return bRet;
1930 //-------------------------------------------------------------------------
1932 sal_Bool SfxObjectShell::DoSaveCompleted( SfxMedium* pNewMed )
1934 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::DoSaveCompleted" );
1936 sal_Bool bOk = sal_True;
1937 sal_Bool bMedChanged = pNewMed && pNewMed!=pMedium;
1939 DBG_ASSERT( !pNewMed || pNewMed->GetError() == ERRCODE_NONE, "DoSaveCompleted: Medium has error!" );
1941 // delete Medium (and Storage!) after all notifications
1942 SfxMedium* pOld = pMedium;
1943 if ( bMedChanged )
1945 pMedium = pNewMed;
1946 pMedium->CanDisposeStorage_Impl( sal_True );
1949 const SfxFilter *pFilter = pMedium ? pMedium->GetFilter() : 0;
1950 if ( pNewMed )
1952 if( bMedChanged )
1954 if( pNewMed->GetName().Len() )
1955 bHasName = sal_True;
1956 Broadcast( SfxSimpleHint(SFX_HINT_NAMECHANGED) );
1957 getDocProperties()->setGenerator(
1958 ::utl::DocInfoHelper::GetGeneratorString() );
1961 uno::Reference< embed::XStorage > xStorage;
1962 if ( !pFilter || IsPackageStorageFormat_Impl( *pMedium ) )
1964 uno::Reference < embed::XStorage > xOld = GetStorage();
1966 // when the package based medium is broken and has no storage or if the storage
1967 // is the same as the document storage the current document storage should be preserved
1968 xStorage = pMedium->GetStorage();
1969 bOk = SaveCompleted( xStorage );
1970 if ( bOk && xStorage.is() && xOld != xStorage
1971 && (!pOld || !pOld->HasStorage_Impl() || xOld != pOld->GetStorage() ) )
1973 // old own storage was not controlled by old Medium -> dispose it
1974 try {
1975 xOld->dispose();
1976 } catch( uno::Exception& )
1978 // the storage is disposed already
1979 // can happen during reload scenario when the medium has
1980 // disposed it during the closing
1981 // will be fixed in one of the next milestones
1985 else
1987 if( pMedium->GetOpenMode() & STREAM_WRITE )
1988 pMedium->GetInStream();
1989 xStorage = GetStorage();
1992 // TODO/LATER: may be this code will be replaced, but not sure
1993 // Set storage in document library containers
1994 pImp->pBasicManager->setStorage( xStorage );
1996 // Get rid of this workaround after issue i113914 is fixed
1999 uno::Reference< script::XStorageBasedLibraryContainer > xBasicLibraries( pImp->xBasicLibraries, uno::UNO_QUERY_THROW );
2000 xBasicLibraries->setRootStorage( xStorage );
2002 catch( uno::Exception& )
2006 uno::Reference< script::XStorageBasedLibraryContainer > xDialogLibraries( pImp->xDialogLibraries, uno::UNO_QUERY_THROW );
2007 xDialogLibraries->setRootStorage( xStorage );
2009 catch( uno::Exception& )
2012 else
2014 if( pMedium )
2016 if( pFilter && !IsPackageStorageFormat_Impl( *pMedium ) && (pMedium->GetOpenMode() & STREAM_WRITE ))
2018 pMedium->ReOpen();
2019 bOk = SaveCompletedChildren( sal_False );
2021 else
2022 bOk = SaveCompleted( NULL );
2024 // either Save or ConvertTo
2025 else
2026 bOk = SaveCompleted( NULL );
2029 if ( bOk && pNewMed )
2031 if( bMedChanged )
2033 delete pOld;
2035 uno::Reference< frame::XModel > xModel = GetModel();
2036 if ( xModel.is() )
2038 ::rtl::OUString aURL = pNewMed->GetOrigURL();
2039 uno::Sequence< beans::PropertyValue > aMediaDescr;
2040 TransformItems( SID_OPENDOC, *pNewMed->GetItemSet(), aMediaDescr );
2043 xModel->attachResource( aURL, aMediaDescr );
2045 catch( uno::Exception& )
2049 // before the title regenerated the document must loose the signatures
2050 pImp->nDocumentSignatureState = SIGNATURESTATE_NOSIGNATURES;
2051 pImp->nScriptingSignatureState = pNewMed->GetCachedSignatureState_Impl();
2052 OSL_ENSURE( pImp->nScriptingSignatureState != SIGNATURESTATE_SIGNATURES_BROKEN, "The signature must not be broken at this place" );
2053 pImp->bSignatureErrorIsShown = sal_False;
2055 // TODO/LATER: in future the medium must control own signature state, not the document
2056 pNewMed->SetCachedSignatureState_Impl( SIGNATURESTATE_NOSIGNATURES ); // set the default value back
2058 // Set new title
2059 if ( pNewMed->GetName().Len() && SFX_CREATE_MODE_EMBEDDED != eCreateMode )
2060 InvalidateName();
2061 SetModified(sal_False); // reset only by set medium
2062 Broadcast( SfxSimpleHint(SFX_HINT_MODECHANGED) );
2064 // this is the end of the saving process, it is possible that
2065 // the file was changed
2066 // between medium commit and this step (attributes change and so on)
2067 // so get the file date again
2068 if ( pNewMed->DocNeedsFileDateCheck() )
2069 pNewMed->GetInitFileDate( sal_True );
2073 pMedium->ClearBackup_Impl();
2074 pMedium->LockOrigFileOnDemand( sal_True, sal_False );
2076 AddToRecentlyUsedList();
2078 return bOk;
2081 void SfxObjectShell::AddToRecentlyUsedList()
2083 INetURLObject aUrl( pMedium->GetOrigURL() );
2085 if ( aUrl.GetProtocol() == INET_PROT_FILE )
2087 const SfxFilter* pOrgFilter = pMedium->GetOrigFilter();
2088 Application::AddToRecentDocumentList( aUrl.GetURLNoPass( INetURLObject::NO_DECODE ),
2089 (pOrgFilter) ? pOrgFilter->GetMimeType() : ::rtl::OUString() );
2093 //-------------------------------------------------------------------------
2095 sal_Bool SfxObjectShell::ConvertFrom
2097 SfxMedium& /*rMedium*/ /* <SfxMedium>, which describes the source file
2098 (for example file name, <SfxFilter>,
2099 Open-Modi and so on) */
2102 /* [Description]
2104 This method is called for loading of documents over all filters which are
2105 not SFX_FILTER_OWN or for which no clipboard format has been registered
2106 (thus no storage format that is used). In other words, whith this method
2107 it is imported.
2109 Files which are to be opened here should be opened through 'rMedium'
2110 to guarantee the right open modes. Especially if the format is retained
2111 (only possible with SFX_FILTER_SIMULATE or SFX_FILTER_ONW) file which must
2112 be opened STREAM_SHARE_DENYWRITE.
2114 [Return value]
2116 sal_Bool sal_True
2117 The document could be loaded.
2119 sal_False
2120 The document could not be loaded, an error code
2121 received through <SvMedium::GetError()const>
2123 [Example]
2125 sal_Bool DocSh::ConvertFrom( SfxMedium &rMedium )
2127 SvStreamRef xStream = rMedium.GetInStream();
2128 if( xStream.is() )
2130 xStream->SetBufferSize(4096);
2131 *xStream >> ...;
2133 // Do not call 'rMedium.CloseInStream()'! Keep File locked!
2134 return SVSTREAM_OK == rMedium.GetError();
2137 return sal_False;
2140 [Cross-references]
2142 <SfxObjectShell::ConvertTo(SfxMedium&)>
2143 <SFX_FILTER_REGISTRATION>
2146 return sal_False;
2149 sal_Bool SfxObjectShell::ImportFrom( SfxMedium& rMedium, bool bInsert )
2151 ::rtl::OUString aTypeName( rMedium.GetFilter()->GetTypeName() );
2152 ::rtl::OUString aFilterName( rMedium.GetFilter()->GetFilterName() );
2154 uno::Reference< lang::XMultiServiceFactory > xMan = ::comphelper::getProcessServiceFactory();
2155 uno::Reference < lang::XMultiServiceFactory > xFilterFact (
2156 xMan->createInstance( DEFINE_CONST_UNICODE( "com.sun.star.document.FilterFactory" ) ), uno::UNO_QUERY );
2158 uno::Sequence < beans::PropertyValue > aProps;
2159 uno::Reference < container::XNameAccess > xFilters ( xFilterFact, uno::UNO_QUERY );
2160 if ( xFilters->hasByName( aFilterName ) )
2162 xFilters->getByName( aFilterName ) >>= aProps;
2163 rMedium.GetItemSet()->Put( SfxStringItem( SID_FILTER_NAME, aFilterName ) );
2166 ::rtl::OUString aFilterImplName;
2167 sal_Int32 nFilterProps = aProps.getLength();
2168 for ( sal_Int32 nFilterProp = 0; nFilterProp<nFilterProps; nFilterProp++ )
2170 const beans::PropertyValue& rFilterProp = aProps[nFilterProp];
2171 if ( rFilterProp.Name.compareToAscii("FilterService") == COMPARE_EQUAL )
2173 rFilterProp.Value >>= aFilterImplName;
2174 break;
2178 uno::Reference< document::XFilter > xLoader;
2179 if ( !aFilterImplName.isEmpty() )
2181 try{
2182 xLoader = uno::Reference< document::XFilter >
2183 ( xFilterFact->createInstanceWithArguments( aFilterName, uno::Sequence < uno::Any >() ), uno::UNO_QUERY );
2184 }catch(const uno::Exception&)
2185 { xLoader.clear(); }
2187 if ( xLoader.is() )
2189 // it happens that xLoader does not support xImporter!
2190 try{
2191 uno::Reference< lang::XComponent > xComp( GetModel(), uno::UNO_QUERY_THROW );
2192 uno::Reference< document::XImporter > xImporter( xLoader, uno::UNO_QUERY_THROW );
2193 xImporter->setTargetDocument( xComp );
2195 uno::Sequence < beans::PropertyValue > lDescriptor;
2196 rMedium.GetItemSet()->Put( SfxStringItem( SID_FILE_NAME, rMedium.GetName() ) );
2197 TransformItems( SID_OPENDOC, *rMedium.GetItemSet(), lDescriptor );
2199 com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue > aArgs ( lDescriptor.getLength() );
2200 com::sun::star::beans::PropertyValue * pNewValue = aArgs.getArray();
2201 const com::sun::star::beans::PropertyValue * pOldValue = lDescriptor.getConstArray();
2202 const OUString sInputStream ( "InputStream" );
2204 sal_Bool bHasInputStream = sal_False;
2205 sal_Bool bHasBaseURL = sal_False;
2206 sal_Int32 i;
2207 sal_Int32 nEnd = lDescriptor.getLength();
2209 for ( i = 0; i < nEnd; i++ )
2211 pNewValue[i] = pOldValue[i];
2212 if ( pOldValue [i].Name == sInputStream )
2213 bHasInputStream = sal_True;
2214 else if ( pOldValue[i].Name == "DocumentBaseURL" )
2215 bHasBaseURL = sal_True;
2218 if ( !bHasInputStream )
2220 aArgs.realloc ( ++nEnd );
2221 aArgs[nEnd-1].Name = sInputStream;
2222 aArgs[nEnd-1].Value <<= com::sun::star::uno::Reference < com::sun::star::io::XInputStream > ( new utl::OSeekableInputStreamWrapper ( *rMedium.GetInStream() ) );
2225 if ( !bHasBaseURL )
2227 aArgs.realloc ( ++nEnd );
2228 aArgs[nEnd-1].Name = ::rtl::OUString( "DocumentBaseURL" );
2229 aArgs[nEnd-1].Value <<= rMedium.GetBaseURL();
2232 if ( bInsert ) {
2233 aArgs.realloc( ++nEnd );
2234 aArgs[nEnd-1].Name = ::rtl::OUString( "InsertMode" );
2235 aArgs[nEnd-1].Value <<= (sal_Bool) sal_True;
2238 return xLoader->filter( aArgs );
2239 }catch(...)
2243 return sal_False;
2246 sal_Bool SfxObjectShell::ExportTo( SfxMedium& rMedium )
2248 ::rtl::OUString aTypeName( rMedium.GetFilter()->GetTypeName() );
2249 ::rtl::OUString aFilterName( rMedium.GetFilter()->GetFilterName() );
2250 uno::Reference< document::XExporter > xExporter;
2253 uno::Reference< lang::XMultiServiceFactory > xMan = ::comphelper::getProcessServiceFactory();
2254 uno::Reference < lang::XMultiServiceFactory > xFilterFact (
2255 xMan->createInstance( DEFINE_CONST_UNICODE( "com.sun.star.document.FilterFactory" ) ), uno::UNO_QUERY );
2257 uno::Sequence < beans::PropertyValue > aProps;
2258 uno::Reference < container::XNameAccess > xFilters ( xFilterFact, uno::UNO_QUERY );
2259 if ( xFilters->hasByName( aFilterName ) )
2260 xFilters->getByName( aFilterName ) >>= aProps;
2262 ::rtl::OUString aFilterImplName;
2263 sal_Int32 nFilterProps = aProps.getLength();
2264 for ( sal_Int32 nFilterProp = 0; nFilterProp<nFilterProps; nFilterProp++ )
2266 const beans::PropertyValue& rFilterProp = aProps[nFilterProp];
2267 if ( rFilterProp.Name.compareToAscii("FilterService") == COMPARE_EQUAL )
2269 rFilterProp.Value >>= aFilterImplName;
2270 break;
2274 if ( !aFilterImplName.isEmpty() )
2276 try{
2277 xExporter = uno::Reference< document::XExporter >
2278 ( xFilterFact->createInstanceWithArguments( aFilterName, uno::Sequence < uno::Any >() ), uno::UNO_QUERY );
2279 }catch(const uno::Exception&)
2280 { xExporter.clear(); }
2284 if ( xExporter.is() )
2286 try{
2287 uno::Reference< lang::XComponent > xComp( GetModel(), uno::UNO_QUERY_THROW );
2288 uno::Reference< document::XFilter > xFilter( xExporter, uno::UNO_QUERY_THROW );
2289 xExporter->setSourceDocument( xComp );
2291 com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue > aOldArgs;
2292 SfxItemSet* pItems = rMedium.GetItemSet();
2293 TransformItems( SID_SAVEASDOC, *pItems, aOldArgs );
2295 const com::sun::star::beans::PropertyValue * pOldValue = aOldArgs.getConstArray();
2296 com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue > aArgs ( aOldArgs.getLength() );
2297 com::sun::star::beans::PropertyValue * pNewValue = aArgs.getArray();
2299 // put in the REAL file name, and copy all PropertyValues
2300 const OUString sOutputStream ( "OutputStream" );
2301 const OUString sStream ( "StreamForOutput" );
2302 sal_Bool bHasOutputStream = sal_False;
2303 sal_Bool bHasStream = sal_False;
2304 sal_Bool bHasBaseURL = sal_False;
2305 sal_Int32 i;
2306 sal_Int32 nEnd = aOldArgs.getLength();
2308 for ( i = 0; i < nEnd; i++ )
2310 pNewValue[i] = pOldValue[i];
2311 if ( pOldValue[i].Name == "FileName" )
2312 pNewValue[i].Value <<= OUString ( rMedium.GetName() );
2313 else if ( pOldValue[i].Name == sOutputStream )
2314 bHasOutputStream = sal_True;
2315 else if ( pOldValue[i].Name == sStream )
2316 bHasStream = sal_True;
2317 else if ( pOldValue[i].Name == "DocumentBaseURL" )
2318 bHasBaseURL = sal_True;
2321 if ( !bHasOutputStream )
2323 aArgs.realloc ( ++nEnd );
2324 aArgs[nEnd-1].Name = sOutputStream;
2325 aArgs[nEnd-1].Value <<= com::sun::star::uno::Reference < com::sun::star::io::XOutputStream > ( new utl::OOutputStreamWrapper ( *rMedium.GetOutStream() ) );
2328 // add stream as well, for OOX export and maybe others
2329 if ( !bHasStream )
2331 aArgs.realloc ( ++nEnd );
2332 aArgs[nEnd-1].Name = sStream;
2333 aArgs[nEnd-1].Value <<= com::sun::star::uno::Reference < com::sun::star::io::XStream > ( new utl::OStreamWrapper ( *rMedium.GetOutStream() ) );
2336 if ( !bHasBaseURL )
2338 aArgs.realloc ( ++nEnd );
2339 aArgs[nEnd-1].Name = ::rtl::OUString( "DocumentBaseURL" );
2340 aArgs[nEnd-1].Value <<= rMedium.GetBaseURL( sal_True );
2343 return xFilter->filter( aArgs );
2344 }catch(const uno::Exception&)
2348 return sal_False;
2351 //-------------------------------------------------------------------------
2353 sal_Bool SfxObjectShell::ConvertTo
2355 SfxMedium& /*rMedium*/ /* <SfxMedium>, which describes the target file
2356 (for example file name, <SfxFilter>,
2357 Open-Modi and so on) */
2360 /* [Description]
2362 This method is called for saving of documents over all filters which are
2363 not SFX_FILTER_OWN or for which no clipboard format has been registered
2364 (thus no storage format that is used). In other words, with this method
2365 it is exported.
2367 Files which are to be opened here should be opened through 'rMedium'
2368 to guarantee the right open modes. Especially if the format is retained
2369 (only possible with SFX_FILTER_SIMULATE or SFX_FILTER_ONW) file which must
2370 be opened STREAM_SHARE_DENYWRITE.
2372 [Return value]
2374 sal_Bool sal_True
2375 The document could be saved.
2377 sal_False
2378 The document could not be saved, an error code is
2379 received by <SvMedium::GetError()const>
2382 [Example]
2384 sal_Bool DocSh::ConvertTo( SfxMedium &rMedium )
2386 SvStreamRef xStream = rMedium.GetOutStream();
2387 if ( xStream.is() )
2389 xStream->SetBufferSize(4096);
2390 *xStream << ...;
2392 rMedium.CloseOutStream(); // opens the InStream automatically
2393 return SVSTREAM_OK == rMedium.GetError();
2395 return sal_False ;
2398 [Cross-references]
2400 <SfxObjectShell::ConvertFrom(SfxMedium&)>
2401 <SFX_FILTER_REGISTRATION>
2405 return sal_False;
2408 //-------------------------------------------------------------------------
2410 sal_Bool SfxObjectShell::DoSave_Impl( const SfxItemSet* pArgs )
2412 SfxMedium* pRetrMedium = GetMedium();
2413 const SfxFilter* pFilter = pRetrMedium->GetFilter();
2415 // copy the original itemset, but remove the "version" item, because pMediumTmp
2416 // is a new medium "from scratch", so no version should be stored into it
2417 SfxItemSet* pSet = new SfxAllItemSet(*pRetrMedium->GetItemSet());
2418 pSet->ClearItem( SID_VERSION );
2419 pSet->ClearItem( SID_DOC_BASEURL );
2421 // create a medium as a copy; this medium is only for writingm, because it
2422 // uses the same name as the original one writing is done through a copy,
2423 // that will be transferred to the target (of course after calling HandsOff)
2424 SfxMedium* pMediumTmp = new SfxMedium( pRetrMedium->GetName(), pRetrMedium->GetOpenMode(), pFilter, pSet );
2425 pMediumTmp->SetLongName( pRetrMedium->GetLongName() );
2426 if ( pMediumTmp->GetErrorCode() != ERRCODE_NONE )
2428 SetError( pMediumTmp->GetError(), ::rtl::OUString( OSL_LOG_PREFIX ) );
2429 delete pMediumTmp;
2430 return sal_False;
2433 // copy version list from "old" medium to target medium, so it can be used on saving
2434 pMediumTmp->TransferVersionList_Impl( *pRetrMedium );
2436 // an interaction handler here can aquire only in case of GUI Saving
2437 // and should be removed after the saving is done
2438 com::sun::star::uno::Reference< XInteractionHandler > xInteract;
2439 SFX_ITEMSET_ARG( pArgs, pxInteractionItem, SfxUnoAnyItem, SID_INTERACTIONHANDLER, sal_False );
2440 if ( pxInteractionItem && ( pxInteractionItem->GetValue() >>= xInteract ) && xInteract.is() )
2441 pMediumTmp->GetItemSet()->Put( SfxUnoAnyItem( SID_INTERACTIONHANDLER, makeAny( xInteract ) ) );
2443 sal_Bool bSaved = sal_False;
2444 if( !GetError() && SaveTo_Impl( *pMediumTmp, pArgs ) )
2446 bSaved = sal_True;
2448 if( pMediumTmp->GetItemSet() )
2450 pMediumTmp->GetItemSet()->ClearItem( SID_INTERACTIONHANDLER );
2451 pMediumTmp->GetItemSet()->ClearItem( SID_PROGRESS_STATUSBAR_CONTROL );
2454 SetError(pMediumTmp->GetErrorCode(), ::rtl::OUString( OSL_LOG_PREFIX ) );
2456 sal_Bool bOpen( sal_False );
2457 bOpen = DoSaveCompleted( pMediumTmp );
2459 DBG_ASSERT(bOpen,"Error handling for DoSaveCompleted not implemented");
2460 (void)bOpen;
2462 else
2464 // transfer error code from medium to objectshell
2465 SetError( pMediumTmp->GetError(), ::rtl::OUString( OSL_LOG_PREFIX ) );
2467 // reconnect to object storage
2468 DoSaveCompleted( 0 );
2470 if( pRetrMedium->GetItemSet() )
2472 pRetrMedium->GetItemSet()->ClearItem( SID_INTERACTIONHANDLER );
2473 pRetrMedium->GetItemSet()->ClearItem( SID_PROGRESS_STATUSBAR_CONTROL );
2476 delete pMediumTmp;
2479 SetModified( !bSaved );
2480 return bSaved;
2483 //-------------------------------------------------------------------------
2485 sal_Bool SfxObjectShell::Save_Impl( const SfxItemSet* pSet )
2487 if ( IsReadOnly() )
2489 SetError( ERRCODE_SFX_DOCUMENTREADONLY, ::rtl::OUString( OSL_LOG_PREFIX ) );
2490 return sal_False;
2493 DBG_CHKTHIS(SfxObjectShell, 0);
2495 pImp->bIsSaving = sal_True;
2496 sal_Bool bSaved = sal_False;
2497 SFX_ITEMSET_ARG( GetMedium()->GetItemSet(), pSalvageItem, SfxStringItem, SID_DOC_SALVAGE, sal_False);
2498 if ( pSalvageItem )
2500 SFX_ITEMSET_ARG( GetMedium()->GetItemSet(), pFilterItem, SfxStringItem, SID_FILTER_NAME, sal_False);
2501 String aFilterName;
2502 const SfxFilter *pFilter = NULL;
2503 if ( pFilterItem )
2504 pFilter = SfxFilterMatcher( String::CreateFromAscii( GetFactory().GetShortName()) ).GetFilter4FilterName( aFilterName );
2506 SfxMedium *pMed = new SfxMedium(
2507 pSalvageItem->GetValue(), STREAM_READWRITE | STREAM_SHARE_DENYWRITE | STREAM_TRUNC, pFilter );
2509 SFX_ITEMSET_ARG( GetMedium()->GetItemSet(), pPasswordItem, SfxStringItem, SID_PASSWORD, sal_False );
2510 if ( pPasswordItem )
2511 pMed->GetItemSet()->Put( *pPasswordItem );
2513 bSaved = DoSaveAs( *pMed );
2514 if ( bSaved )
2515 bSaved = DoSaveCompleted( pMed );
2516 else
2517 delete pMed;
2519 else
2520 bSaved = DoSave_Impl( pSet );
2521 return bSaved;
2524 //-------------------------------------------------------------------------
2526 sal_Bool SfxObjectShell::CommonSaveAs_Impl
2528 const INetURLObject& aURL,
2529 const String& aFilterName,
2530 SfxItemSet* aParams
2533 if( aURL.HasError() )
2535 SetError( ERRCODE_IO_INVALIDPARAMETER, ::rtl::OUString( OSL_LOG_PREFIX ) );
2536 return sal_False;
2539 if ( aURL != INetURLObject( ::rtl::OUString( "private:stream" ) ) )
2541 // Is there already a Document with this name?
2542 SfxObjectShell* pDoc = 0;
2543 for ( SfxObjectShell* pTmp = SfxObjectShell::GetFirst();
2544 pTmp && !pDoc;
2545 pTmp = SfxObjectShell::GetNext(*pTmp) )
2547 if( ( pTmp != this ) && pTmp->GetMedium() )
2549 INetURLObject aCompare( pTmp->GetMedium()->GetName() );
2550 if ( aCompare == aURL )
2551 pDoc = pTmp;
2554 if ( pDoc )
2556 // Then error message: "already opened"
2557 SetError(ERRCODE_SFX_ALREADYOPEN, ::rtl::OUString( OSL_LOG_PREFIX ));
2558 return sal_False;
2562 DBG_ASSERT( aURL.GetProtocol() != INET_PROT_NOT_VALID, "Illegal URL!" );
2563 DBG_ASSERT( aParams->Count() != 0, "Incorrect Parameter");
2565 SFX_ITEMSET_ARG( aParams, pSaveToItem, SfxBoolItem, SID_SAVETO, sal_False );
2566 sal_Bool bSaveTo = pSaveToItem ? pSaveToItem->GetValue() : sal_False;
2568 const SfxFilter* pFilter = GetFactory().GetFilterContainer()->GetFilter4FilterName( aFilterName );
2569 if ( !pFilter
2570 || !pFilter->CanExport()
2571 || (!bSaveTo && !pFilter->CanImport()) )
2573 SetError( ERRCODE_IO_INVALIDPARAMETER, ::rtl::OUString( OSL_LOG_PREFIX ) );
2574 return sal_False;
2577 SFX_ITEMSET_ARG( aParams, pCopyStreamItem, SfxBoolItem, SID_COPY_STREAM_IF_POSSIBLE, sal_False );
2578 if ( bSaveTo && pCopyStreamItem && pCopyStreamItem->GetValue() && !IsModified() )
2580 if ( pMedium->TryDirectTransfer( aURL.GetMainURL( INetURLObject::NO_DECODE ), *aParams ) )
2581 return sal_True;
2583 aParams->ClearItem( SID_COPY_STREAM_IF_POSSIBLE );
2585 pImp->bPasswd = aParams && SFX_ITEM_SET == aParams->GetItemState(SID_PASSWORD);
2587 SfxMedium *pActMed = GetMedium();
2588 const INetURLObject aActName(pActMed->GetName());
2590 sal_Bool bWasReadonly = IsReadOnly();
2592 if ( aURL == aActName && aURL != INetURLObject( OUString("private:stream") )
2593 && IsReadOnly() )
2595 SetError(ERRCODE_SFX_DOCUMENTREADONLY, ::rtl::OUString( OSL_LOG_PREFIX ));
2596 return sal_False;
2599 if( SFX_ITEM_SET != aParams->GetItemState(SID_UNPACK) && SvtSaveOptions().IsSaveUnpacked() )
2600 aParams->Put( SfxBoolItem( SID_UNPACK, sal_False ) );
2602 ::rtl::OUString aTempFileURL;
2603 if ( IsDocShared() )
2604 aTempFileURL = pMedium->GetURLObject().GetMainURL( INetURLObject::NO_DECODE );
2606 if ( PreDoSaveAs_Impl(aURL.GetMainURL( INetURLObject::NO_DECODE ),aFilterName,aParams))
2608 // Update Data on media
2609 SfxItemSet *pSet = GetMedium()->GetItemSet();
2610 pSet->ClearItem( SID_INTERACTIONHANDLER );
2611 pSet->ClearItem( SID_PROGRESS_STATUSBAR_CONTROL );
2612 pSet->ClearItem( SID_STANDARD_DIR );
2613 pSet->ClearItem( SID_PATH );
2615 if ( !bSaveTo )
2617 pSet->ClearItem( SID_REFERER );
2618 pSet->ClearItem( SID_POSTDATA );
2619 pSet->ClearItem( SID_TEMPLATE );
2620 pSet->ClearItem( SID_DOC_READONLY );
2621 pSet->ClearItem( SID_CONTENTTYPE );
2622 pSet->ClearItem( SID_CHARSET );
2623 pSet->ClearItem( SID_FILTER_NAME );
2624 pSet->ClearItem( SID_OPTIONS );
2625 pSet->ClearItem( SID_VERSION );
2626 pSet->ClearItem( SID_EDITDOC );
2627 pSet->ClearItem( SID_OVERWRITE );
2628 pSet->ClearItem( SID_DEFAULTFILEPATH );
2629 pSet->ClearItem( SID_DEFAULTFILENAME );
2631 SFX_ITEMSET_GET( (*aParams), pFilterItem, SfxStringItem, SID_FILTER_NAME, sal_False );
2632 if ( pFilterItem )
2633 pSet->Put( *pFilterItem );
2635 SFX_ITEMSET_GET( (*aParams), pOptionsItem, SfxStringItem, SID_OPTIONS, sal_False );
2636 if ( pOptionsItem )
2637 pSet->Put( *pOptionsItem );
2639 SFX_ITEMSET_GET( (*aParams), pFilterOptItem, SfxStringItem, SID_FILE_FILTEROPTIONS, sal_False );
2640 if ( pFilterOptItem )
2641 pSet->Put( *pFilterOptItem );
2643 if ( IsDocShared() && !aTempFileURL.isEmpty() )
2645 // this is a shared document that has to be disconnected from the old location
2646 FreeSharedFile( aTempFileURL );
2648 if ( pFilter->IsOwnFormat()
2649 && pFilter->UsesStorage()
2650 && pFilter->GetVersion() >= SOFFICE_FILEFORMAT_60 )
2652 // the target format is the own format
2653 // the target document must be shared
2654 SwitchToShared( sal_True, sal_False );
2659 if ( bWasReadonly && !bSaveTo )
2660 Broadcast( SfxSimpleHint(SFX_HINT_MODECHANGED) );
2662 return sal_True;
2664 else
2665 return sal_False;
2668 //-------------------------------------------------------------------------
2670 sal_Bool SfxObjectShell::PreDoSaveAs_Impl
2672 const String& rFileName,
2673 const String& aFilterName,
2674 SfxItemSet* pParams
2677 // copy all items stored in the itemset of the current medium
2678 SfxAllItemSet* pMergedParams = new SfxAllItemSet( *pMedium->GetItemSet() );
2680 // in "SaveAs" title and password will be cleared ( maybe the new itemset contains new values, otherwise they will be empty )
2681 pMergedParams->ClearItem( SID_ENCRYPTIONDATA );
2682 pMergedParams->ClearItem( SID_PASSWORD );
2683 pMergedParams->ClearItem( SID_DOCINFO_TITLE );
2685 pMergedParams->ClearItem( SID_INPUTSTREAM );
2686 pMergedParams->ClearItem( SID_STREAM );
2687 pMergedParams->ClearItem( SID_CONTENT );
2688 pMergedParams->ClearItem( SID_DOC_READONLY );
2689 pMergedParams->ClearItem( SID_DOC_BASEURL );
2691 pMergedParams->ClearItem( SID_REPAIRPACKAGE );
2693 // "SaveAs" will never store any version information - it's a complete new file !
2694 pMergedParams->ClearItem( SID_VERSION );
2696 // merge the new parameters into the copy
2697 // all values present in both itemsets will be overwritten by the new parameters
2698 if( pParams )
2699 pMergedParams->Put( *pParams );
2701 #ifdef DBG_UTIL
2702 if ( pMergedParams->GetItemState( SID_DOC_SALVAGE) >= SFX_ITEM_SET )
2703 OSL_FAIL("Salvage item present in Itemset, check the parameters!");
2704 #endif
2706 // should be unneccessary - too hot to handle!
2707 pMergedParams->ClearItem( SID_DOC_SALVAGE );
2709 // take over the new merged itemset
2710 pParams = pMergedParams;
2712 // create a medium for the target URL
2713 SfxMedium *pNewFile = new SfxMedium( rFileName, STREAM_READWRITE | STREAM_SHARE_DENYWRITE | STREAM_TRUNC, 0, pParams );
2715 // set filter; if no filter is given, take the default filter of the factory
2716 if ( aFilterName.Len() )
2717 pNewFile->SetFilter( GetFactory().GetFilterContainer()->GetFilter4FilterName( aFilterName ) );
2718 else
2719 pNewFile->SetFilter( GetFactory().GetFilterContainer()->GetAnyFilter( SFX_FILTER_IMPORT | SFX_FILTER_EXPORT ) );
2721 if ( pNewFile->GetErrorCode() != ERRCODE_NONE )
2723 // creating temporary file failed ( f.e. floppy disk not inserted! )
2724 SetError( pNewFile->GetError(), ::rtl::OUString( OSL_LOG_PREFIX ) );
2725 delete pNewFile;
2726 return sal_False;
2729 // check if a "SaveTo" is wanted, no "SaveAs"
2730 SFX_ITEMSET_ARG( pParams, pSaveToItem, SfxBoolItem, SID_SAVETO, sal_False );
2731 sal_Bool bCopyTo = GetCreateMode() == SFX_CREATE_MODE_EMBEDDED || (pSaveToItem && pSaveToItem->GetValue());
2733 // distinguish between "Save" and "SaveAs"
2734 pImp->bIsSaving = sal_False;
2736 // copy version list from "old" medium to target medium, so it can be used on saving
2737 if ( pImp->bPreserveVersions )
2738 pNewFile->TransferVersionList_Impl( *pMedium );
2740 // Save the document ( first as temporary file, then transfer to the target URL by committing the medium )
2741 sal_Bool bOk = sal_False;
2742 if ( !pNewFile->GetErrorCode() && SaveTo_Impl( *pNewFile, NULL ) )
2744 bOk = sal_True;
2746 // transfer a possible error from the medium to the document
2747 SetError( pNewFile->GetErrorCode(), ::rtl::OUString( OSL_LOG_PREFIX ) );
2749 // notify the document that saving was done successfully
2750 if ( !bCopyTo )
2752 bOk = DoSaveCompleted( pNewFile );
2754 else
2755 bOk = DoSaveCompleted(0);
2757 if( bOk )
2759 if( !bCopyTo )
2760 SetModified( sal_False );
2762 else
2764 // TODO/LATER: the code below must be dead since the storage commit makes all the stuff
2765 // and the DoSaveCompleted call should not be able to fail in general
2767 DBG_ASSERT( !bCopyTo, "Error while reconnecting to medium, can't be handled!");
2768 SetError( pNewFile->GetErrorCode(), ::rtl::OUString( OSL_LOG_PREFIX ) );
2770 if ( !bCopyTo )
2772 // reconnect to the old medium
2773 sal_Bool bRet( sal_False );
2774 bRet = DoSaveCompleted( pMedium );
2775 DBG_ASSERT( bRet, "Error in DoSaveCompleted, can't be handled!");
2776 (void)bRet;
2779 // TODO/LATER: disconnect the new file from the storage for the case when pure saving is done
2780 // if storing has corrupted the file, probably it must be restored either here or
2781 // by the storage
2782 DELETEZ( pNewFile );
2785 else
2787 SetError( pNewFile->GetErrorCode(), ::rtl::OUString( OSL_LOG_PREFIX ) );
2789 // reconnect to the old storage
2790 DoSaveCompleted( 0 );
2792 DELETEZ( pNewFile );
2795 if ( bCopyTo )
2796 DELETEZ( pNewFile );
2797 else if( !bOk )
2798 SetModified( sal_True );
2800 return bOk;
2803 //------------------------------------------------------------------------
2805 sal_Bool SfxObjectShell::LoadFrom( SfxMedium& /*rMedium*/ )
2807 OSL_FAIL( "Base implementation, must not be called in general!" );
2808 return sal_True;
2811 //-------------------------------------------------------------------------
2812 sal_Bool SfxObjectShell::IsInformationLost()
2814 Sequence< PropertyValue > aProps = GetModel()->getArgs();
2815 ::rtl::OUString aFilterName;
2816 ::rtl::OUString aPreusedFilterName;
2817 for ( sal_Int32 nInd = 0; nInd < aProps.getLength(); nInd++ )
2819 if ( aProps[nInd].Name == "FilterName" )
2820 aProps[nInd].Value >>= aFilterName;
2821 else if ( aProps[nInd].Name == "PreusedFilterName" )
2822 aProps[nInd].Value >>= aPreusedFilterName;
2825 // if current filter can lead to information loss and it was used
2826 // for the latest store then the user should be asked to store in own format
2827 if ( !aFilterName.isEmpty() && aFilterName.equals( aPreusedFilterName ) )
2829 const SfxFilter *pFilt = GetMedium()->GetFilter();
2830 DBG_ASSERT( pFilt && aFilterName.equals( pFilt->GetName() ), "MediaDescriptor contains wrong filter!\n" );
2831 return ( pFilt && pFilt->IsAlienFormat() );
2834 return sal_False;
2837 //-------------------------------------------------------------------------
2838 sal_Bool SfxObjectShell::CanReload_Impl()
2840 /* [Description]
2842 Internal method for determining whether a reload of the document
2843 (as RevertToSaved or last known version) is possible.
2847 return pMedium && HasName() && !IsInModalMode() && !pImp->bForbidReload;
2850 //-------------------------------------------------------------------------
2852 sal_uInt16 SfxObjectShell::GetHiddenInformationState( sal_uInt16 nStates )
2854 sal_uInt16 nState = 0;
2855 if ( nStates & HIDDENINFORMATION_DOCUMENTVERSIONS )
2857 if ( GetMedium()->GetVersionList().getLength() )
2858 nState |= HIDDENINFORMATION_DOCUMENTVERSIONS;
2861 return nState;
2864 sal_Int16 SfxObjectShell::QueryHiddenInformation( HiddenWarningFact eFact, Window* pParent )
2866 sal_Int16 nRet = RET_YES;
2867 sal_uInt16 nResId = 0;
2868 SvtSecurityOptions::EOption eOption = static_cast< SvtSecurityOptions::EOption >( -1 );
2870 switch ( eFact )
2872 case WhenSaving :
2874 nResId = STR_HIDDENINFO_CONTINUE_SAVING;
2875 eOption = SvtSecurityOptions::E_DOCWARN_SAVEORSEND;
2876 break;
2878 case WhenPrinting :
2880 nResId = STR_HIDDENINFO_CONTINUE_PRINTING;
2881 eOption = SvtSecurityOptions::E_DOCWARN_PRINT;
2882 break;
2884 case WhenSigning :
2886 nResId = STR_HIDDENINFO_CONTINUE_SIGNING;
2887 eOption = SvtSecurityOptions::E_DOCWARN_SIGNING;
2888 break;
2890 case WhenCreatingPDF :
2892 nResId = STR_HIDDENINFO_CONTINUE_CREATEPDF;
2893 eOption = SvtSecurityOptions::E_DOCWARN_CREATEPDF;
2894 break;
2896 default:
2898 SAL_WARN( "sfx2.doc", "SfxObjectShell::DetectHiddenInformation(): what fact?" );
2902 if ( eOption != -1 && SvtSecurityOptions().IsOptionSet( eOption ) )
2904 String sMessage( SfxResId( STR_HIDDENINFO_CONTAINS ) );
2905 sal_uInt16 nWantedStates = HIDDENINFORMATION_RECORDEDCHANGES | HIDDENINFORMATION_NOTES;
2906 if ( eFact != WhenPrinting )
2907 nWantedStates |= HIDDENINFORMATION_DOCUMENTVERSIONS;
2908 sal_uInt16 nStates = GetHiddenInformationState( nWantedStates );
2909 bool bWarning = false;
2911 if ( ( nStates & HIDDENINFORMATION_RECORDEDCHANGES ) == HIDDENINFORMATION_RECORDEDCHANGES )
2913 sMessage += String( SfxResId( STR_HIDDENINFO_RECORDCHANGES ) );
2914 sMessage += '\n';
2915 bWarning = true;
2917 if ( ( nStates & HIDDENINFORMATION_NOTES ) == HIDDENINFORMATION_NOTES )
2919 sMessage += String( SfxResId( STR_HIDDENINFO_NOTES ) );
2920 sMessage += '\n';
2921 bWarning = true;
2923 if ( ( nStates & HIDDENINFORMATION_DOCUMENTVERSIONS ) == HIDDENINFORMATION_DOCUMENTVERSIONS )
2925 sMessage += String( SfxResId( STR_HIDDENINFO_DOCVERSIONS ) );
2926 sMessage += '\n';
2927 bWarning = true;
2930 if ( bWarning )
2932 sMessage += '\n';
2933 sMessage += String( SfxResId( nResId ) );
2934 WarningBox aWBox( pParent, WB_YES_NO | WB_DEF_NO, sMessage );
2935 nRet = aWBox.Execute();
2939 return nRet;
2942 sal_Bool SfxObjectShell::HasSecurityOptOpenReadOnly() const
2944 return sal_True;
2947 sal_Bool SfxObjectShell::IsSecurityOptOpenReadOnly() const
2949 return IsLoadReadonly();
2952 void SfxObjectShell::SetSecurityOptOpenReadOnly( sal_Bool _b )
2954 SetLoadReadonly( _b );
2957 sal_Bool SfxObjectShell::LoadOwnFormat( SfxMedium& rMedium )
2959 RTL_LOGFILE_PRODUCT_CONTEXT( aLog, "PERFORMANCE SfxObjectShell::LoadOwnFormat" );
2960 if( RTL_LOGFILE_HASLOGFILE() )
2962 rtl::OString aString(
2963 rtl::OUStringToOString(rMedium.GetName(), RTL_TEXTENCODING_ASCII_US));
2964 RTL_LOGFILE_PRODUCT_CONTEXT_TRACE1(aLog, "loading \"%s\"", aString.getStr());
2967 uno::Reference< embed::XStorage > xStorage = rMedium.GetStorage();
2968 if ( xStorage.is() )
2970 // Password
2971 SFX_ITEMSET_ARG( rMedium.GetItemSet(), pPasswdItem, SfxStringItem, SID_PASSWORD, sal_False );
2972 if ( pPasswdItem || ERRCODE_IO_ABORT != CheckPasswd_Impl( this, SFX_APP()->GetPool(), pMedium ) )
2974 uno::Sequence< beans::NamedValue > aEncryptionData;
2975 if ( GetEncryptionData_Impl(pMedium->GetItemSet(), aEncryptionData) )
2979 // the following code must throw an exception in case of failure
2980 ::comphelper::OStorageHelper::SetCommonStorageEncryptionData( xStorage, aEncryptionData );
2982 catch( uno::Exception& )
2984 // TODO/LATER: handle the error code
2988 // load document
2989 return Load( rMedium );
2991 return sal_False;
2993 else
2994 return sal_False;
2997 sal_Bool SfxObjectShell::SaveAsOwnFormat( SfxMedium& rMedium )
2999 uno::Reference< embed::XStorage > xStorage = rMedium.GetStorage();
3000 if( xStorage.is() )
3002 sal_Int32 nVersion = rMedium.GetFilter()->GetVersion();
3004 // OASIS templates have own mediatypes ( SO7 also actually, but it is to late to use them here )
3005 sal_Bool bTemplate = ( rMedium.GetFilter()->IsOwnTemplateFormat() && nVersion > SOFFICE_FILEFORMAT_60 );
3007 SetupStorage( xStorage, nVersion, bTemplate );
3008 #ifndef DISABLE_SCRIPTING
3009 if ( HasBasic() )
3011 // Initialize Basic
3012 GetBasicManager();
3014 // Save dialog/script container
3015 pImp->pBasicManager->storeLibrariesToStorage( xStorage );
3017 #endif
3018 return SaveAs( rMedium );
3020 else return sal_False;
3023 uno::Reference< embed::XStorage > SfxObjectShell::GetStorage()
3025 if ( !pImp->m_xDocStorage.is() )
3027 OSL_ENSURE( pImp->m_bCreateTempStor, "The storage must exist already!\n" );
3028 try {
3029 // no notification is required the storage is set the first time
3030 pImp->m_xDocStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
3031 OSL_ENSURE( pImp->m_xDocStorage.is(), "The method must either return storage or throw an exception!" );
3033 SetupStorage( pImp->m_xDocStorage, SOFFICE_FILEFORMAT_CURRENT, sal_False );
3034 pImp->m_bCreateTempStor = sal_False;
3035 SFX_APP()->NotifyEvent( SfxEventHint( SFX_EVENT_STORAGECHANGED, GlobalEventConfig::GetEventName(STR_EVENT_STORAGECHANGED), this ) );
3037 catch( uno::Exception& )
3039 // TODO/LATER: error handling?
3040 DBG_UNHANDLED_EXCEPTION();
3044 OSL_ENSURE( pImp->m_xDocStorage.is(), "The document storage must be created!" );
3045 return pImp->m_xDocStorage;
3049 sal_Bool SfxObjectShell::SaveChildren( sal_Bool bObjectsOnly )
3051 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SaveChildren" );
3053 sal_Bool bResult = sal_True;
3054 if ( pImp->mpObjectContainer )
3056 sal_Bool bOasis = ( SotStorage::GetVersion( GetStorage() ) > SOFFICE_FILEFORMAT_60 );
3057 GetEmbeddedObjectContainer().StoreChildren(bOasis,bObjectsOnly);
3060 return bResult;
3063 sal_Bool SfxObjectShell::SaveAsChildren( SfxMedium& rMedium )
3065 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SaveAsChildren" );
3067 sal_Bool bResult = sal_True;
3069 uno::Reference < embed::XStorage > xStorage = rMedium.GetStorage();
3070 if ( !xStorage.is() )
3071 return sal_False;
3073 if ( xStorage == GetStorage() )
3074 return SaveChildren();
3076 sal_Bool bOasis = sal_True;
3077 if ( pImp->mpObjectContainer )
3079 bOasis = ( SotStorage::GetVersion( xStorage ) > SOFFICE_FILEFORMAT_60 );
3080 GetEmbeddedObjectContainer().StoreAsChildren(bOasis,SFX_CREATE_MODE_EMBEDDED == eCreateMode,xStorage);
3083 if ( bResult )
3084 bResult = CopyStoragesOfUnknownMediaType( GetStorage(), xStorage );
3086 return bResult;
3089 sal_Bool SfxObjectShell::SaveCompletedChildren( sal_Bool bSuccess )
3091 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SaveCompletedChildren" );
3093 sal_Bool bResult = sal_True;
3095 if ( pImp->mpObjectContainer )
3097 uno::Sequence < ::rtl::OUString > aNames = GetEmbeddedObjectContainer().GetObjectNames();
3098 for ( sal_Int32 n=0; n<aNames.getLength(); n++ )
3100 uno::Reference < embed::XEmbeddedObject > xObj = GetEmbeddedObjectContainer().GetEmbeddedObject( aNames[n] );
3101 OSL_ENSURE( xObj.is(), "An empty entry in the embedded objects list!\n" );
3102 if ( xObj.is() )
3104 uno::Reference< embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
3105 if ( xPersist.is() )
3109 xPersist->saveCompleted( bSuccess );
3111 catch( uno::Exception& )
3113 // TODO/LATER: error handling
3114 bResult = sal_False;
3115 break;
3122 return bResult;
3125 sal_Bool SfxObjectShell::SwitchChildrenPersistance( const uno::Reference< embed::XStorage >& xStorage,
3126 sal_Bool bForceNonModified )
3128 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SwitchChildrenPersistence" );
3130 if ( !xStorage.is() )
3132 // TODO/LATER: error handling
3133 return sal_False;
3136 sal_Bool bResult = sal_True;
3138 if ( pImp->mpObjectContainer )
3139 pImp->mpObjectContainer->SetPersistentEntries(xStorage,bForceNonModified);
3141 return bResult;
3144 // Never call this method directly, always use the DoSaveCompleted call
3145 sal_Bool SfxObjectShell::SaveCompleted( const uno::Reference< embed::XStorage >& xStorage )
3147 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SaveCompleted" );
3149 sal_Bool bResult = sal_False;
3150 sal_Bool bSendNotification = sal_False;
3151 uno::Reference< embed::XStorage > xOldStorageHolder;
3153 #ifdef DBG_UTIL
3154 // check for wrong creation of object container
3155 sal_Bool bHasContainer = ( pImp->mpObjectContainer != 0 );
3156 #endif
3158 if ( !xStorage.is() || xStorage == GetStorage() )
3160 // no persistence change
3161 bResult = SaveCompletedChildren( sal_False );
3163 else
3165 if ( pImp->mpObjectContainer )
3166 GetEmbeddedObjectContainer().SwitchPersistence( xStorage );
3168 bResult = SwitchChildrenPersistance( xStorage, sal_True );
3171 if ( bResult )
3173 if ( xStorage.is() && pImp->m_xDocStorage != xStorage )
3175 // make sure that until the storage is assigned the object
3176 // container is not created by accident!
3177 DBG_ASSERT( bHasContainer == (pImp->mpObjectContainer != 0), "Wrong storage in object container!" );
3178 xOldStorageHolder = pImp->m_xDocStorage;
3179 pImp->m_xDocStorage = xStorage;
3180 bSendNotification = sal_True;
3182 if ( IsEnableSetModified() )
3183 SetModified( sal_False );
3186 else
3188 if ( pImp->mpObjectContainer )
3189 GetEmbeddedObjectContainer().SwitchPersistence( pImp->m_xDocStorage );
3191 // let already successfully connected objects be switched back
3192 SwitchChildrenPersistance( pImp->m_xDocStorage, sal_True );
3195 if ( bSendNotification )
3197 SFX_APP()->NotifyEvent( SfxEventHint( SFX_EVENT_STORAGECHANGED, GlobalEventConfig::GetEventName(STR_EVENT_STORAGECHANGED), this ) );
3200 return bResult;
3203 #if OSL_DEBUG_LEVEL > 0
3204 sal_Bool StoragesOfUnknownMediaTypeAreCopied_Impl( const uno::Reference< embed::XStorage >& xSource,
3205 const uno::Reference< embed::XStorage >& xTarget )
3207 OSL_ENSURE( xSource.is() && xTarget.is(), "Source and/or target storages are not available!\n" );
3208 if ( !xSource.is() || !xTarget.is() || xSource == xTarget )
3209 return sal_True;
3213 uno::Sequence< ::rtl::OUString > aSubElements = xSource->getElementNames();
3214 for ( sal_Int32 nInd = 0; nInd < aSubElements.getLength(); nInd++ )
3216 if ( xSource->isStorageElement( aSubElements[nInd] ) )
3218 ::rtl::OUString aMediaType;
3219 ::rtl::OUString aMediaTypePropName( "MediaType" );
3220 sal_Bool bGotMediaType = sal_False;
3224 uno::Reference< embed::XOptimizedStorage > xOptStorage( xSource, uno::UNO_QUERY_THROW );
3225 bGotMediaType =
3226 ( xOptStorage->getElementPropertyValue( aSubElements[nInd], aMediaTypePropName ) >>= aMediaType );
3228 catch( uno::Exception& )
3231 if ( !bGotMediaType )
3233 uno::Reference< embed::XStorage > xSubStorage;
3234 try {
3235 xSubStorage = xSource->openStorageElement( aSubElements[nInd], embed::ElementModes::READ );
3236 } catch( uno::Exception& )
3239 if ( !xSubStorage.is() )
3241 xSubStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
3242 xSource->copyStorageElementLastCommitTo( aSubElements[nInd], xSubStorage );
3245 uno::Reference< beans::XPropertySet > xProps( xSubStorage, uno::UNO_QUERY_THROW );
3246 bGotMediaType = ( xProps->getPropertyValue( aMediaTypePropName ) >>= aMediaType );
3249 // TODO/LATER: there should be a way to detect whether an object with such a MediaType can exist
3250 // probably it should be placed in the MimeType-ClassID table or in standalone table
3251 if ( !aMediaType.isEmpty()
3252 && aMediaType.compareToAscii( "application/vnd.sun.star.oleobject" ) != COMPARE_EQUAL )
3254 ::com::sun::star::datatransfer::DataFlavor aDataFlavor;
3255 aDataFlavor.MimeType = aMediaType;
3256 sal_uInt32 nFormat = SotExchange::GetFormat( aDataFlavor );
3258 switch ( nFormat )
3260 case SOT_FORMATSTR_ID_STARWRITER_60 :
3261 case SOT_FORMATSTR_ID_STARWRITERWEB_60 :
3262 case SOT_FORMATSTR_ID_STARWRITERGLOB_60 :
3263 case SOT_FORMATSTR_ID_STARDRAW_60 :
3264 case SOT_FORMATSTR_ID_STARIMPRESS_60 :
3265 case SOT_FORMATSTR_ID_STARCALC_60 :
3266 case SOT_FORMATSTR_ID_STARCHART_60 :
3267 case SOT_FORMATSTR_ID_STARMATH_60 :
3268 case SOT_FORMATSTR_ID_STARWRITER_8:
3269 case SOT_FORMATSTR_ID_STARWRITERWEB_8:
3270 case SOT_FORMATSTR_ID_STARWRITERGLOB_8:
3271 case SOT_FORMATSTR_ID_STARDRAW_8:
3272 case SOT_FORMATSTR_ID_STARIMPRESS_8:
3273 case SOT_FORMATSTR_ID_STARCALC_8:
3274 case SOT_FORMATSTR_ID_STARCHART_8:
3275 case SOT_FORMATSTR_ID_STARMATH_8:
3276 break;
3278 default:
3280 if ( !xTarget->hasByName( aSubElements[nInd] ) )
3281 return sal_False;
3288 catch( uno::Exception& )
3290 OSL_FAIL( "Cant check storage consistency!\n" );
3293 return sal_True;
3295 #endif
3297 sal_Bool SfxObjectShell::SwitchPersistance( const uno::Reference< embed::XStorage >& xStorage )
3299 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SwitchPersistance" );
3301 sal_Bool bResult = sal_False;
3302 #ifdef DBG_UTIL
3303 // check for wrong creation of object container
3304 sal_Bool bHasContainer = ( pImp->mpObjectContainer != 0 );
3305 #endif
3306 if ( xStorage.is() )
3308 if ( pImp->mpObjectContainer )
3309 GetEmbeddedObjectContainer().SwitchPersistence( xStorage );
3310 bResult = SwitchChildrenPersistance( xStorage );
3312 // TODO/LATER: substorages that have unknown mimetypes probably should be copied to the target storage here
3313 OSL_ENSURE( StoragesOfUnknownMediaTypeAreCopied_Impl( pImp->m_xDocStorage, xStorage ),
3314 "Some of substorages with unknown mimetypes is lost!" );
3317 if ( bResult )
3319 // make sure that until the storage is assigned the object container is not created by accident!
3320 DBG_ASSERT( bHasContainer == (pImp->mpObjectContainer != 0), "Wrong storage in object container!" );
3321 if ( pImp->m_xDocStorage != xStorage )
3322 DoSaveCompleted( new SfxMedium( xStorage, GetMedium()->GetBaseURL() ) );
3324 if ( IsEnableSetModified() )
3325 SetModified( sal_True ); // ???
3328 return bResult;
3331 sal_Bool SfxObjectShell::CopyStoragesOfUnknownMediaType( const uno::Reference< embed::XStorage >& xSource,
3332 const uno::Reference< embed::XStorage >& xTarget )
3334 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::CopyStoragesOfUnknownMediaType" );
3336 // This method does not commit the target storage and should not do it
3337 sal_Bool bResult = sal_True;
3341 uno::Sequence< ::rtl::OUString > aSubElements = xSource->getElementNames();
3342 for ( sal_Int32 nInd = 0; nInd < aSubElements.getLength(); nInd++ )
3344 if ( aSubElements[nInd] == "Configurations" )
3346 // The workaround for compatibility with SO7, "Configurations" substorage must be preserved
3347 if ( xSource->isStorageElement( aSubElements[nInd] ) )
3349 OSL_ENSURE( !xTarget->hasByName( aSubElements[nInd] ),
3350 "The target storage is an output storage, the element should not exist in the target!\n" );
3352 xSource->copyElementTo( aSubElements[nInd], xTarget, aSubElements[nInd] );
3355 else if ( xSource->isStorageElement( aSubElements[nInd] ) )
3357 ::rtl::OUString aMediaType;
3358 ::rtl::OUString aMediaTypePropName( "MediaType" );
3359 sal_Bool bGotMediaType = sal_False;
3363 uno::Reference< embed::XOptimizedStorage > xOptStorage( xSource, uno::UNO_QUERY_THROW );
3364 bGotMediaType =
3365 ( xOptStorage->getElementPropertyValue( aSubElements[nInd], aMediaTypePropName ) >>= aMediaType );
3367 catch( uno::Exception& )
3370 if ( !bGotMediaType )
3372 uno::Reference< embed::XStorage > xSubStorage;
3373 try {
3374 xSubStorage = xSource->openStorageElement( aSubElements[nInd], embed::ElementModes::READ );
3375 } catch( uno::Exception& )
3378 if ( !xSubStorage.is() )
3380 // TODO/LATER: as optimization in future a substorage of target storage could be used
3381 // instead of the temporary storage; this substorage should be removed later
3382 // if the MimeType is wrong
3383 xSubStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
3384 xSource->copyStorageElementLastCommitTo( aSubElements[nInd], xSubStorage );
3387 uno::Reference< beans::XPropertySet > xProps( xSubStorage, uno::UNO_QUERY_THROW );
3388 bGotMediaType = ( xProps->getPropertyValue( aMediaTypePropName ) >>= aMediaType );
3391 // TODO/LATER: there should be a way to detect whether an object with such a MediaType can exist
3392 // probably it should be placed in the MimeType-ClassID table or in standalone table
3393 if ( !aMediaType.isEmpty()
3394 && aMediaType.compareToAscii( "application/vnd.sun.star.oleobject" ) != COMPARE_EQUAL )
3396 ::com::sun::star::datatransfer::DataFlavor aDataFlavor;
3397 aDataFlavor.MimeType = aMediaType;
3398 sal_uInt32 nFormat = SotExchange::GetFormat( aDataFlavor );
3400 switch ( nFormat )
3402 case SOT_FORMATSTR_ID_STARWRITER_60 :
3403 case SOT_FORMATSTR_ID_STARWRITERWEB_60 :
3404 case SOT_FORMATSTR_ID_STARWRITERGLOB_60 :
3405 case SOT_FORMATSTR_ID_STARDRAW_60 :
3406 case SOT_FORMATSTR_ID_STARIMPRESS_60 :
3407 case SOT_FORMATSTR_ID_STARCALC_60 :
3408 case SOT_FORMATSTR_ID_STARCHART_60 :
3409 case SOT_FORMATSTR_ID_STARMATH_60 :
3410 case SOT_FORMATSTR_ID_STARWRITER_8:
3411 case SOT_FORMATSTR_ID_STARWRITERWEB_8:
3412 case SOT_FORMATSTR_ID_STARWRITERGLOB_8:
3413 case SOT_FORMATSTR_ID_STARDRAW_8:
3414 case SOT_FORMATSTR_ID_STARIMPRESS_8:
3415 case SOT_FORMATSTR_ID_STARCALC_8:
3416 case SOT_FORMATSTR_ID_STARCHART_8:
3417 case SOT_FORMATSTR_ID_STARMATH_8:
3418 break;
3420 default:
3422 OSL_ENSURE( aSubElements[nInd] == "Configurations2" || !xTarget->hasByName( aSubElements[nInd] ),
3423 "The target storage is an output storage, the element should not exist in the target!\n" );
3425 if ( !xTarget->hasByName( aSubElements[nInd] ) )
3427 xSource->copyElementTo( aSubElements[nInd], xTarget, aSubElements[nInd] );
3435 catch( uno::Exception& )
3437 bResult = sal_False;
3438 // TODO/LATER: a specific error could be provided
3441 return bResult;
3444 sal_Bool SfxObjectShell::GenerateAndStoreThumbnail( sal_Bool bEncrypted,
3445 sal_Bool bSigned,
3446 sal_Bool bIsTemplate,
3447 const uno::Reference< embed::XStorage >& xStor )
3449 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::GenerateAndStoreThumbnail" );
3451 sal_Bool bResult = sal_False;
3453 try {
3454 uno::Reference< embed::XStorage > xThumbnailStor =
3455 xStor->openStorageElement( ::rtl::OUString("Thumbnails"),
3456 embed::ElementModes::READWRITE );
3457 if ( xThumbnailStor.is() )
3459 uno::Reference< io::XStream > xStream = xThumbnailStor->openStreamElement(
3460 ::rtl::OUString("thumbnail.png"),
3461 embed::ElementModes::READWRITE );
3463 if ( xStream.is() && WriteThumbnail( bEncrypted, bSigned, bIsTemplate, xStream ) )
3465 uno::Reference< embed::XTransactedObject > xTransact( xThumbnailStor, uno::UNO_QUERY_THROW );
3466 xTransact->commit();
3467 bResult = sal_True;
3471 catch( uno::Exception& )
3475 return bResult;
3478 sal_Bool SfxObjectShell::WriteThumbnail( sal_Bool bEncrypted,
3479 sal_Bool bSigned,
3480 sal_Bool bIsTemplate,
3481 const uno::Reference< io::XStream >& xStream )
3483 sal_Bool bResult = sal_False;
3485 if ( xStream.is() )
3487 try {
3488 uno::Reference< io::XTruncate > xTruncate( xStream->getOutputStream(), uno::UNO_QUERY_THROW );
3489 xTruncate->truncate();
3491 uno::Reference < beans::XPropertySet > xSet( xStream, uno::UNO_QUERY );
3492 if ( xSet.is() )
3493 xSet->setPropertyValue( ::rtl::OUString("MediaType"),
3494 uno::makeAny( ::rtl::OUString("image/png") ) );
3495 if ( bEncrypted )
3497 sal_uInt16 nResID = GraphicHelper::getThumbnailReplacementIDByFactoryName_Impl(
3498 ::rtl::OUString::createFromAscii( GetFactory().GetShortName() ),
3499 bIsTemplate );
3500 if ( nResID )
3502 if ( !bSigned )
3504 bResult = GraphicHelper::getThumbnailReplacement_Impl( nResID, xStream );
3506 else
3508 // retrieve the bitmap and write a signature bitmap over it
3509 SfxResId aResId( nResID );
3510 BitmapEx aThumbBitmap( aResId );
3511 bResult = GraphicHelper::getSignedThumbnailFormatFromBitmap_Impl( aThumbBitmap, xStream );
3515 else
3517 ::boost::shared_ptr<GDIMetaFile> pMetaFile =
3518 GetPreviewMetaFile( sal_False );
3519 if ( pMetaFile )
3521 bResult = GraphicHelper::getThumbnailFormatFromGDI_Impl(
3522 pMetaFile.get(), bSigned, xStream );
3526 catch( uno::Exception& )
3530 return bResult;
3533 void SfxObjectShell::UpdateLinks()
3537 void SfxObjectShell::CheckConfigOptions()
3539 // not handled. Each app's shell needs to overwrite this method to add handler.
3540 SetConfigOptionsChecked(true);
3543 sal_Bool SfxObjectShell::IsConfigOptionsChecked() const
3545 return pImp->m_bConfigOptionsChecked;
3548 void SfxObjectShell::SetConfigOptionsChecked( sal_Bool bChecked )
3550 pImp->m_bConfigOptionsChecked = bChecked;
3553 sal_Bool SfxObjectShell::QuerySaveSizeExceededModules_Impl( const uno::Reference< task::XInteractionHandler >& xHandler )
3555 #ifdef DISABLE_SCRIPTING
3556 (void) xHandler;
3557 #else
3558 if ( !HasBasic() )
3559 return sal_True;
3561 if ( !pImp->pBasicManager->isValid() )
3562 GetBasicManager();
3563 uno::Sequence< rtl::OUString > sModules;
3564 if ( xHandler.is() )
3566 if( pImp->pBasicManager->LegacyPsswdBinaryLimitExceeded( sModules ) )
3568 ModuleSizeExceeded* pReq = new ModuleSizeExceeded( sModules );
3569 uno::Reference< task::XInteractionRequest > xReq( pReq );
3570 xHandler->handle( xReq );
3571 return pReq->isApprove();
3574 #endif
3575 // No interaction handler, default is to continue to save
3576 return sal_True;
3578 // -----------------------------------------------------------------------------
3579 uno::Reference< task::XInteractionHandler > SfxObjectShell::getInteractionHandler() const
3581 uno::Reference< task::XInteractionHandler > xRet;
3582 if ( GetMedium() )
3583 xRet = GetMedium()->GetInteractionHandler();
3584 return xRet;
3587 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */