Bump version to 4.1-6
[LibreOffice.git] / sfx2 / source / doc / objstor.cxx
blob660b843ce1f191f317be1779f4e2797bf2adfcf7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_features.h>
22 #include "sal/config.h"
24 #include <cassert>
26 #include <vcl/msgbox.hxx>
27 #include <svl/eitem.hxx>
28 #include <svl/stritem.hxx>
29 #include <svl/intitem.hxx>
30 #include <com/sun/star/frame/GlobalEventBroadcaster.hpp>
31 #include <com/sun/star/frame/XStorable.hpp>
32 #include <com/sun/star/frame/XModel.hpp>
33 #include <com/sun/star/frame/XFrame.hpp>
34 #include <com/sun/star/document/XFilter.hpp>
35 #include <com/sun/star/document/XImporter.hpp>
36 #include <com/sun/star/document/XExporter.hpp>
37 #include <com/sun/star/document/FilterOptionsRequest.hpp>
38 #include <com/sun/star/document/XInteractionFilterOptions.hpp>
39 #include <com/sun/star/packages/zip/ZipIOException.hpp>
40 #include <com/sun/star/task/XInteractionHandler.hpp>
41 #include <com/sun/star/task/XInteractionAskLater.hpp>
42 #include <com/sun/star/task/FutureDocumentVersionProductUpdateRequest.hpp>
43 #include <com/sun/star/task/InteractionClassification.hpp>
44 #include <com/sun/star/lang/XInitialization.hpp>
45 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
46 #include <com/sun/star/document/MacroExecMode.hpp>
47 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
48 #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
49 #include <com/sun/star/ui/dialogs/XFilePicker.hpp>
50 #include <com/sun/star/beans/XPropertySetInfo.hpp>
51 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
52 #include <com/sun/star/beans/XPropertyAccess.hpp>
53 #include <com/sun/star/beans/PropertyValue.hpp>
54 #include <com/sun/star/beans/XPropertySet.hpp>
55 #include <com/sun/star/container/XNameAccess.hpp>
56 #include <com/sun/star/container/XSet.hpp>
57 #include <com/sun/star/embed/ElementModes.hpp>
58 #include <com/sun/star/embed/EmbedStates.hpp>
59 #include <com/sun/star/embed/Aspects.hpp>
60 #include <com/sun/star/embed/XTransactedObject.hpp>
61 #include <com/sun/star/embed/XEmbedPersist.hpp>
62 #include <com/sun/star/embed/XLinkageSupport.hpp>
63 #include <com/sun/star/embed/EntryInitModes.hpp>
64 #include <com/sun/star/embed/XOptimizedStorage.hpp>
65 #include <com/sun/star/embed/XEncryptionProtectedStorage.hpp>
66 #include <com/sun/star/io/XTruncate.hpp>
67 #include <com/sun/star/util/XModifiable.hpp>
68 #include <com/sun/star/security/DocumentDigitalSignatures.hpp>
69 #include <com/sun/star/xml/crypto/CipherID.hpp>
70 #include <com/sun/star/xml/crypto/DigestID.hpp>
72 #include <com/sun/star/document/XDocumentProperties.hpp>
73 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
74 #include <comphelper/processfactory.hxx>
75 #include <comphelper/configurationhelper.hxx>
76 #include <comphelper/interaction.hxx>
77 #include <svtools/sfxecode.hxx>
78 #include <unotools/securityoptions.hxx>
79 #include <cppuhelper/weak.hxx>
80 #include <unotools/streamwrap.hxx>
82 #include <unotools/saveopt.hxx>
83 #include <unotools/useroptions.hxx>
84 #include <unotools/pathoptions.hxx>
85 #include <tools/urlobj.hxx>
86 #include <tools/diagnose_ex.h>
87 #include <unotools/localfilehelper.hxx>
88 #include <unotools/ucbhelper.hxx>
89 #include <unotools/tempfile.hxx>
90 #include <unotools/docinfohelper.hxx>
91 #include <ucbhelper/content.hxx>
92 #include <sot/storinfo.hxx>
93 #include <sot/exchange.hxx>
94 #include <sot/formats.hxx>
95 #include <comphelper/storagehelper.hxx>
96 #include <comphelper/seqstream.hxx>
97 #include <comphelper/documentconstants.hxx>
98 #include <comphelper/string.hxx>
99 #include <vcl/bitmapex.hxx>
100 #include <svtools/embedhlp.hxx>
101 #include <rtl/logfile.hxx>
102 #include <basic/modsizeexceeded.hxx>
103 #include <osl/file.hxx>
105 #include <sfx2/signaturestate.hxx>
106 #include <sfx2/app.hxx>
107 #include <sfx2/objsh.hxx>
108 #include <sfx2/childwin.hxx>
109 #include <sfx2/request.hxx>
110 #include "sfx2/sfxresid.hxx"
111 #include <sfx2/docfile.hxx>
112 #include "fltfnc.hxx"
113 #include <sfx2/docfilt.hxx>
114 #include <sfx2/docfac.hxx>
115 #include "objshimp.hxx"
116 #include "sfxtypes.hxx"
117 #include "doc.hrc"
118 #include <sfx2/sfxsids.hrc>
119 #include <sfx2/module.hxx>
120 #include <sfx2/dispatch.hxx>
121 #include "openflag.hxx"
122 #include "helper.hxx"
123 #include <sfx2/event.hxx>
124 #include "fltoptint.hxx"
125 #include <sfx2/viewfrm.hxx>
126 #include "graphhelp.hxx"
127 #include "appbaslib.hxx"
128 #include "appdata.hxx"
130 #include "../appl/app.hrc"
132 extern sal_uInt32 CheckPasswd_Impl( SfxObjectShell*, SfxItemPool&, SfxMedium* );
134 using namespace ::com::sun::star;
135 using namespace ::com::sun::star::container;
136 using namespace ::com::sun::star::lang;
137 using namespace ::com::sun::star::ui::dialogs;
138 using namespace ::com::sun::star::uno;
139 using namespace ::com::sun::star::beans;
140 using namespace ::com::sun::star::ucb;
141 using namespace ::com::sun::star::task;
142 using namespace ::com::sun::star::document;
143 using namespace ::rtl;
144 using namespace ::cppu;
146 //=========================================================================
147 void impl_addToModelCollection(const css::uno::Reference< css::frame::XModel >& xModel)
149 if (!xModel.is())
150 return;
152 css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
153 css::uno::Reference< css::frame::XGlobalEventBroadcaster > xModelCollection =
154 css::frame::GlobalEventBroadcaster::create(xContext);
157 xModelCollection->insert(css::uno::makeAny(xModel));
159 catch ( uno::Exception& )
161 OSL_FAIL( "The document seems to be in the collection already!\n" );
165 //=========================================================================
167 sal_Bool SfxObjectShell::Save()
169 return SaveChildren();
172 //--------------------------------------------------------------------------
174 sal_Bool SfxObjectShell::SaveAs( SfxMedium& rMedium )
176 return SaveAsChildren( rMedium );
179 //-------------------------------------------------------------------------
181 sal_Bool SfxObjectShell::QuerySlotExecutable( sal_uInt16 /*nSlotId*/ )
183 return sal_True;
186 //-------------------------------------------------------------------------
188 bool GetEncryptionData_Impl( const SfxItemSet* pSet, uno::Sequence< beans::NamedValue >& o_rEncryptionData )
190 bool bResult = false;
191 if ( pSet )
193 SFX_ITEMSET_ARG( pSet, pEncryptionDataItem, SfxUnoAnyItem, SID_ENCRYPTIONDATA, sal_False);
194 if ( pEncryptionDataItem )
196 pEncryptionDataItem->GetValue() >>= o_rEncryptionData;
197 bResult = true;
199 else
201 SFX_ITEMSET_ARG( pSet, pPasswordItem, SfxStringItem, SID_PASSWORD, sal_False);
202 if ( pPasswordItem )
204 OUString aPassword = pPasswordItem->GetValue();
205 o_rEncryptionData = ::comphelper::OStorageHelper::CreatePackageEncryptionData( aPassword );
206 bResult = true;
211 return bResult;
214 //-------------------------------------------------------------------------
215 sal_Bool SfxObjectShell::PutURLContentsToVersionStream_Impl(
216 OUString aURL,
217 const uno::Reference< embed::XStorage >& xDocStorage,
218 OUString aStreamName )
220 sal_Bool bResult = sal_False;
223 uno::Reference< embed::XStorage > xVersion = xDocStorage->openStorageElement(
224 OUString("Versions"),
225 embed::ElementModes::READWRITE );
227 DBG_ASSERT( xVersion.is(),
228 "The method must throw an exception if the storage can not be opened!\n" );
229 if ( !xVersion.is() )
230 throw uno::RuntimeException();
232 uno::Reference< io::XStream > xVerStream = xVersion->openStreamElement(
233 aStreamName,
234 embed::ElementModes::READWRITE );
235 DBG_ASSERT( xVerStream.is(), "The method must throw an exception if the storage can not be opened!\n" );
236 if ( !xVerStream.is() )
237 throw uno::RuntimeException();
239 uno::Reference< io::XOutputStream > xOutStream = xVerStream->getOutputStream();
240 uno::Reference< io::XTruncate > xTrunc( xOutStream, uno::UNO_QUERY );
242 DBG_ASSERT( xTrunc.is(), "The output stream must exist and implement XTruncate interface!\n" );
243 if ( !xTrunc.is() )
244 throw RuntimeException();
246 uno::Reference< io::XInputStream > xTmpInStream =
247 ::comphelper::OStorageHelper::GetInputStreamFromURL(
248 aURL, comphelper::getProcessComponentContext() );
249 assert( xTmpInStream.is() );
251 xTrunc->truncate();
252 ::comphelper::OStorageHelper::CopyInputToOutput( xTmpInStream, xOutStream );
253 xOutStream->closeOutput();
255 uno::Reference< embed::XTransactedObject > xTransact( xVersion, uno::UNO_QUERY );
256 DBG_ASSERT( xTransact.is(), "The storage must implement XTransacted interface!\n" );
257 if ( xTransact.is() )
258 xTransact->commit();
260 bResult = sal_True;
262 catch( uno::Exception& )
264 // TODO/LATER: handle the error depending on exception
265 SetError( ERRCODE_IO_GENERAL, OUString( OSL_LOG_PREFIX ) );
268 return bResult;
271 //-------------------------------------------------------------------------
272 OUString SfxObjectShell::CreateTempCopyOfStorage_Impl( const uno::Reference< embed::XStorage >& xStorage )
274 OUString aTempURL = ::utl::TempFile().GetURL();
276 DBG_ASSERT( !aTempURL.isEmpty(), "Can't create a temporary file!\n" );
277 if ( !aTempURL.isEmpty() )
281 uno::Reference< embed::XStorage > xTempStorage =
282 ::comphelper::OStorageHelper::GetStorageFromURL( aTempURL, embed::ElementModes::READWRITE );
284 // the password will be transferred from the xStorage to xTempStorage by storage implemetation
285 xStorage->copyToStorage( xTempStorage );
287 // the temporary storage was commited by the previous method and it will die by refcount
289 catch ( uno::Exception& )
291 OSL_FAIL( "Creation of a storage copy is failed!" );
292 ::utl::UCBContentHelper::Kill( aTempURL );
294 aTempURL = OUString();
296 // TODO/LATER: may need error code setting based on exception
297 SetError( ERRCODE_IO_GENERAL, OUString( OSL_LOG_PREFIX ) );
301 return aTempURL;
304 //-------------------------------------------------------------------------
305 SvGlobalName SfxObjectShell::GetClassName() const
307 return GetFactory().GetClassId();
310 namespace {
313 * Chart2 does not have an Object shell, so handle this here for now
314 * If we ever implement a full scale object shell in chart2 move it there
316 sal_uInt32 GetChartVersion( sal_Int32 nVersion, bool bTemplate )
318 if( nVersion == SOFFICE_FILEFORMAT_60)
320 return SOT_FORMATSTR_ID_STARCHART_60;
322 else if( nVersion == SOFFICE_FILEFORMAT_8)
324 if (bTemplate)
326 SAL_WARN("sfx2", "no chart template support yet");
327 return SOT_FORMATSTR_ID_STARCHART_8;
329 else
330 return SOT_FORMATSTR_ID_STARCHART_8;
333 SAL_WARN("sfx2", "unsupported version");
334 return 0;
339 //-------------------------------------------------------------------------
340 void SfxObjectShell::SetupStorage( const uno::Reference< embed::XStorage >& xStorage,
341 sal_Int32 nVersion, sal_Bool bTemplate, bool bChart ) const
343 uno::Reference< beans::XPropertySet > xProps( xStorage, uno::UNO_QUERY );
345 if ( xProps.is() )
347 SvGlobalName aName;
348 OUString aFullTypeName, aShortTypeName, aAppName;
349 sal_uInt32 nClipFormat=0;
351 if(!bChart)
352 FillClass( &aName, &nClipFormat, &aAppName, &aFullTypeName, &aShortTypeName, nVersion, bTemplate );
353 else
354 nClipFormat = GetChartVersion(nVersion, bTemplate);
356 if ( nClipFormat )
358 // basic doesn't have a ClipFormat
359 // without MediaType the storage is not really usable, but currently the BasicIDE still
360 // is an SfxObjectShell and so we can't take this as an error
361 datatransfer::DataFlavor aDataFlavor;
362 SotExchange::GetFormatDataFlavor( nClipFormat, aDataFlavor );
363 if ( !aDataFlavor.MimeType.isEmpty() )
367 xProps->setPropertyValue( OUString("MediaType"), uno::makeAny( aDataFlavor.MimeType ) );
369 catch( uno::Exception& )
371 const_cast<SfxObjectShell*>( this )->SetError( ERRCODE_IO_GENERAL, OUString( OSL_LOG_PREFIX ) );
374 SvtSaveOptions aSaveOpt;
375 SvtSaveOptions::ODFDefaultVersion nDefVersion = aSaveOpt.GetODFDefaultVersion();
377 uno::Sequence< beans::NamedValue > aEncryptionAlgs( 3 );
378 aEncryptionAlgs[0].Name = OUString( "StartKeyGenerationAlgorithm" );
379 aEncryptionAlgs[1].Name = OUString( "EncryptionAlgorithm" );
380 aEncryptionAlgs[2].Name = OUString( "ChecksumAlgorithm" );
381 // the default values, that should be used for ODF1.1 and older formats
382 aEncryptionAlgs[0].Value <<= xml::crypto::DigestID::SHA1;
383 aEncryptionAlgs[1].Value <<= xml::crypto::CipherID::BLOWFISH_CFB_8;
384 aEncryptionAlgs[2].Value <<= xml::crypto::DigestID::SHA1_1K;
386 if ( nVersion >= SOFFICE_FILEFORMAT_8 )
390 // older versions can not have this property set, it exists only starting from ODF1.2
391 xProps->setPropertyValue( OUString("Version" ), uno::makeAny( ODFVER_012_TEXT ) );
393 catch( uno::Exception& )
397 if ( !aSaveOpt.IsUseSHA1InODF12() && nDefVersion != SvtSaveOptions::ODFVER_012_EXT_COMPAT )
399 aEncryptionAlgs[0].Value <<= xml::crypto::DigestID::SHA256;
400 aEncryptionAlgs[2].Value <<= xml::crypto::DigestID::SHA256_1K;
402 if ( !aSaveOpt.IsUseBlowfishInODF12() && nDefVersion != SvtSaveOptions::ODFVER_012_EXT_COMPAT )
403 aEncryptionAlgs[1].Value <<= xml::crypto::CipherID::AES_CBC_W3C_PADDING;
408 // set the encryption algorithms accordingly;
409 // the setting does not trigger encryption,
410 // it just provides the format for the case that contents should be encrypted
411 uno::Reference< embed::XEncryptionProtectedStorage > xEncr( xStorage, uno::UNO_QUERY_THROW );
412 xEncr->setEncryptionAlgorithms( aEncryptionAlgs );
414 catch( uno::Exception& )
416 const_cast<SfxObjectShell*>( this )->SetError( ERRCODE_IO_GENERAL, OUString( OSL_LOG_PREFIX ) );
424 //-------------------------------------------------------------------------
425 void SfxObjectShell::PrepareSecondTryLoad_Impl()
427 // only for internal use
428 pImp->m_xDocStorage = uno::Reference< embed::XStorage >();
429 pImp->m_bIsInit = sal_False;
430 ResetError();
433 //-------------------------------------------------------------------------
434 sal_Bool SfxObjectShell::GeneralInit_Impl( const uno::Reference< embed::XStorage >& xStorage,
435 sal_Bool bTypeMustBeSetAlready )
437 if ( pImp->m_bIsInit )
438 return sal_False;
440 pImp->m_bIsInit = sal_True;
441 if ( xStorage.is() )
443 // no notification is required the storage is set the first time
444 pImp->m_xDocStorage = xStorage;
446 try {
447 uno::Reference < beans::XPropertySet > xPropSet( xStorage, uno::UNO_QUERY_THROW );
448 Any a = xPropSet->getPropertyValue( OUString("MediaType" ) );
449 OUString aMediaType;
450 if ( !(a>>=aMediaType) || aMediaType.isEmpty() )
452 if ( bTypeMustBeSetAlready )
454 SetError( ERRCODE_IO_BROKENPACKAGE, OUString( OSL_LOG_PREFIX ) );
455 return sal_False;
458 SetupStorage( xStorage, SOFFICE_FILEFORMAT_CURRENT, sal_False, false );
461 catch ( uno::Exception& )
463 OSL_FAIL( "Can't check storage's mediatype!\n" );
466 else
467 pImp->m_bCreateTempStor = sal_True;
469 return sal_True;
472 //-------------------------------------------------------------------------
473 sal_Bool SfxObjectShell::InitNew( const uno::Reference< embed::XStorage >& xStorage )
475 return GeneralInit_Impl( xStorage, sal_False );
478 //-------------------------------------------------------------------------
479 sal_Bool SfxObjectShell::Load( SfxMedium& rMedium )
481 return GeneralInit_Impl( rMedium.GetStorage(), sal_True );
484 bool SfxObjectShell::DoInitUnitTest()
486 pMedium = new SfxMedium;
487 return true; // always a success!
490 sal_Bool SfxObjectShell::DoInitNew( SfxMedium* pMed )
491 /* [Description]
493 This from SvPersist inherited virtual method is called to initialize
494 the SfxObjectShell instance from a storage (PStore! = 0) or (PStore == 0)
496 Like with all Do...-methods there is a from a control, the actual
497 implementation is done by the virtual method in which also the
498 InitNew(SvStorate *) from the SfxObjectShell-Subclass is implemented.
500 For pStore == 0 the SfxObjectShell-instance is connected to an empty
501 SfxMedium, otherwise a SfxMedium, which refers to the SvStorage
502 passed as a parameter.
504 The object is only initialized correctly after InitNew() or Load().
506 [Return value]
507 sal_True The object has been initialized.
508 sal_False The object could not be initialized
512 ModifyBlocker_Impl aBlock( this );
513 pMedium = pMed;
514 if ( !pMedium )
516 bIsTmp = sal_True;
517 pMedium = new SfxMedium;
520 pMedium->CanDisposeStorage_Impl( sal_True );
522 if ( InitNew( pMed ? pMed->GetStorage() : uno::Reference < embed::XStorage >() ) )
524 // empty documents always get their macros from the user, so there is no reason to restrict access
525 pImp->aMacroMode.allowMacroExecution();
526 if ( SFX_CREATE_MODE_EMBEDDED == eCreateMode )
527 SetTitle(SfxResId(STR_NONAME).toString());
529 uno::Reference< frame::XModel > xModel ( GetModel(), uno::UNO_QUERY );
530 if ( xModel.is() )
532 SfxItemSet *pSet = GetMedium()->GetItemSet();
533 uno::Sequence< beans::PropertyValue > aArgs;
534 TransformItems( SID_OPENDOC, *pSet, aArgs );
535 sal_Int32 nLength = aArgs.getLength();
536 aArgs.realloc( nLength + 1 );
537 aArgs[nLength].Name = "Title";
538 aArgs[nLength].Value <<= OUString( GetTitle( SFX_TITLE_DETECT ) );
539 xModel->attachResource( OUString(), aArgs );
540 impl_addToModelCollection(xModel);
543 SetInitialized_Impl( true );
544 return sal_True;
547 return sal_False;
550 //-------------------------------------------------------------------------
552 sal_Bool SfxObjectShell::ImportFromGeneratedStream_Impl(
553 const uno::Reference< io::XStream >& xStream,
554 const uno::Sequence< beans::PropertyValue >& aMediaDescr )
556 if ( !xStream.is() )
557 return sal_False;
559 if ( pMedium && pMedium->HasStorage_Impl() )
560 pMedium->CloseStorage();
562 sal_Bool bResult = sal_False;
566 uno::Reference< embed::XStorage > xStorage =
567 ::comphelper::OStorageHelper::GetStorageFromStream( xStream, embed::ElementModes::READWRITE );
569 if ( !xStorage.is() )
570 throw uno::RuntimeException();
572 if ( !pMedium )
573 pMedium = new SfxMedium( xStorage, String() );
574 else
575 pMedium->SetStorage_Impl( xStorage );
577 SfxAllItemSet aSet( SFX_APP()->GetPool() );
578 TransformParameters( SID_OPENDOC, aMediaDescr, aSet );
579 pMedium->GetItemSet()->Put( aSet );
580 pMedium->CanDisposeStorage_Impl( sal_False );
582 // allow the subfilter to reinit the model
583 if ( pImp->m_bIsInit )
584 pImp->m_bIsInit = sal_False;
586 if ( LoadOwnFormat( *pMedium ) )
588 bHasName = sal_True;
589 if ( !IsReadOnly() && IsLoadReadonly() )
590 SetReadOnlyUI();
592 bResult = sal_True;
593 OSL_ENSURE( pImp->m_xDocStorage == xStorage, "Wrong storage is used!\n" );
596 // now the medium can be disconnected from the storage
597 // the medium is not allowed to dispose the storage so CloseStorage() can be used
598 pMedium->CloseStorage();
600 catch( uno::Exception& )
604 return bResult;
607 //-------------------------------------------------------------------------
609 sal_Bool SfxObjectShell::DoLoad( SfxMedium *pMed )
611 ModifyBlocker_Impl aBlock( this );
613 pMedium = pMed;
614 pMedium->CanDisposeStorage_Impl( sal_True );
616 sal_Bool bOk = sal_False;
617 const SfxFilter* pFilter = pMed->GetFilter();
618 SfxItemSet* pSet = pMedium->GetItemSet();
619 if( !pImp->nEventId )
621 SFX_ITEMSET_ARG(
622 pSet, pTemplateItem, SfxBoolItem,
623 SID_TEMPLATE, sal_False);
624 SetActivateEvent_Impl(
625 ( pTemplateItem && pTemplateItem->GetValue() )
626 ? SFX_EVENT_CREATEDOC : SFX_EVENT_OPENDOC );
630 SFX_ITEMSET_ARG( pSet, pBaseItem, SfxStringItem,
631 SID_BASEURL, sal_False);
632 OUString aBaseURL;
633 SFX_ITEMSET_ARG( pMedium->GetItemSet(), pSalvageItem, SfxStringItem, SID_DOC_SALVAGE, sal_False);
634 if( pBaseItem )
635 aBaseURL = pBaseItem->GetValue();
636 else
638 if ( pSalvageItem )
640 OUString aName( pMed->GetPhysicalName() );
641 ::utl::LocalFileHelper::ConvertPhysicalNameToURL( aName, aBaseURL );
643 else
644 aBaseURL = pMed->GetBaseURL();
646 pMed->GetItemSet()->Put( SfxStringItem( SID_DOC_BASEURL, aBaseURL ) );
648 pImp->nLoadedFlags = 0;
649 pImp->bModelInitialized = sal_False;
651 //TODO/LATER: make a clear strategy how to handle "UsesStorage" etc.
652 sal_Bool bOwnStorageFormat = IsOwnStorageFormat_Impl( *pMedium );
653 sal_Bool bHasStorage = IsPackageStorageFormat_Impl( *pMedium );
654 if ( pMedium->GetFilter() )
656 sal_uInt32 nError = HandleFilter( pMedium, this );
657 if ( nError != ERRCODE_NONE )
658 SetError( nError, OUString( OSL_LOG_PREFIX ) );
660 if (pMedium->GetFilter()->GetFilterFlags() & SFX_FILTER_STARTPRESENTATION)
661 pSet->Put( SfxBoolItem( SID_DOC_STARTPRESENTATION, sal_True) );
664 EnableSetModified( sal_False );
666 pMedium->LockOrigFileOnDemand( sal_True, sal_False );
667 if ( GetError() == ERRCODE_NONE && bOwnStorageFormat && ( !pFilter || !( pFilter->GetFilterFlags() & SFX_FILTER_STARONEFILTER ) ) )
669 uno::Reference< embed::XStorage > xStorage;
670 if ( pMedium->GetError() == ERRCODE_NONE )
671 xStorage = pMedium->GetStorage();
673 if( xStorage.is() && pMedium->GetLastStorageCreationState() == ERRCODE_NONE )
675 DBG_ASSERT( pFilter, "No filter for storage found!" );
679 sal_Bool bWarnMediaTypeFallback = sal_False;
680 SFX_ITEMSET_ARG( pMedium->GetItemSet(), pRepairPackageItem, SfxBoolItem, SID_REPAIRPACKAGE, sal_False);
682 // treat the package as broken if the mediatype was retrieved as a fallback
683 uno::Reference< beans::XPropertySet > xStorProps( xStorage, uno::UNO_QUERY_THROW );
684 xStorProps->getPropertyValue( OUString( "MediaTypeFallbackUsed" ) )
685 >>= bWarnMediaTypeFallback;
687 if ( pRepairPackageItem && pRepairPackageItem->GetValue() )
689 // the macros in repaired documents should be disabled
690 pMedium->GetItemSet()->Put( SfxUInt16Item( SID_MACROEXECMODE, document::MacroExecMode::NEVER_EXECUTE ) );
692 // the mediatype was retrieved by using fallback solution but this is a repairing mode
693 // so it is acceptable to open the document if there is no contents that required manifest.xml
694 bWarnMediaTypeFallback = sal_False;
697 if ( bWarnMediaTypeFallback || !xStorage->getElementNames().getLength() )
698 SetError( ERRCODE_IO_BROKENPACKAGE, OUString( OSL_LOG_PREFIX ) );
700 catch( uno::Exception& )
702 // TODO/LATER: may need error code setting based on exception
703 SetError( ERRCODE_IO_GENERAL, OUString( OSL_LOG_PREFIX ) );
706 // Load
707 if ( !GetError() )
709 pImp->nLoadedFlags = 0;
710 pImp->bModelInitialized = sal_False;
711 bOk = xStorage.is() && LoadOwnFormat( *pMed );
712 if ( bOk )
714 // the document loaded from template has no name
715 SFX_ITEMSET_ARG( pMedium->GetItemSet(), pTemplateItem, SfxBoolItem, SID_TEMPLATE, sal_False);
716 if ( !pTemplateItem || !pTemplateItem->GetValue() )
717 bHasName = sal_True;
719 else
720 SetError( ERRCODE_ABORT, OUString( OSL_LOG_PREFIX ) );
723 else
724 SetError( pMed->GetLastStorageCreationState(), OUString( OSL_LOG_PREFIX ) );
726 else if ( GetError() == ERRCODE_NONE && InitNew(0) )
728 // Name vor ConvertFrom setzen, damit GetSbxObject() schon funktioniert
729 bHasName = sal_True;
730 SetName( SfxResId(STR_NONAME).toString() );
732 if( !bHasStorage )
733 pMedium->GetInStream();
734 else
735 pMedium->GetStorage();
737 if ( GetError() == ERRCODE_NONE )
739 pImp->nLoadedFlags = 0;
740 pImp->bModelInitialized = sal_False;
741 if ( pMedium->GetFilter() && ( pMedium->GetFilter()->GetFilterFlags() & SFX_FILTER_STARONEFILTER ) )
743 uno::Reference < beans::XPropertySet > xSet( GetModel(), uno::UNO_QUERY );
744 OUString sLockUpdates("LockUpdates");
745 bool bSetProperty = true;
748 xSet->setPropertyValue( sLockUpdates, makeAny( (sal_Bool) sal_True ) );
750 catch(const beans::UnknownPropertyException& )
752 bSetProperty = false;
754 bOk = ImportFrom( *pMedium, false );
755 if(bSetProperty)
759 xSet->setPropertyValue( sLockUpdates, makeAny( (sal_Bool) sal_False ) );
761 catch(const beans::UnknownPropertyException& )
764 UpdateLinks();
765 FinishedLoading( SFX_LOADED_ALL );
767 else
769 bOk = ConvertFrom(*pMedium);
770 InitOwnModel_Impl();
775 if ( bOk )
777 if ( IsReadOnlyMedium() || IsLoadReadonly() )
778 SetReadOnlyUI();
782 ::ucbhelper::Content aContent( pMedium->GetName(), com::sun::star::uno::Reference < XCommandEnvironment >(), comphelper::getProcessComponentContext() );
783 com::sun::star::uno::Reference < XPropertySetInfo > xProps = aContent.getProperties();
784 if ( xProps.is() )
786 OUString aAuthor( "Author" );
787 OUString aKeywords( "Keywords" );
788 OUString aSubject( "Subject" );
789 Any aAny;
790 OUString aValue;
791 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
792 GetModel(), uno::UNO_QUERY_THROW);
793 uno::Reference<document::XDocumentProperties> xDocProps
794 = xDPS->getDocumentProperties();
795 if ( xProps->hasPropertyByName( aAuthor ) )
797 aAny = aContent.getPropertyValue( aAuthor );
798 if ( ( aAny >>= aValue ) )
799 xDocProps->setAuthor(aValue);
801 if ( xProps->hasPropertyByName( aKeywords ) )
803 aAny = aContent.getPropertyValue( aKeywords );
804 if ( ( aAny >>= aValue ) )
805 xDocProps->setKeywords(
806 ::comphelper::string::convertCommaSeparated(aValue));
809 if ( xProps->hasPropertyByName( aSubject ) )
811 aAny = aContent.getPropertyValue( aSubject );
812 if ( ( aAny >>= aValue ) ) {
813 xDocProps->setSubject(aValue);
818 catch( Exception& )
822 // If not loaded asynchronously call FinishedLoading
823 if ( !( pImp->nLoadedFlags & SFX_LOADED_MAINDOCUMENT ) &&
824 ( !pMedium->GetFilter() || pMedium->GetFilter()->UsesStorage() )
826 FinishedLoading( SFX_LOADED_MAINDOCUMENT );
828 if( IsOwnStorageFormat_Impl(*pMed) && pMed->GetFilter() )
831 Broadcast( SfxSimpleHint(SFX_HINT_NAMECHANGED) );
833 if ( SFX_CREATE_MODE_EMBEDDED != eCreateMode )
835 SFX_ITEMSET_ARG( pMedium->GetItemSet(), pAsTempItem, SfxBoolItem, SID_TEMPLATE, sal_False);
836 SFX_ITEMSET_ARG( pMedium->GetItemSet(), pPreviewItem, SfxBoolItem, SID_PREVIEW, sal_False);
837 SFX_ITEMSET_ARG( pMedium->GetItemSet(), pHiddenItem, SfxBoolItem, SID_HIDDEN, sal_False);
838 if( bOk && !pMedium->GetOrigURL().isEmpty()
839 && !( pAsTempItem && pAsTempItem->GetValue() )
840 && !( pPreviewItem && pPreviewItem->GetValue() )
841 && !( pHiddenItem && pHiddenItem->GetValue() ) )
843 AddToRecentlyUsedList();
847 const SfxBoolItem* pDdeReconnectItem = static_cast<const SfxBoolItem*>(
848 SfxRequest::GetItem(pMedium->GetItemSet(), SID_DDE_RECONNECT_ONLOAD, false, TYPE(SfxBoolItem)));
850 bool bReconnectDde = true; // by default, we try to auto-connect DDE connections.
851 if (pDdeReconnectItem)
852 bReconnectDde = pDdeReconnectItem->GetValue();
854 if (bReconnectDde)
855 ReconnectDdeLinks(*this);
858 return bOk;
861 bool SfxObjectShell::DoLoadExternal( SfxMedium *pMed )
863 pMedium = pMed;
864 return LoadExternal(*pMedium);
867 sal_uInt32 SfxObjectShell::HandleFilter( SfxMedium* pMedium, SfxObjectShell* pDoc )
869 sal_uInt32 nError = ERRCODE_NONE;
870 SfxItemSet* pSet = pMedium->GetItemSet();
871 SFX_ITEMSET_ARG( pSet, pOptions, SfxStringItem, SID_FILE_FILTEROPTIONS, sal_False );
872 SFX_ITEMSET_ARG( pSet, pData, SfxUnoAnyItem, SID_FILTER_DATA, sal_False );
873 if ( !pData && !pOptions )
875 com::sun::star::uno::Reference< XMultiServiceFactory > xServiceManager = ::comphelper::getProcessServiceFactory();
876 com::sun::star::uno::Reference< XNameAccess > xFilterCFG;
877 if( xServiceManager.is() )
879 xFilterCFG = com::sun::star::uno::Reference< XNameAccess >(
880 xServiceManager->createInstance( OUString("com.sun.star.document.FilterFactory") ),
881 UNO_QUERY );
884 if( xFilterCFG.is() )
886 sal_Bool bAbort = sal_False;
887 try {
888 const SfxFilter* pFilter = pMedium->GetFilter();
889 Sequence < PropertyValue > aProps;
890 Any aAny = xFilterCFG->getByName( pFilter->GetName() );
891 if ( aAny >>= aProps )
893 sal_Int32 nPropertyCount = aProps.getLength();
894 for( sal_Int32 nProperty=0; nProperty < nPropertyCount; ++nProperty )
895 if( aProps[nProperty].Name == "UIComponent" )
897 OUString aServiceName;
898 aProps[nProperty].Value >>= aServiceName;
899 if( !aServiceName.isEmpty() )
901 com::sun::star::uno::Reference< XInteractionHandler > rHandler = pMedium->GetInteractionHandler();
902 if( rHandler.is() )
904 // we need some properties in the media descriptor, so we have to make sure that they are in
905 Any aStreamAny;
906 aStreamAny <<= pMedium->GetInputStream();
907 if ( pSet->GetItemState( SID_INPUTSTREAM ) < SFX_ITEM_SET )
908 pSet->Put( SfxUnoAnyItem( SID_INPUTSTREAM, aStreamAny ) );
909 if ( pSet->GetItemState( SID_FILE_NAME ) < SFX_ITEM_SET )
910 pSet->Put( SfxStringItem( SID_FILE_NAME, pMedium->GetName() ) );
911 if ( pSet->GetItemState( SID_FILTER_NAME ) < SFX_ITEM_SET )
912 pSet->Put( SfxStringItem( SID_FILTER_NAME, pFilter->GetName() ) );
914 Sequence< PropertyValue > rProperties;
915 TransformItems( SID_OPENDOC, *pSet, rProperties, NULL );
916 RequestFilterOptions* pFORequest = new RequestFilterOptions( pDoc->GetModel(), rProperties );
918 com::sun::star::uno::Reference< XInteractionRequest > rRequest( pFORequest );
919 rHandler->handle( rRequest );
921 if ( !pFORequest->isAbort() )
923 SfxAllItemSet aNewParams( pDoc->GetPool() );
924 TransformParameters( SID_OPENDOC,
925 pFORequest->getFilterOptions(),
926 aNewParams,
927 NULL );
929 SFX_ITEMSET_ARG( &aNewParams,
930 pFilterOptions,
931 SfxStringItem,
932 SID_FILE_FILTEROPTIONS,
933 sal_False );
934 if ( pFilterOptions )
935 pSet->Put( *pFilterOptions );
937 SFX_ITEMSET_ARG( &aNewParams,
938 pFilterData,
939 SfxUnoAnyItem,
940 SID_FILTER_DATA,
941 sal_False );
942 if ( pFilterData )
943 pSet->Put( *pFilterData );
945 else
946 bAbort = sal_True;
950 break;
954 if( bAbort )
956 // filter options were not entered
957 nError = ERRCODE_ABORT;
960 catch( NoSuchElementException& )
962 // the filter name is unknown
963 nError = ERRCODE_IO_INVALIDPARAMETER;
965 catch( Exception& )
967 nError = ERRCODE_ABORT;
972 return nError;
975 //-------------------------------------------------------------------------
977 sal_Bool SfxObjectShell::IsOwnStorageFormat_Impl(const SfxMedium &rMedium) const
979 return !rMedium.GetFilter() || // Embedded
980 ( rMedium.GetFilter()->IsOwnFormat() &&
981 rMedium.GetFilter()->UsesStorage() &&
982 rMedium.GetFilter()->GetVersion() >= SOFFICE_FILEFORMAT_60 );
985 //-------------------------------------------------------------------------
987 sal_Bool SfxObjectShell::IsPackageStorageFormat_Impl(const SfxMedium &rMedium) const
989 return !rMedium.GetFilter() || // Embedded
990 ( rMedium.GetFilter()->UsesStorage() &&
991 rMedium.GetFilter()->GetVersion() >= SOFFICE_FILEFORMAT_60 );
994 //-------------------------------------------------------------------------
996 sal_Bool SfxObjectShell::DoSave()
997 // DoSave is only invoked for OLE. Save your own documents in the SFX through
998 // DoSave_Impl order to allow for the creation of backups.
999 // Save in your own format again.
1001 sal_Bool bOk = sal_False ;
1003 ModifyBlocker_Impl aBlock( this );
1005 pImp->bIsSaving = sal_True;
1007 uno::Sequence< beans::NamedValue > aEncryptionData;
1008 if ( IsPackageStorageFormat_Impl( *GetMedium() ) )
1010 if ( GetEncryptionData_Impl( GetMedium()->GetItemSet(), aEncryptionData ) )
1014 //TODO/MBA: GetOutputStorage?! Special mode, because it's "Save"?!
1015 ::comphelper::OStorageHelper::SetCommonStorageEncryptionData( GetMedium()->GetStorage(), aEncryptionData );
1016 bOk = sal_True;
1018 catch( uno::Exception& )
1020 SetError( ERRCODE_IO_GENERAL, OUString( OSL_LOG_PREFIX ) );
1023 DBG_ASSERT( bOk, "The root storage must allow to set common password!\n" );
1025 else
1026 bOk = sal_True;
1027 #ifndef DISABLE_SCRIPTING
1028 if ( HasBasic() )
1032 // The basic and dialogs related contents are still not able to proceed with save operation ( saveTo only )
1033 // so since the document storage is locked a workaround has to be used
1035 uno::Reference< embed::XStorage > xTmpStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
1036 DBG_ASSERT( xTmpStorage.is(), "If a storage can not be created an exception must be thrown!\n" );
1037 if ( !xTmpStorage.is() )
1038 throw uno::RuntimeException();
1040 OUString aBasicStorageName( "Basic" );
1041 OUString aDialogsStorageName( "Dialogs" );
1042 if ( GetMedium()->GetStorage()->hasByName( aBasicStorageName ) )
1043 GetMedium()->GetStorage()->copyElementTo( aBasicStorageName, xTmpStorage, aBasicStorageName );
1044 if ( GetMedium()->GetStorage()->hasByName( aDialogsStorageName ) )
1045 GetMedium()->GetStorage()->copyElementTo( aDialogsStorageName, xTmpStorage, aDialogsStorageName );
1047 GetBasicManager();
1049 // disconnect from the current storage
1050 pImp->pBasicManager->setStorage( xTmpStorage );
1052 // store to the current storage
1053 pImp->pBasicManager->storeLibrariesToStorage( GetMedium()->GetStorage() );
1055 // connect to the current storage back
1056 pImp->pBasicManager->setStorage( GetMedium()->GetStorage() );
1058 catch( uno::Exception& )
1060 SetError( ERRCODE_IO_GENERAL, OUString( OSL_LOG_PREFIX ) );
1061 bOk = sal_False;
1064 #endif
1067 if ( bOk )
1068 bOk = Save();
1070 bOk = pMedium->Commit();
1073 return bOk;
1076 void Lock_Impl( SfxObjectShell* pDoc, sal_Bool bLock )
1078 SfxViewFrame *pFrame= SfxViewFrame::GetFirst( pDoc );
1079 while ( pFrame )
1081 pFrame->GetDispatcher()->Lock( bLock );
1082 pFrame->Enable( !bLock );
1083 pFrame = SfxViewFrame::GetNext( *pFrame, pDoc );
1088 //-------------------------------------------------------------------------
1090 sal_Bool SfxObjectShell::SaveTo_Impl
1092 SfxMedium &rMedium, // Medium, in which it will be stored
1093 const SfxItemSet* pSet
1096 /* [Description]
1098 Writes the current contents to the medium rMedium. If the target medium is
1099 no storage, then saving to a temporary storage, or directly if the medium
1100 is transacted, if we ourselves have opened it, and if we are a server
1101 either the container a transacted storage provides or created a
1102 temporary storage by one self.
1106 RTL_LOGFILE_PRODUCT_CONTEXT( aLog, "PERFORMANCE SfxObjectShell::SaveTo_Impl" );
1107 if( RTL_LOGFILE_HASLOGFILE() )
1109 OString aString(
1110 OUStringToOString(rMedium.GetName(), RTL_TEXTENCODING_ASCII_US));
1111 RTL_LOGFILE_PRODUCT_CONTEXT_TRACE1(aLog, "saving \"%s\"", aString.getStr());
1114 AddLog( OUString( OSL_LOG_PREFIX "Begin" ) );
1116 ModifyBlocker_Impl aMod(this);
1118 const SfxFilter *pFilter = rMedium.GetFilter();
1119 if ( !pFilter )
1121 // if no filter was set, use the default filter
1122 // this should be changed in the feature, it should be an error!
1123 OSL_FAIL("No filter set!");
1124 pFilter = GetFactory().GetFilterContainer()->GetAnyFilter( SFX_FILTER_IMPORT | SFX_FILTER_EXPORT );
1125 rMedium.SetFilter(pFilter);
1128 sal_Bool bStorageBasedSource = IsPackageStorageFormat_Impl( *pMedium );
1129 sal_Bool bStorageBasedTarget = IsPackageStorageFormat_Impl( rMedium );
1130 sal_Bool bOwnSource = IsOwnStorageFormat_Impl( *pMedium );
1131 sal_Bool bOwnTarget = IsOwnStorageFormat_Impl( rMedium );
1133 // Examine target format to determine whether to query if any password
1134 // protected libraries exceed the size we can handler
1135 if ( bOwnTarget && !QuerySaveSizeExceededModules_Impl( rMedium.GetInteractionHandler() ) )
1137 SetError( ERRCODE_IO_ABORT, OUString( OSL_LOG_PREFIX ) );
1138 return sal_False;
1141 sal_Bool bNeedsDisconnectionOnFail = sal_False;
1143 sal_Bool bStoreToSameLocation = sal_False;
1145 // the detection whether the script is changed should be done before saving
1146 sal_Bool bTryToPreserveScriptSignature = sal_False;
1147 // no way to detect whether a filter is oasis format, have to wait for saving process
1148 sal_Bool bNoPreserveForOasis = sal_False;
1149 if ( bOwnSource && bOwnTarget
1150 && ( pImp->nScriptingSignatureState == SIGNATURESTATE_SIGNATURES_OK
1151 || pImp->nScriptingSignatureState == SIGNATURESTATE_SIGNATURES_NOTVALIDATED
1152 || pImp->nScriptingSignatureState == SIGNATURESTATE_SIGNATURES_INVALID ) )
1154 AddLog( OUString( OSL_LOG_PREFIX "MacroSignaturePreserving" ) );
1156 // the checking of the library modified state iterates over the libraries, should be done only when required
1157 // currently the check is commented out since it is broken, we have to check the signature every time we save
1158 // TODO/LATER: let isAnyContainerModified() work!
1159 bTryToPreserveScriptSignature = sal_True; // !pImp->pBasicManager->isAnyContainerModified();
1160 if ( bTryToPreserveScriptSignature )
1162 // check that the storage format stays the same
1163 SvtSaveOptions aSaveOpt;
1164 SvtSaveOptions::ODFDefaultVersion nVersion = aSaveOpt.GetODFDefaultVersion();
1166 OUString aODFVersion;
1169 uno::Reference < beans::XPropertySet > xPropSet( GetStorage(), uno::UNO_QUERY_THROW );
1170 xPropSet->getPropertyValue( OUString( "Version" ) ) >>= aODFVersion;
1172 catch( uno::Exception& )
1175 // preserve only if the same filter has been used
1176 bTryToPreserveScriptSignature = pMedium->GetFilter() && pFilter && pMedium->GetFilter()->GetFilterName() == pFilter->GetFilterName();
1178 bNoPreserveForOasis = (
1179 (aODFVersion.equals( ODFVER_012_TEXT ) && nVersion == SvtSaveOptions::ODFVER_011) ||
1180 (aODFVersion.isEmpty() && nVersion >= SvtSaveOptions::ODFVER_012)
1185 sal_Bool bCopyTo = sal_False;
1186 SfxItemSet *pMedSet = rMedium.GetItemSet();
1187 if( pMedSet )
1189 SFX_ITEMSET_ARG( pMedSet, pSaveToItem, SfxBoolItem, SID_SAVETO, sal_False );
1190 bCopyTo = GetCreateMode() == SFX_CREATE_MODE_EMBEDDED ||
1191 (pSaveToItem && pSaveToItem->GetValue());
1194 // use UCB for case sensitive/insensitive file name comparison
1195 if ( pMedium
1196 && !pMedium->GetName().equalsIgnoreAsciiCase("private:stream")
1197 && !rMedium.GetName().equalsIgnoreAsciiCase("private:stream")
1198 && ::utl::UCBContentHelper::EqualURLs( pMedium->GetName(), rMedium.GetName() ) )
1200 bStoreToSameLocation = sal_True;
1201 AddLog( OUString( OSL_LOG_PREFIX "Save" ) );
1203 if ( pMedium->DocNeedsFileDateCheck() )
1204 rMedium.CheckFileDate( pMedium->GetInitFileDate( sal_False ) );
1206 if ( bCopyTo && GetCreateMode() != SFX_CREATE_MODE_EMBEDDED )
1208 // export to the same location is forbidden
1209 SetError( ERRCODE_IO_CANTWRITE, OUString( OSL_LOG_PREFIX ) );
1211 else
1213 // before we overwrite the original file, we will make a backup if there is a demand for that
1214 // if the backup is not created here it will be created internally and will be removed in case of successful saving
1215 const sal_Bool bDoBackup = SvtSaveOptions().IsBackup();
1216 if ( bDoBackup )
1218 AddLog( OUString( OSL_LOG_PREFIX "DoBackup" ) );
1219 rMedium.DoBackup_Impl();
1220 if ( rMedium.GetError() )
1222 SetError( rMedium.GetErrorCode(), OUString( OSL_LOG_PREFIX ) );
1223 rMedium.ResetError();
1227 if ( bStorageBasedSource && bStorageBasedTarget )
1229 // The active storage must be switched. The simple saving is not enough.
1230 // The problem is that the target medium contains target MediaDescriptor.
1232 // In future the switch of the persistance could be done on stream level:
1233 // a new wrapper service will be implemented that allows to exchange
1234 // persistance on the fly. So the real persistance will be set
1235 // to that stream only after successful commit of the storage.
1236 // TODO/LATER:
1237 // create wrapper stream based on the URL
1238 // create a new storage based on this stream
1239 // store to this new storage
1240 // commit the new storage
1241 // call saveCompleted based with this new storage ( get rid of old storage and "frees" URL )
1242 // commit the wrapper stream ( the stream will connect the URL only on commit, after that it will hold it )
1243 // if the last step is failed the stream should stay to be transacted and should be commited on any flush
1244 // so we can forget the stream in any way and the next storage commit will flush it
1246 AddLog( OUString( OSL_LOG_PREFIX "Save: Own to Own" ) );
1248 bNeedsDisconnectionOnFail = DisconnectStorage_Impl(
1249 *pMedium, rMedium );
1250 if ( bNeedsDisconnectionOnFail
1251 || ConnectTmpStorage_Impl( pMedium->GetStorage(), pMedium ) )
1253 pMedium->CloseAndRelease();
1255 // TODO/LATER: for now the medium must be closed since it can already contain streams from old medium
1256 // in future those streams should not be copied in case a valid target url is provided,
1257 // if the url is not provided ( means the document is based on a stream ) this code is not
1258 // reachable.
1259 rMedium.CloseAndRelease();
1260 rMedium.GetOutputStorage();
1263 else if ( !bStorageBasedSource && !bStorageBasedTarget )
1265 // the source and the target formats are alien
1266 // just disconnect the stream from the source format
1267 // so that the target medium can use it
1269 AddLog( OUString( OSL_LOG_PREFIX "Save: Alien to Alien" ) );
1271 pMedium->CloseAndRelease();
1272 rMedium.CloseAndRelease();
1273 rMedium.CreateTempFileNoCopy();
1274 rMedium.GetOutStream();
1276 else if ( !bStorageBasedSource && bStorageBasedTarget )
1278 // the source format is an alien one but the target
1279 // format is an own one so just disconnect the source
1280 // medium
1282 AddLog( OUString( OSL_LOG_PREFIX "Save: Alien to Own" ) );
1284 pMedium->CloseAndRelease();
1285 rMedium.CloseAndRelease();
1286 rMedium.GetOutputStorage();
1288 else // means if ( bStorageBasedSource && !bStorageBasedTarget )
1290 // the source format is an own one but the target is
1291 // an alien format, just connect the source to temporary
1292 // storage
1294 AddLog( OUString( OSL_LOG_PREFIX "Save: Own to Alien" ) );
1296 bNeedsDisconnectionOnFail = DisconnectStorage_Impl(
1297 *pMedium, rMedium );
1298 if ( bNeedsDisconnectionOnFail
1299 || ConnectTmpStorage_Impl( pMedium->GetStorage(), pMedium ) )
1301 pMedium->CloseAndRelease();
1302 rMedium.CloseAndRelease();
1303 rMedium.CreateTempFileNoCopy();
1304 rMedium.GetOutStream();
1309 else
1311 // This is SaveAs or export action, prepare the target medium
1312 // the alien filters still might write directly to the file, that is of course a bug,
1313 // but for now the framework has to be ready for it
1314 // TODO/LATER: let the medium be prepared for alien formats as well
1316 AddLog( OUString( OSL_LOG_PREFIX "SaveAs/Export" ) );
1318 rMedium.CloseAndRelease();
1319 if ( bStorageBasedTarget )
1321 rMedium.GetOutputStorage();
1325 // TODO/LATER: error handling
1326 if( rMedium.GetErrorCode() || pMedium->GetErrorCode() || GetErrorCode() )
1327 return sal_False;
1329 AddLog( OUString( OSL_LOG_PREFIX "Locking" ) );
1331 rMedium.LockOrigFileOnDemand( sal_False, sal_False );
1333 if ( bStorageBasedTarget )
1335 if ( rMedium.GetErrorCode() )
1336 return sal_False;
1338 // If the filter is a "cross export" filter ( f.e. a filter for exporting an impress document from
1339 // a draw document ), the ClassId of the destination storage is different from the ClassId of this
1340 // document. It can be retrieved from the default filter for the desired target format
1341 long nFormat = rMedium.GetFilter()->GetFormat();
1342 SfxFilterMatcher& rMatcher = SFX_APP()->GetFilterMatcher();
1343 const SfxFilter *pFilt = rMatcher.GetFilter4ClipBoardId( nFormat );
1344 if ( pFilt )
1346 if ( pFilt->GetServiceName() != rMedium.GetFilter()->GetServiceName() )
1348 datatransfer::DataFlavor aDataFlavor;
1349 SotExchange::GetFormatDataFlavor( nFormat, aDataFlavor );
1353 uno::Reference< beans::XPropertySet > xProps( rMedium.GetStorage(), uno::UNO_QUERY );
1354 DBG_ASSERT( xProps.is(), "The storage implementation must implement XPropertySet!" );
1355 if ( !xProps.is() )
1356 throw uno::RuntimeException();
1358 xProps->setPropertyValue( OUString("MediaType"),
1359 uno::makeAny( aDataFlavor.MimeType ) );
1361 catch( uno::Exception& )
1368 // TODO/LATER: error handling
1369 if( rMedium.GetErrorCode() || pMedium->GetErrorCode() || GetErrorCode() )
1370 return sal_False;
1372 sal_Bool bOldStat = pImp->bForbidReload;
1373 pImp->bForbidReload = sal_True;
1375 // lock user interface while saving the document
1376 Lock_Impl( this, sal_True );
1378 sal_Bool bOk = sal_False;
1379 // TODO/LATER: get rid of bOk
1381 if( bOwnTarget && !( pFilter->GetFilterFlags() & SFX_FILTER_STARONEFILTER ) )
1383 AddLog( OUString( OSL_LOG_PREFIX "Storing in own format." ) );
1384 uno::Reference< embed::XStorage > xMedStorage = rMedium.GetStorage();
1385 if ( !xMedStorage.is() )
1387 // no saving without storage, unlock UI and return
1388 Lock_Impl( this, sal_False );
1389 pImp->bForbidReload = bOldStat;
1390 AddLog( OUString( OSL_LOG_PREFIX "Storing failed, still no error set." ) );
1391 return sal_False;
1394 // transfer password from the parameters to the storage
1395 uno::Sequence< beans::NamedValue > aEncryptionData;
1396 sal_Bool bPasswdProvided = sal_False;
1397 if ( GetEncryptionData_Impl( rMedium.GetItemSet(), aEncryptionData ) )
1399 bPasswdProvided = sal_True;
1400 try {
1401 ::comphelper::OStorageHelper::SetCommonStorageEncryptionData( xMedStorage, aEncryptionData );
1402 bOk = sal_True;
1404 catch( uno::Exception& )
1406 OSL_FAIL( "Setting of common encryption key failed!" );
1407 SetError( ERRCODE_IO_GENERAL, OUString( OSL_LOG_PREFIX ) );
1410 else
1411 bOk = sal_True;
1413 pFilter = rMedium.GetFilter();
1415 const SfxStringItem *pVersionItem = ( !rMedium.IsInCheckIn( ) && pSet ) ? (const SfxStringItem*)
1416 SfxRequest::GetItem( pSet, SID_DOCINFO_COMMENTS, sal_False, TYPE(SfxStringItem) ) : NULL;
1417 OUString aTmpVersionURL;
1419 if ( bOk )
1421 bOk = sal_False;
1422 // currently the case that the storage is the same should be impossible
1423 if ( xMedStorage == GetStorage() )
1425 OSL_ENSURE( !pVersionItem, "This scenario is impossible currently!\n" );
1426 AddLog( OUString( OSL_LOG_PREFIX "Should be impossible." ) );
1427 // usual save procedure
1428 bOk = Save();
1430 else
1432 // save to target
1433 AddLog( OUString( OSL_LOG_PREFIX "Save as own format." ) );
1434 bOk = SaveAsOwnFormat( rMedium );
1435 if ( bOk && pVersionItem )
1437 AddLog( OUString( OSL_LOG_PREFIX "pVersionItem != NULL" ) );
1438 aTmpVersionURL = CreateTempCopyOfStorage_Impl( xMedStorage );
1439 bOk = !aTmpVersionURL.isEmpty();
1445 if ( bOk && GetCreateMode() != SFX_CREATE_MODE_EMBEDDED && !bPasswdProvided )
1447 // store the thumbnail representation image
1448 // the thumbnail is not stored in case of encrypted document
1449 AddLog( OUString( OSL_LOG_PREFIX "Thumbnail creation." ) );
1450 if ( !GenerateAndStoreThumbnail( bPasswdProvided,
1451 sal_False,
1452 pFilter->IsOwnTemplateFormat(),
1453 xMedStorage ) )
1455 // TODO: error handling
1456 OSL_FAIL( "Couldn't store thumbnail representation!" );
1460 if ( bOk )
1462 if ( pImp->bIsSaving || pImp->bPreserveVersions )
1464 AddLog( OUString( OSL_LOG_PREFIX "Preserve versions." ) );
1467 Sequence < util::RevisionTag > aVersions = rMedium.GetVersionList();
1468 if ( aVersions.getLength() )
1470 // copy the version streams
1471 OUString aVersionsName( "Versions" );
1472 uno::Reference< embed::XStorage > xNewVerStor = xMedStorage->openStorageElement(
1473 aVersionsName,
1474 embed::ElementModes::READWRITE );
1475 uno::Reference< embed::XStorage > xOldVerStor = GetStorage()->openStorageElement(
1476 aVersionsName,
1477 embed::ElementModes::READ );
1478 if ( !xNewVerStor.is() || !xOldVerStor.is() )
1479 throw uno::RuntimeException();
1481 for ( sal_Int32 n=0; n<aVersions.getLength(); n++ )
1483 if ( xOldVerStor->hasByName( aVersions[n].Identifier ) )
1484 xOldVerStor->copyElementTo( aVersions[n].Identifier, xNewVerStor, aVersions[n].Identifier );
1487 uno::Reference< embed::XTransactedObject > xTransact( xNewVerStor, uno::UNO_QUERY );
1488 if ( xTransact.is() )
1489 xTransact->commit();
1492 catch( uno::Exception& )
1494 AddLog( OUString( OSL_LOG_PREFIX "Preserve versions has failed." ) );
1495 OSL_FAIL( "Couldn't copy versions!\n" );
1496 bOk = sal_False;
1497 // TODO/LATER: a specific error could be set
1501 if ( bOk && pVersionItem && !rMedium.IsInCheckIn() )
1503 // store a version also
1504 const SfxStringItem *pAuthorItem = pSet ? (const SfxStringItem*)
1505 SfxRequest::GetItem( pSet, SID_DOCINFO_AUTHOR, sal_False, TYPE(SfxStringItem) ) : NULL;
1507 // version comment
1508 util::RevisionTag aInfo;
1509 aInfo.Comment = pVersionItem->GetValue();
1511 // version author
1512 if ( pAuthorItem )
1513 aInfo.Author = pAuthorItem->GetValue();
1514 else
1515 // if not transferred as a parameter, get it from user settings
1516 aInfo.Author = SvtUserOptions().GetFullName();
1518 DateTime aTime( DateTime::SYSTEM );
1519 aInfo.TimeStamp.Day = aTime.GetDay();
1520 aInfo.TimeStamp.Month = aTime.GetMonth();
1521 aInfo.TimeStamp.Year = aTime.GetYear();
1522 aInfo.TimeStamp.Hours = aTime.GetHour();
1523 aInfo.TimeStamp.Minutes = aTime.GetMin();
1524 aInfo.TimeStamp.Seconds = aTime.GetSec();
1526 if ( bOk )
1528 // add new version information into the versionlist and save the versionlist
1529 // the version list must have been transferred from the "old" medium before
1530 rMedium.AddVersion_Impl( aInfo );
1531 rMedium.SaveVersionList_Impl( sal_True );
1532 bOk = PutURLContentsToVersionStream_Impl( aTmpVersionURL, xMedStorage, aInfo.Identifier );
1535 else if ( bOk && ( pImp->bIsSaving || pImp->bPreserveVersions ) )
1537 rMedium.SaveVersionList_Impl( sal_True );
1541 if ( !aTmpVersionURL.isEmpty() )
1542 ::utl::UCBContentHelper::Kill( aTmpVersionURL );
1544 else
1546 AddLog( OUString( OSL_LOG_PREFIX "Storing in alien format." ) );
1547 // it's a "SaveAs" in an alien format
1548 if ( rMedium.GetFilter() && ( rMedium.GetFilter()->GetFilterFlags() & SFX_FILTER_STARONEFILTER ) )
1549 bOk = ExportTo( rMedium );
1550 else
1551 bOk = ConvertTo( rMedium );
1553 // after saving the document, the temporary object storage must be updated
1554 // if the old object storage was not a temporary one, it will be updated also, because it will be used
1555 // as a source for copying the objects into the new temporary storage that will be created below
1556 // updating means: all child objects must be stored into it
1557 // ( same as on loading, where these objects are copied to the temporary storage )
1558 // but don't commit these changes, because in the case when the old object storage is not a temporary one,
1559 // all changes will be written into the original file !
1561 if( bOk && !bCopyTo )
1562 // we also don't touch any graphical replacements here
1563 bOk = SaveChildren( sal_True );
1566 if ( bOk )
1568 // if ODF version of oasis format changes on saving the signature should not be preserved
1569 if ( bOk && bTryToPreserveScriptSignature && bNoPreserveForOasis )
1570 bTryToPreserveScriptSignature = ( SotStorage::GetVersion( rMedium.GetStorage() ) == SOFFICE_FILEFORMAT_60 );
1572 uno::Reference< security::XDocumentDigitalSignatures > xDDSigns;
1573 if ( bOk && bTryToPreserveScriptSignature )
1575 AddLog( OUString( OSL_LOG_PREFIX "Copying scripting signature." ) );
1577 // if the scripting code was not changed and it is signed the signature should be preserved
1578 // unfortunately at this point we have only information whether the basic code has changed or not
1579 // so the only way is to check the signature if the basic was not changed
1582 // get the ODF version of the new medium
1583 OUString aVersion;
1586 uno::Reference < beans::XPropertySet > xPropSet( rMedium.GetStorage(), uno::UNO_QUERY_THROW );
1587 xPropSet->getPropertyValue( OUString( "Version" ) ) >>= aVersion;
1589 catch( uno::Exception& )
1593 xDDSigns = security::DocumentDigitalSignatures::createWithVersion(comphelper::getProcessComponentContext(), aVersion);
1595 OUString aScriptSignName = xDDSigns->getScriptingContentSignatureDefaultStreamName();
1597 if ( !aScriptSignName.isEmpty() )
1599 pMedium->Close();
1601 // target medium is still not commited, it should not be closed
1602 // commit the package storage and close it, but leave the streams open
1603 rMedium.StorageCommit_Impl();
1604 rMedium.CloseStorage();
1606 uno::Reference< embed::XStorage > xReadOrig = pMedium->GetZipStorageToSign_Impl();
1607 if ( !xReadOrig.is() )
1608 throw uno::RuntimeException();
1609 uno::Reference< embed::XStorage > xMetaInf = xReadOrig->openStorageElement(
1610 OUString( "META-INF" ),
1611 embed::ElementModes::READ );
1613 uno::Reference< embed::XStorage > xTarget = rMedium.GetZipStorageToSign_Impl( sal_False );
1614 if ( !xTarget.is() )
1615 throw uno::RuntimeException();
1616 uno::Reference< embed::XStorage > xTargetMetaInf = xTarget->openStorageElement(
1617 OUString( "META-INF" ),
1618 embed::ElementModes::READWRITE );
1620 if ( xMetaInf.is() && xTargetMetaInf.is() )
1622 xMetaInf->copyElementTo( aScriptSignName, xTargetMetaInf, aScriptSignName );
1624 uno::Reference< embed::XTransactedObject > xTransact( xTargetMetaInf, uno::UNO_QUERY );
1625 if ( xTransact.is() )
1626 xTransact->commit();
1628 xTargetMetaInf->dispose();
1630 // now check the copied signature
1631 uno::Sequence< security::DocumentSignatureInformation > aInfos =
1632 xDDSigns->verifyScriptingContentSignatures( xTarget,
1633 uno::Reference< io::XInputStream >() );
1634 sal_uInt16 nState = ImplCheckSignaturesInformation( aInfos );
1635 if ( nState == SIGNATURESTATE_SIGNATURES_OK || nState == SIGNATURESTATE_SIGNATURES_NOTVALIDATED
1636 || nState == SIGNATURESTATE_SIGNATURES_PARTIAL_OK)
1638 rMedium.SetCachedSignatureState_Impl( nState );
1640 // commit the ZipStorage from target medium
1641 xTransact.set( xTarget, uno::UNO_QUERY );
1642 if ( xTransact.is() )
1643 xTransact->commit();
1645 else
1647 // it should not happen, the copies signature is invalid!
1648 // throw the changes away
1649 OSL_FAIL( "An invalid signature was copied!" );
1654 catch( uno::Exception& )
1658 pMedium->Close();
1659 rMedium.CloseZipStorage_Impl();
1662 AddLog( OUString( OSL_LOG_PREFIX "Medium commit." ) );
1664 OUString sName( rMedium.GetName( ) );
1665 bOk = rMedium.Commit();
1666 OUString sNewName( rMedium.GetName( ) );
1668 if ( sName != sNewName )
1669 GetMedium( )->SwitchDocumentToFile( sNewName );
1671 if ( bOk )
1673 AddLog( OUString( OSL_LOG_PREFIX "Storing is successful." ) );
1675 // if the target medium is an alien format and the "old" medium was an own format and the "old" medium
1676 // has a name, the object storage must be exchanged, because now we need a new temporary storage
1677 // as object storage
1678 if ( !bCopyTo && bStorageBasedSource && !bStorageBasedTarget )
1680 if ( bStoreToSameLocation )
1682 // if the old medium already disconnected from document storage, the storage still must
1683 // be switched if backup file is used
1684 if ( bNeedsDisconnectionOnFail )
1685 ConnectTmpStorage_Impl( pImp->m_xDocStorage, NULL );
1687 else if (!pMedium->GetName().isEmpty()
1688 || ( pMedium->HasStorage_Impl() && pMedium->WillDisposeStorageOnClose_Impl() ) )
1690 OSL_ENSURE(!pMedium->GetName().isEmpty(), "Fallback is used, the medium without name should not dispose the storage!\n");
1691 // copy storage of old medium to new temporary storage and take this over
1692 if( !ConnectTmpStorage_Impl( pMedium->GetStorage(), pMedium ) )
1694 AddLog( OUString( OSL_LOG_PREFIX "Process after storing has failed." ) );
1695 bOk = sal_False;
1700 else
1702 AddLog( OUString( OSL_LOG_PREFIX "Storing has failed." ) );
1704 // in case the document storage was connected to backup temporarely it must be disconnected now
1705 if ( bNeedsDisconnectionOnFail )
1706 ConnectTmpStorage_Impl( pImp->m_xDocStorage, NULL );
1710 // unlock user interface
1711 Lock_Impl( this, sal_False );
1712 pImp->bForbidReload = bOldStat;
1714 if ( bOk )
1718 ::ucbhelper::Content aContent( rMedium.GetName(), com::sun::star::uno::Reference < XCommandEnvironment >(), comphelper::getProcessComponentContext() );
1719 com::sun::star::uno::Reference < XPropertySetInfo > xProps = aContent.getProperties();
1720 if ( xProps.is() )
1722 OUString aAuthor( "Author" );
1723 OUString aKeywords( "Keywords" );
1724 OUString aSubject( "Subject" );
1725 Any aAny;
1727 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
1728 GetModel(), uno::UNO_QUERY_THROW);
1729 uno::Reference<document::XDocumentProperties> xDocProps
1730 = xDPS->getDocumentProperties();
1732 if ( xProps->hasPropertyByName( aAuthor ) )
1734 aAny <<= xDocProps->getAuthor();
1735 aContent.setPropertyValue( aAuthor, aAny );
1737 if ( xProps->hasPropertyByName( aKeywords ) )
1739 aAny <<= ::comphelper::string::convertCommaSeparated(
1740 xDocProps->getKeywords());
1741 aContent.setPropertyValue( aKeywords, aAny );
1743 if ( xProps->hasPropertyByName( aSubject ) )
1745 aAny <<= xDocProps->getSubject();
1746 aContent.setPropertyValue( aSubject, aAny );
1750 catch( Exception& )
1755 return bOk;
1758 //------------------------------------------------------------------------
1759 sal_Bool SfxObjectShell::DisconnectStorage_Impl( SfxMedium& rSrcMedium, SfxMedium& rTargetMedium )
1761 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::DisconnectStorage_Impl" );
1763 // this method disconnects the storage from source medium, and attaches it to the backup created by the target medium
1765 uno::Reference< embed::XStorage > xStorage = rSrcMedium.GetStorage();
1767 sal_Bool bResult = sal_False;
1768 if ( xStorage == pImp->m_xDocStorage )
1772 uno::Reference< embed::XOptimizedStorage > xOptStorage( xStorage, uno::UNO_QUERY_THROW );
1773 OUString aBackupURL = rTargetMedium.GetBackup_Impl();
1774 if ( aBackupURL.isEmpty() )
1776 // the backup could not be created, try to disconnect the storage and close the source SfxMedium
1777 // in this case the optimization is not possible, connect storage to a temporary file
1778 rTargetMedium.ResetError();
1779 xOptStorage->writeAndAttachToStream( uno::Reference< io::XStream >() );
1780 rSrcMedium.CanDisposeStorage_Impl( sal_False );
1781 rSrcMedium.Close();
1783 // now try to create the backup
1784 rTargetMedium.GetBackup_Impl();
1786 else
1788 // the following call will only compare stream sizes
1789 // TODO/LATER: this is a very risky part, since if the URL contents are different from the storage
1790 // contents, the storag will be broken
1791 xOptStorage->attachToURL( aBackupURL, sal_True );
1793 // the storage is successfully attached to backup, thus it it owned by the document not by the medium
1794 rSrcMedium.CanDisposeStorage_Impl( sal_False );
1795 bResult = sal_True;
1798 catch ( uno::Exception& )
1802 return bResult;
1805 //------------------------------------------------------------------------
1807 sal_Bool SfxObjectShell::ConnectTmpStorage_Impl(
1808 const uno::Reference< embed::XStorage >& xStorage,
1809 SfxMedium* pMediumArg )
1811 /* [Description]
1813 If the application operates on a temporary storage, then it may not take
1814 the temporary storage from the SaveCompleted. Therefore the new storage
1815 is connected already here in this case and SaveCompleted then does nothing.
1819 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::ConnectTmpStorage_Impl" );
1821 sal_Bool bResult = sal_False;
1823 if ( xStorage.is() )
1827 // the empty argument means that the storage will create temporary stream itself
1828 uno::Reference< embed::XOptimizedStorage > xOptStorage( xStorage, uno::UNO_QUERY_THROW );
1829 xOptStorage->writeAndAttachToStream( uno::Reference< io::XStream >() );
1831 // the storage is successfully disconnected from the original sources, thus the medium must not dispose it
1832 if ( pMediumArg )
1833 pMediumArg->CanDisposeStorage_Impl( sal_False );
1835 bResult = sal_True;
1837 catch( uno::Exception& )
1841 // if switching of the storage does not work for any reason ( nonroot storage for example ) use the old method
1842 if ( !bResult ) try
1844 uno::Reference< embed::XStorage > xTmpStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
1846 DBG_ASSERT( xTmpStorage.is(), "If a storage can not be created an exception must be thrown!\n" );
1847 if ( !xTmpStorage.is() )
1848 throw uno::RuntimeException();
1850 // TODO/LATER: may be it should be done in SwitchPersistence also
1851 // TODO/LATER: find faster way to copy storage; perhaps sharing with backup?!
1852 xStorage->copyToStorage( xTmpStorage );
1853 bResult = SaveCompleted( xTmpStorage );
1855 if ( bResult )
1857 pImp->pBasicManager->setStorage( xTmpStorage );
1859 // Get rid of this workaround after issue i113914 is fixed
1862 uno::Reference< script::XStorageBasedLibraryContainer > xBasicLibraries( pImp->xBasicLibraries, uno::UNO_QUERY_THROW );
1863 xBasicLibraries->setRootStorage( xTmpStorage );
1865 catch( uno::Exception& )
1869 uno::Reference< script::XStorageBasedLibraryContainer > xDialogLibraries( pImp->xDialogLibraries, uno::UNO_QUERY_THROW );
1870 xDialogLibraries->setRootStorage( xTmpStorage );
1872 catch( uno::Exception& )
1876 catch( uno::Exception& )
1879 if ( !bResult )
1881 // TODO/LATER: may need error code setting based on exception
1882 SetError( ERRCODE_IO_GENERAL, OUString( OSL_LOG_PREFIX ) );
1886 return bResult;
1889 //-------------------------------------------------------------------------
1891 sal_Bool SfxObjectShell::DoSaveObjectAs( SfxMedium& rMedium, sal_Bool bCommit )
1893 sal_Bool bOk = sal_False;
1895 ModifyBlocker_Impl aBlock( this );
1897 uno::Reference < embed::XStorage > xNewStor = rMedium.GetStorage();
1898 if ( !xNewStor.is() )
1899 return sal_False;
1901 uno::Reference < beans::XPropertySet > xPropSet( xNewStor, uno::UNO_QUERY );
1902 if ( xPropSet.is() )
1904 Any a = xPropSet->getPropertyValue( OUString("MediaType" ) );
1905 OUString aMediaType;
1906 if ( !(a>>=aMediaType) || aMediaType.isEmpty() )
1908 OSL_FAIL( "The mediatype must be set already!\n" );
1909 SetupStorage( xNewStor, SOFFICE_FILEFORMAT_CURRENT, sal_False, false );
1912 pImp->bIsSaving = sal_False;
1913 bOk = SaveAsOwnFormat( rMedium );
1915 if ( bCommit )
1917 try {
1918 uno::Reference< embed::XTransactedObject > xTransact( xNewStor, uno::UNO_QUERY_THROW );
1919 xTransact->commit();
1921 catch( uno::Exception& )
1923 OSL_FAIL( "The strotage was not commited on DoSaveAs!\n" );
1929 return bOk;
1932 //-------------------------------------------------------------------------
1933 // TODO/LATER: may be the call must be removed completelly
1934 sal_Bool SfxObjectShell::DoSaveAs( SfxMedium& rMedium )
1936 // here only root storages are included, which are stored via temp file
1937 rMedium.CreateTempFileNoCopy();
1938 SetError(rMedium.GetErrorCode(), OUString( OSL_LOG_PREFIX ) );
1939 if ( GetError() )
1940 return sal_False;
1942 // copy version list from "old" medium to target medium, so it can be used on saving
1943 if ( pImp->bPreserveVersions )
1944 rMedium.TransferVersionList_Impl( *pMedium );
1946 sal_Bool bRet = SaveTo_Impl( rMedium, NULL );
1947 if ( !bRet )
1948 SetError(rMedium.GetErrorCode(), OUString( OSL_LOG_PREFIX ) );
1949 return bRet;
1952 //-------------------------------------------------------------------------
1954 sal_Bool SfxObjectShell::DoSaveCompleted( SfxMedium* pNewMed )
1956 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::DoSaveCompleted" );
1958 sal_Bool bOk = sal_True;
1959 sal_Bool bMedChanged = pNewMed && pNewMed!=pMedium;
1961 DBG_ASSERT( !pNewMed || pNewMed->GetError() == ERRCODE_NONE, "DoSaveCompleted: Medium has error!" );
1963 // delete Medium (and Storage!) after all notifications
1964 SfxMedium* pOld = pMedium;
1965 if ( bMedChanged )
1967 pMedium = pNewMed;
1968 pMedium->CanDisposeStorage_Impl( sal_True );
1971 const SfxFilter *pFilter = pMedium ? pMedium->GetFilter() : 0;
1972 if ( pNewMed )
1974 if( bMedChanged )
1976 if (!pNewMed->GetName().isEmpty())
1977 bHasName = sal_True;
1978 Broadcast( SfxSimpleHint(SFX_HINT_NAMECHANGED) );
1979 getDocProperties()->setGenerator(
1980 ::utl::DocInfoHelper::GetGeneratorString() );
1983 uno::Reference< embed::XStorage > xStorage;
1984 if ( !pFilter || IsPackageStorageFormat_Impl( *pMedium ) )
1986 uno::Reference < embed::XStorage > xOld = GetStorage();
1988 // when the package based medium is broken and has no storage or if the storage
1989 // is the same as the document storage the current document storage should be preserved
1990 xStorage = pMedium->GetStorage();
1991 bOk = SaveCompleted( xStorage );
1992 if ( bOk && xStorage.is() && xOld != xStorage
1993 && (!pOld || !pOld->HasStorage_Impl() || xOld != pOld->GetStorage() ) )
1995 // old own storage was not controlled by old Medium -> dispose it
1996 try {
1997 xOld->dispose();
1998 } catch( uno::Exception& )
2000 // the storage is disposed already
2001 // can happen during reload scenario when the medium has
2002 // disposed it during the closing
2003 // will be fixed in one of the next milestones
2007 else
2009 if( pMedium->GetOpenMode() & STREAM_WRITE )
2010 pMedium->GetInStream();
2011 xStorage = GetStorage();
2014 // TODO/LATER: may be this code will be replaced, but not sure
2015 // Set storage in document library containers
2016 pImp->pBasicManager->setStorage( xStorage );
2018 // Get rid of this workaround after issue i113914 is fixed
2021 uno::Reference< script::XStorageBasedLibraryContainer > xBasicLibraries( pImp->xBasicLibraries, uno::UNO_QUERY_THROW );
2022 xBasicLibraries->setRootStorage( xStorage );
2024 catch( uno::Exception& )
2028 uno::Reference< script::XStorageBasedLibraryContainer > xDialogLibraries( pImp->xDialogLibraries, uno::UNO_QUERY_THROW );
2029 xDialogLibraries->setRootStorage( xStorage );
2031 catch( uno::Exception& )
2034 else
2036 if( pMedium )
2038 if( pFilter && !IsPackageStorageFormat_Impl( *pMedium ) && (pMedium->GetOpenMode() & STREAM_WRITE ))
2040 pMedium->ReOpen();
2041 bOk = SaveCompletedChildren( sal_False );
2043 else
2044 bOk = SaveCompleted( NULL );
2046 // either Save or ConvertTo
2047 else
2048 bOk = SaveCompleted( NULL );
2051 if ( bOk && pNewMed )
2053 if( bMedChanged )
2055 delete pOld;
2057 uno::Reference< frame::XModel > xModel = GetModel();
2058 if ( xModel.is() )
2060 OUString aURL = pNewMed->GetOrigURL();
2061 uno::Sequence< beans::PropertyValue > aMediaDescr;
2062 TransformItems( SID_OPENDOC, *pNewMed->GetItemSet(), aMediaDescr );
2065 xModel->attachResource( aURL, aMediaDescr );
2067 catch( uno::Exception& )
2071 // before the title regenerated the document must loose the signatures
2072 pImp->nDocumentSignatureState = SIGNATURESTATE_NOSIGNATURES;
2073 pImp->nScriptingSignatureState = pNewMed->GetCachedSignatureState_Impl();
2074 OSL_ENSURE( pImp->nScriptingSignatureState != SIGNATURESTATE_SIGNATURES_BROKEN, "The signature must not be broken at this place" );
2075 pImp->bSignatureErrorIsShown = sal_False;
2077 // TODO/LATER: in future the medium must control own signature state, not the document
2078 pNewMed->SetCachedSignatureState_Impl( SIGNATURESTATE_NOSIGNATURES ); // set the default value back
2080 // Set new title
2081 if (!pNewMed->GetName().isEmpty() && SFX_CREATE_MODE_EMBEDDED != eCreateMode)
2082 InvalidateName();
2083 SetModified(sal_False); // reset only by set medium
2084 Broadcast( SfxSimpleHint(SFX_HINT_MODECHANGED) );
2086 // this is the end of the saving process, it is possible that
2087 // the file was changed
2088 // between medium commit and this step (attributes change and so on)
2089 // so get the file date again
2090 if ( pNewMed->DocNeedsFileDateCheck() )
2091 pNewMed->GetInitFileDate( sal_True );
2095 pMedium->ClearBackup_Impl();
2096 pMedium->LockOrigFileOnDemand( sal_True, sal_False );
2098 AddToRecentlyUsedList();
2100 return bOk;
2103 void SfxObjectShell::AddToRecentlyUsedList()
2105 INetURLObject aUrl( pMedium->GetOrigURL() );
2107 if ( aUrl.GetProtocol() == INET_PROT_FILE )
2109 const SfxFilter* pOrgFilter = pMedium->GetOrigFilter();
2110 Application::AddToRecentDocumentList( aUrl.GetURLNoPass( INetURLObject::NO_DECODE ),
2111 (pOrgFilter) ? pOrgFilter->GetMimeType() : OUString(),
2112 (pOrgFilter) ? pOrgFilter->GetServiceName() : OUString() );
2116 //-------------------------------------------------------------------------
2118 sal_Bool SfxObjectShell::ConvertFrom
2120 SfxMedium& /*rMedium*/ /* <SfxMedium>, which describes the source file
2121 (for example file name, <SfxFilter>,
2122 Open-Modi and so on) */
2125 /* [Description]
2127 This method is called for loading of documents over all filters which are
2128 not SFX_FILTER_OWN or for which no clipboard format has been registered
2129 (thus no storage format that is used). In other words, with this method
2130 it is imported.
2132 Files which are to be opened here should be opened through 'rMedium'
2133 to guarantee the right open modes. Especially if the format is retained
2134 (only possible with SFX_FILTER_SIMULATE or SFX_FILTER_ONW) file which must
2135 be opened STREAM_SHARE_DENYWRITE.
2137 [Return value]
2139 sal_Bool sal_True
2140 The document could be loaded.
2142 sal_False
2143 The document could not be loaded, an error code
2144 received through <SvMedium::GetError()const>
2146 [Example]
2148 sal_Bool DocSh::ConvertFrom( SfxMedium &rMedium )
2150 SvStreamRef xStream = rMedium.GetInStream();
2151 if( xStream.is() )
2153 xStream->SetBufferSize(4096);
2154 *xStream >> ...;
2156 // Do not call 'rMedium.CloseInStream()'! Keep File locked!
2157 return SVSTREAM_OK == rMedium.GetError();
2160 return sal_False;
2163 [Cross-references]
2165 <SfxObjectShell::ConvertTo(SfxMedium&)>
2166 <SFX_FILTER_REGISTRATION>
2169 return sal_False;
2172 sal_Bool SfxObjectShell::ImportFrom( SfxMedium& rMedium, bool bInsert )
2174 OUString aFilterName( rMedium.GetFilter()->GetFilterName() );
2176 uno::Reference< lang::XMultiServiceFactory > xMan = ::comphelper::getProcessServiceFactory();
2177 uno::Reference < lang::XMultiServiceFactory > xFilterFact (
2178 xMan->createInstance( "com.sun.star.document.FilterFactory" ), uno::UNO_QUERY );
2180 uno::Sequence < beans::PropertyValue > aProps;
2181 uno::Reference < container::XNameAccess > xFilters ( xFilterFact, uno::UNO_QUERY );
2182 if ( xFilters->hasByName( aFilterName ) )
2184 xFilters->getByName( aFilterName ) >>= aProps;
2185 rMedium.GetItemSet()->Put( SfxStringItem( SID_FILTER_NAME, aFilterName ) );
2188 OUString aFilterImplName;
2189 sal_Int32 nFilterProps = aProps.getLength();
2190 for ( sal_Int32 nFilterProp = 0; nFilterProp<nFilterProps; nFilterProp++ )
2192 const beans::PropertyValue& rFilterProp = aProps[nFilterProp];
2193 if ( rFilterProp.Name.compareToAscii("FilterService") == COMPARE_EQUAL )
2195 rFilterProp.Value >>= aFilterImplName;
2196 break;
2200 uno::Reference< document::XFilter > xLoader;
2201 if ( !aFilterImplName.isEmpty() )
2203 try{
2204 xLoader = uno::Reference< document::XFilter >
2205 ( xFilterFact->createInstanceWithArguments( aFilterName, uno::Sequence < uno::Any >() ), uno::UNO_QUERY );
2206 }catch(const uno::Exception&)
2207 { xLoader.clear(); }
2209 if ( xLoader.is() )
2211 // it happens that xLoader does not support xImporter!
2212 try{
2213 uno::Reference< lang::XComponent > xComp( GetModel(), uno::UNO_QUERY_THROW );
2214 uno::Reference< document::XImporter > xImporter( xLoader, uno::UNO_QUERY_THROW );
2215 xImporter->setTargetDocument( xComp );
2217 uno::Sequence < beans::PropertyValue > lDescriptor;
2218 rMedium.GetItemSet()->Put( SfxStringItem( SID_FILE_NAME, rMedium.GetName() ) );
2219 TransformItems( SID_OPENDOC, *rMedium.GetItemSet(), lDescriptor );
2221 com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue > aArgs ( lDescriptor.getLength() );
2222 com::sun::star::beans::PropertyValue * pNewValue = aArgs.getArray();
2223 const com::sun::star::beans::PropertyValue * pOldValue = lDescriptor.getConstArray();
2224 const OUString sInputStream ( "InputStream" );
2226 sal_Bool bHasInputStream = sal_False;
2227 sal_Bool bHasBaseURL = sal_False;
2228 sal_Int32 i;
2229 sal_Int32 nEnd = lDescriptor.getLength();
2231 for ( i = 0; i < nEnd; i++ )
2233 pNewValue[i] = pOldValue[i];
2234 if ( pOldValue [i].Name == sInputStream )
2235 bHasInputStream = sal_True;
2236 else if ( pOldValue[i].Name == "DocumentBaseURL" )
2237 bHasBaseURL = sal_True;
2240 if ( !bHasInputStream )
2242 aArgs.realloc ( ++nEnd );
2243 aArgs[nEnd-1].Name = sInputStream;
2244 aArgs[nEnd-1].Value <<= com::sun::star::uno::Reference < com::sun::star::io::XInputStream > ( new utl::OSeekableInputStreamWrapper ( *rMedium.GetInStream() ) );
2247 if ( !bHasBaseURL )
2249 aArgs.realloc ( ++nEnd );
2250 aArgs[nEnd-1].Name = OUString( "DocumentBaseURL" );
2251 aArgs[nEnd-1].Value <<= rMedium.GetBaseURL();
2254 if ( bInsert ) {
2255 aArgs.realloc( ++nEnd );
2256 aArgs[nEnd-1].Name = OUString( "InsertMode" );
2257 aArgs[nEnd-1].Value <<= (sal_Bool) sal_True;
2260 // #i119492# During loading, some OLE objects like chart will be set
2261 // modified flag, so needs to reset the flag to false after loading
2262 sal_Bool bRtn = xLoader->filter( aArgs );
2263 uno::Sequence < OUString > aNames = GetEmbeddedObjectContainer().GetObjectNames();
2264 for ( sal_Int32 n = 0; n < aNames.getLength(); ++n )
2266 OUString aName = aNames[n];
2267 uno::Reference < embed::XEmbeddedObject > xObj = GetEmbeddedObjectContainer().GetEmbeddedObject( aName );
2268 OSL_ENSURE( xObj.is(), "An empty entry in the embedded objects list!\n" );
2269 if ( xObj.is() )
2271 sal_Int32 nState = xObj->getCurrentState();
2272 if ( nState == embed::EmbedStates::LOADED || nState == embed::EmbedStates::RUNNING ) // means that the object is not active
2274 uno::Reference< util::XModifiable > xModifiable( xObj->getComponent(), uno::UNO_QUERY );
2275 if ( xModifiable.is() )
2276 xModifiable->setModified(sal_False);
2280 return bRtn;
2282 catch (const packages::zip::ZipIOException&)
2284 SetError( ERRCODE_IO_BROKENPACKAGE, "Badness in the underlying package format." );
2286 catch (const lang::WrappedTargetRuntimeException& rWrapped)
2288 io::WrongFormatException e;
2289 if (rWrapped.TargetException >>= e)
2291 SetError(*new StringErrorInfo(ERRCODE_SFX_FORMAT_ROWCOL,
2292 e.Message, ERRCODE_BUTTON_OK | ERRCODE_MSG_ERROR ), "");
2295 catch(...)
2299 return sal_False;
2302 sal_Bool SfxObjectShell::ExportTo( SfxMedium& rMedium )
2304 OUString aFilterName( rMedium.GetFilter()->GetFilterName() );
2305 uno::Reference< document::XExporter > xExporter;
2308 uno::Reference< lang::XMultiServiceFactory > xMan = ::comphelper::getProcessServiceFactory();
2309 uno::Reference < lang::XMultiServiceFactory > xFilterFact (
2310 xMan->createInstance( "com.sun.star.document.FilterFactory" ), uno::UNO_QUERY );
2312 uno::Sequence < beans::PropertyValue > aProps;
2313 uno::Reference < container::XNameAccess > xFilters ( xFilterFact, uno::UNO_QUERY );
2314 if ( xFilters->hasByName( aFilterName ) )
2315 xFilters->getByName( aFilterName ) >>= aProps;
2317 OUString aFilterImplName;
2318 sal_Int32 nFilterProps = aProps.getLength();
2319 for ( sal_Int32 nFilterProp = 0; nFilterProp<nFilterProps; nFilterProp++ )
2321 const beans::PropertyValue& rFilterProp = aProps[nFilterProp];
2322 if ( rFilterProp.Name.compareToAscii("FilterService") == COMPARE_EQUAL )
2324 rFilterProp.Value >>= aFilterImplName;
2325 break;
2329 if ( !aFilterImplName.isEmpty() )
2331 try{
2332 xExporter = uno::Reference< document::XExporter >
2333 ( xFilterFact->createInstanceWithArguments( aFilterName, uno::Sequence < uno::Any >() ), uno::UNO_QUERY );
2334 }catch(const uno::Exception&)
2335 { xExporter.clear(); }
2339 if ( xExporter.is() )
2341 try{
2342 uno::Reference< lang::XComponent > xComp( GetModel(), uno::UNO_QUERY_THROW );
2343 uno::Reference< document::XFilter > xFilter( xExporter, uno::UNO_QUERY_THROW );
2344 xExporter->setSourceDocument( xComp );
2346 com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue > aOldArgs;
2347 SfxItemSet* pItems = rMedium.GetItemSet();
2348 TransformItems( SID_SAVEASDOC, *pItems, aOldArgs );
2350 const com::sun::star::beans::PropertyValue * pOldValue = aOldArgs.getConstArray();
2351 com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue > aArgs ( aOldArgs.getLength() );
2352 com::sun::star::beans::PropertyValue * pNewValue = aArgs.getArray();
2354 // put in the REAL file name, and copy all PropertyValues
2355 const OUString sOutputStream ( "OutputStream" );
2356 const OUString sStream ( "StreamForOutput" );
2357 sal_Bool bHasOutputStream = sal_False;
2358 sal_Bool bHasStream = sal_False;
2359 sal_Bool bHasBaseURL = sal_False;
2360 sal_Int32 i;
2361 sal_Int32 nEnd = aOldArgs.getLength();
2363 for ( i = 0; i < nEnd; i++ )
2365 pNewValue[i] = pOldValue[i];
2366 if ( pOldValue[i].Name == "FileName" )
2367 pNewValue[i].Value <<= OUString ( rMedium.GetName() );
2368 else if ( pOldValue[i].Name == sOutputStream )
2369 bHasOutputStream = sal_True;
2370 else if ( pOldValue[i].Name == sStream )
2371 bHasStream = sal_True;
2372 else if ( pOldValue[i].Name == "DocumentBaseURL" )
2373 bHasBaseURL = sal_True;
2376 if ( !bHasOutputStream )
2378 aArgs.realloc ( ++nEnd );
2379 aArgs[nEnd-1].Name = sOutputStream;
2380 aArgs[nEnd-1].Value <<= com::sun::star::uno::Reference < com::sun::star::io::XOutputStream > ( new utl::OOutputStreamWrapper ( *rMedium.GetOutStream() ) );
2383 // add stream as well, for OOX export and maybe others
2384 if ( !bHasStream )
2386 aArgs.realloc ( ++nEnd );
2387 aArgs[nEnd-1].Name = sStream;
2388 aArgs[nEnd-1].Value <<= com::sun::star::uno::Reference < com::sun::star::io::XStream > ( new utl::OStreamWrapper ( *rMedium.GetOutStream() ) );
2391 if ( !bHasBaseURL )
2393 aArgs.realloc ( ++nEnd );
2394 aArgs[nEnd-1].Name = OUString( "DocumentBaseURL" );
2395 aArgs[nEnd-1].Value <<= rMedium.GetBaseURL( sal_True );
2398 return xFilter->filter( aArgs );
2399 }catch(const uno::Exception&)
2403 return sal_False;
2406 //-------------------------------------------------------------------------
2408 sal_Bool SfxObjectShell::ConvertTo
2410 SfxMedium& /*rMedium*/ /* <SfxMedium>, which describes the target file
2411 (for example file name, <SfxFilter>,
2412 Open-Modi and so on) */
2415 /* [Description]
2417 This method is called for saving of documents over all filters which are
2418 not SFX_FILTER_OWN or for which no clipboard format has been registered
2419 (thus no storage format that is used). In other words, with this method
2420 it is exported.
2422 Files which are to be opened here should be opened through 'rMedium'
2423 to guarantee the right open modes. Especially if the format is retained
2424 (only possible with SFX_FILTER_SIMULATE or SFX_FILTER_ONW) file which must
2425 be opened STREAM_SHARE_DENYWRITE.
2427 [Return value]
2429 sal_Bool sal_True
2430 The document could be saved.
2432 sal_False
2433 The document could not be saved, an error code is
2434 received by <SvMedium::GetError()const>
2437 [Example]
2439 sal_Bool DocSh::ConvertTo( SfxMedium &rMedium )
2441 SvStreamRef xStream = rMedium.GetOutStream();
2442 if ( xStream.is() )
2444 xStream->SetBufferSize(4096);
2445 *xStream << ...;
2447 rMedium.CloseOutStream(); // opens the InStream automatically
2448 return SVSTREAM_OK == rMedium.GetError();
2450 return sal_False ;
2453 [Cross-references]
2455 <SfxObjectShell::ConvertFrom(SfxMedium&)>
2456 <SFX_FILTER_REGISTRATION>
2460 return sal_False;
2463 //-------------------------------------------------------------------------
2465 sal_Bool SfxObjectShell::DoSave_Impl( const SfxItemSet* pArgs )
2467 SfxMedium* pRetrMedium = GetMedium();
2468 const SfxFilter* pFilter = pRetrMedium->GetFilter();
2470 // copy the original itemset, but remove the "version" item, because pMediumTmp
2471 // is a new medium "from scratch", so no version should be stored into it
2472 SfxItemSet* pSet = new SfxAllItemSet(*pRetrMedium->GetItemSet());
2473 pSet->ClearItem( SID_VERSION );
2474 pSet->ClearItem( SID_DOC_BASEURL );
2476 // copy the version comment and major items for the checkin only
2477 if ( pRetrMedium->IsInCheckIn( ) )
2479 const SfxPoolItem* pMajor = pArgs->GetItem( SID_DOCINFO_MAJOR );
2480 if ( pMajor )
2481 pSet->Put( *pMajor );
2483 const SfxPoolItem* pComments = pArgs->GetItem( SID_DOCINFO_COMMENTS );
2484 if ( pComments )
2485 pSet->Put( *pComments );
2488 // create a medium as a copy; this medium is only for writingm, because it
2489 // uses the same name as the original one writing is done through a copy,
2490 // that will be transferred to the target (of course after calling HandsOff)
2491 SfxMedium* pMediumTmp = new SfxMedium( pRetrMedium->GetName(), pRetrMedium->GetOpenMode(), pFilter, pSet );
2492 pMediumTmp->SetInCheckIn( pRetrMedium->IsInCheckIn( ) );
2493 pMediumTmp->SetLongName( pRetrMedium->GetLongName() );
2494 if ( pMediumTmp->GetErrorCode() != ERRCODE_NONE )
2496 SetError( pMediumTmp->GetError(), OUString( OSL_LOG_PREFIX ) );
2497 delete pMediumTmp;
2498 return sal_False;
2501 // copy version list from "old" medium to target medium, so it can be used on saving
2502 pMediumTmp->TransferVersionList_Impl( *pRetrMedium );
2504 // an interaction handler here can aquire only in case of GUI Saving
2505 // and should be removed after the saving is done
2506 com::sun::star::uno::Reference< XInteractionHandler > xInteract;
2507 SFX_ITEMSET_ARG( pArgs, pxInteractionItem, SfxUnoAnyItem, SID_INTERACTIONHANDLER, sal_False );
2508 if ( pxInteractionItem && ( pxInteractionItem->GetValue() >>= xInteract ) && xInteract.is() )
2509 pMediumTmp->GetItemSet()->Put( SfxUnoAnyItem( SID_INTERACTIONHANDLER, makeAny( xInteract ) ) );
2511 sal_Bool bSaved = sal_False;
2512 if( !GetError() && SaveTo_Impl( *pMediumTmp, pArgs ) )
2514 bSaved = sal_True;
2516 if( pMediumTmp->GetItemSet() )
2518 pMediumTmp->GetItemSet()->ClearItem( SID_INTERACTIONHANDLER );
2519 pMediumTmp->GetItemSet()->ClearItem( SID_PROGRESS_STATUSBAR_CONTROL );
2522 SetError(pMediumTmp->GetErrorCode(), OUString( OSL_LOG_PREFIX ) );
2524 sal_Bool bOpen( sal_False );
2525 bOpen = DoSaveCompleted( pMediumTmp );
2527 DBG_ASSERT(bOpen,"Error handling for DoSaveCompleted not implemented");
2528 (void)bOpen;
2530 else
2532 // transfer error code from medium to objectshell
2533 SetError( pMediumTmp->GetError(), OUString( OSL_LOG_PREFIX ) );
2535 // reconnect to object storage
2536 DoSaveCompleted( 0 );
2538 if( pRetrMedium->GetItemSet() )
2540 pRetrMedium->GetItemSet()->ClearItem( SID_INTERACTIONHANDLER );
2541 pRetrMedium->GetItemSet()->ClearItem( SID_PROGRESS_STATUSBAR_CONTROL );
2544 delete pMediumTmp;
2547 SetModified( !bSaved );
2548 return bSaved;
2551 //-------------------------------------------------------------------------
2553 sal_Bool SfxObjectShell::Save_Impl( const SfxItemSet* pSet )
2555 if ( IsReadOnly() )
2557 SetError( ERRCODE_SFX_DOCUMENTREADONLY, OUString( OSL_LOG_PREFIX ) );
2558 return sal_False;
2561 DBG_CHKTHIS(SfxObjectShell, 0);
2563 pImp->bIsSaving = sal_True;
2564 sal_Bool bSaved = sal_False;
2565 SFX_ITEMSET_ARG( GetMedium()->GetItemSet(), pSalvageItem, SfxStringItem, SID_DOC_SALVAGE, sal_False);
2566 if ( pSalvageItem )
2568 SFX_ITEMSET_ARG( GetMedium()->GetItemSet(), pFilterItem, SfxStringItem, SID_FILTER_NAME, sal_False);
2569 String aFilterName;
2570 const SfxFilter *pFilter = NULL;
2571 if ( pFilterItem )
2572 pFilter = SfxFilterMatcher( OUString::createFromAscii( GetFactory().GetShortName()) ).GetFilter4FilterName( aFilterName );
2574 SfxMedium *pMed = new SfxMedium(
2575 pSalvageItem->GetValue(), STREAM_READWRITE | STREAM_SHARE_DENYWRITE | STREAM_TRUNC, pFilter );
2577 SFX_ITEMSET_ARG( GetMedium()->GetItemSet(), pPasswordItem, SfxStringItem, SID_PASSWORD, sal_False );
2578 if ( pPasswordItem )
2579 pMed->GetItemSet()->Put( *pPasswordItem );
2581 bSaved = DoSaveAs( *pMed );
2582 if ( bSaved )
2583 bSaved = DoSaveCompleted( pMed );
2584 else
2585 delete pMed;
2587 else
2588 bSaved = DoSave_Impl( pSet );
2589 return bSaved;
2592 //-------------------------------------------------------------------------
2594 sal_Bool SfxObjectShell::CommonSaveAs_Impl
2596 const INetURLObject& aURL,
2597 const String& aFilterName,
2598 SfxItemSet* aParams
2601 if( aURL.HasError() )
2603 SetError( ERRCODE_IO_INVALIDPARAMETER, OUString( OSL_LOG_PREFIX ) );
2604 return sal_False;
2607 if ( aURL != INetURLObject( OUString( "private:stream" ) ) )
2609 // Is there already a Document with this name?
2610 SfxObjectShell* pDoc = 0;
2611 for ( SfxObjectShell* pTmp = SfxObjectShell::GetFirst();
2612 pTmp && !pDoc;
2613 pTmp = SfxObjectShell::GetNext(*pTmp) )
2615 if( ( pTmp != this ) && pTmp->GetMedium() )
2617 INetURLObject aCompare( pTmp->GetMedium()->GetName() );
2618 if ( aCompare == aURL )
2619 pDoc = pTmp;
2622 if ( pDoc )
2624 // Then error message: "already opened"
2625 SetError(ERRCODE_SFX_ALREADYOPEN, OUString( OSL_LOG_PREFIX ));
2626 return sal_False;
2630 DBG_ASSERT( aURL.GetProtocol() != INET_PROT_NOT_VALID, "Illegal URL!" );
2631 DBG_ASSERT( aParams->Count() != 0, "Incorrect Parameter");
2633 SFX_ITEMSET_ARG( aParams, pSaveToItem, SfxBoolItem, SID_SAVETO, sal_False );
2634 sal_Bool bSaveTo = pSaveToItem ? pSaveToItem->GetValue() : sal_False;
2636 const SfxFilter* pFilter = GetFactory().GetFilterContainer()->GetFilter4FilterName( aFilterName );
2637 if ( !pFilter
2638 || !pFilter->CanExport()
2639 || (!bSaveTo && !pFilter->CanImport()) )
2641 SetError( ERRCODE_IO_INVALIDPARAMETER, OUString( OSL_LOG_PREFIX ) );
2642 return sal_False;
2645 SFX_ITEMSET_ARG( aParams, pCopyStreamItem, SfxBoolItem, SID_COPY_STREAM_IF_POSSIBLE, sal_False );
2646 if ( bSaveTo && pCopyStreamItem && pCopyStreamItem->GetValue() && !IsModified() )
2648 if ( pMedium->TryDirectTransfer( aURL.GetMainURL( INetURLObject::NO_DECODE ), *aParams ) )
2649 return sal_True;
2651 aParams->ClearItem( SID_COPY_STREAM_IF_POSSIBLE );
2653 pImp->bPasswd = aParams && SFX_ITEM_SET == aParams->GetItemState(SID_PASSWORD);
2655 SfxMedium *pActMed = GetMedium();
2656 const INetURLObject aActName(pActMed->GetName());
2658 sal_Bool bWasReadonly = IsReadOnly();
2660 if ( aURL == aActName && aURL != INetURLObject( OUString("private:stream") )
2661 && IsReadOnly() )
2663 SetError(ERRCODE_SFX_DOCUMENTREADONLY, OUString( OSL_LOG_PREFIX ));
2664 return sal_False;
2667 if( SFX_ITEM_SET != aParams->GetItemState(SID_UNPACK) && SvtSaveOptions().IsSaveUnpacked() )
2668 aParams->Put( SfxBoolItem( SID_UNPACK, sal_False ) );
2670 OUString aTempFileURL;
2671 if ( IsDocShared() )
2672 aTempFileURL = pMedium->GetURLObject().GetMainURL( INetURLObject::NO_DECODE );
2674 if ( PreDoSaveAs_Impl(aURL.GetMainURL( INetURLObject::NO_DECODE ),aFilterName,aParams))
2676 // Update Data on media
2677 SfxItemSet *pSet = GetMedium()->GetItemSet();
2678 pSet->ClearItem( SID_INTERACTIONHANDLER );
2679 pSet->ClearItem( SID_PROGRESS_STATUSBAR_CONTROL );
2680 pSet->ClearItem( SID_STANDARD_DIR );
2681 pSet->ClearItem( SID_PATH );
2683 if ( !bSaveTo )
2685 pSet->ClearItem( SID_REFERER );
2686 pSet->ClearItem( SID_POSTDATA );
2687 pSet->ClearItem( SID_TEMPLATE );
2688 pSet->ClearItem( SID_DOC_READONLY );
2689 pSet->ClearItem( SID_CONTENTTYPE );
2690 pSet->ClearItem( SID_CHARSET );
2691 pSet->ClearItem( SID_FILTER_NAME );
2692 pSet->ClearItem( SID_OPTIONS );
2693 pSet->ClearItem( SID_VERSION );
2694 pSet->ClearItem( SID_EDITDOC );
2695 pSet->ClearItem( SID_OVERWRITE );
2696 pSet->ClearItem( SID_DEFAULTFILEPATH );
2697 pSet->ClearItem( SID_DEFAULTFILENAME );
2699 SFX_ITEMSET_GET( (*aParams), pFilterItem, SfxStringItem, SID_FILTER_NAME, sal_False );
2700 if ( pFilterItem )
2701 pSet->Put( *pFilterItem );
2703 SFX_ITEMSET_GET( (*aParams), pOptionsItem, SfxStringItem, SID_OPTIONS, sal_False );
2704 if ( pOptionsItem )
2705 pSet->Put( *pOptionsItem );
2707 SFX_ITEMSET_GET( (*aParams), pFilterOptItem, SfxStringItem, SID_FILE_FILTEROPTIONS, sal_False );
2708 if ( pFilterOptItem )
2709 pSet->Put( *pFilterOptItem );
2711 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
2712 if ( IsDocShared() && !aTempFileURL.isEmpty() )
2714 // this is a shared document that has to be disconnected from the old location
2715 FreeSharedFile( aTempFileURL );
2717 if ( pFilter->IsOwnFormat()
2718 && pFilter->UsesStorage()
2719 && pFilter->GetVersion() >= SOFFICE_FILEFORMAT_60 )
2721 // the target format is the own format
2722 // the target document must be shared
2723 SwitchToShared( sal_True, sal_False );
2726 #endif
2729 if ( bWasReadonly && !bSaveTo )
2730 Broadcast( SfxSimpleHint(SFX_HINT_MODECHANGED) );
2732 return sal_True;
2734 else
2735 return sal_False;
2738 //-------------------------------------------------------------------------
2740 sal_Bool SfxObjectShell::PreDoSaveAs_Impl
2742 const String& rFileName,
2743 const String& aFilterName,
2744 SfxItemSet* pParams
2747 // copy all items stored in the itemset of the current medium
2748 SfxAllItemSet* pMergedParams = new SfxAllItemSet( *pMedium->GetItemSet() );
2750 // in "SaveAs" title and password will be cleared ( maybe the new itemset contains new values, otherwise they will be empty )
2751 pMergedParams->ClearItem( SID_ENCRYPTIONDATA );
2752 pMergedParams->ClearItem( SID_PASSWORD );
2753 // #i119366# - As the SID_ENCRYPTIONDATA and SID_PASSWORD are using for setting password together, we need to clear them both.
2754 // Also, ( maybe the new itemset contains new values, otherwise they will be empty )
2755 pMergedParams->ClearItem( SID_ENCRYPTIONDATA );
2756 pMergedParams->ClearItem( SID_DOCINFO_TITLE );
2758 pMergedParams->ClearItem( SID_INPUTSTREAM );
2759 pMergedParams->ClearItem( SID_STREAM );
2760 pMergedParams->ClearItem( SID_CONTENT );
2761 pMergedParams->ClearItem( SID_DOC_READONLY );
2762 pMergedParams->ClearItem( SID_DOC_BASEURL );
2764 pMergedParams->ClearItem( SID_REPAIRPACKAGE );
2766 // "SaveAs" will never store any version information - it's a complete new file !
2767 pMergedParams->ClearItem( SID_VERSION );
2769 // merge the new parameters into the copy
2770 // all values present in both itemsets will be overwritten by the new parameters
2771 if( pParams )
2772 pMergedParams->Put( *pParams );
2774 #ifdef DBG_UTIL
2775 if ( pMergedParams->GetItemState( SID_DOC_SALVAGE) >= SFX_ITEM_SET )
2776 OSL_FAIL("Salvage item present in Itemset, check the parameters!");
2777 #endif
2779 // should be unneccessary - too hot to handle!
2780 pMergedParams->ClearItem( SID_DOC_SALVAGE );
2782 // take over the new merged itemset
2783 pParams = pMergedParams;
2785 // create a medium for the target URL
2786 SfxMedium *pNewFile = new SfxMedium( rFileName, STREAM_READWRITE | STREAM_SHARE_DENYWRITE | STREAM_TRUNC, 0, pParams );
2788 // set filter; if no filter is given, take the default filter of the factory
2789 if ( aFilterName.Len() )
2790 pNewFile->SetFilter( GetFactory().GetFilterContainer()->GetFilter4FilterName( aFilterName ) );
2791 else
2792 pNewFile->SetFilter( GetFactory().GetFilterContainer()->GetAnyFilter( SFX_FILTER_IMPORT | SFX_FILTER_EXPORT ) );
2794 if ( pNewFile->GetErrorCode() != ERRCODE_NONE )
2796 // creating temporary file failed ( f.e. floppy disk not inserted! )
2797 SetError( pNewFile->GetError(), OUString( OSL_LOG_PREFIX ) );
2798 delete pNewFile;
2799 return sal_False;
2802 // check if a "SaveTo" is wanted, no "SaveAs"
2803 SFX_ITEMSET_ARG( pParams, pSaveToItem, SfxBoolItem, SID_SAVETO, sal_False );
2804 sal_Bool bCopyTo = GetCreateMode() == SFX_CREATE_MODE_EMBEDDED || (pSaveToItem && pSaveToItem->GetValue());
2806 // distinguish between "Save" and "SaveAs"
2807 pImp->bIsSaving = sal_False;
2809 // copy version list from "old" medium to target medium, so it can be used on saving
2810 if ( pImp->bPreserveVersions )
2811 pNewFile->TransferVersionList_Impl( *pMedium );
2813 // Save the document ( first as temporary file, then transfer to the target URL by committing the medium )
2814 sal_Bool bOk = sal_False;
2815 if ( !pNewFile->GetErrorCode() && SaveTo_Impl( *pNewFile, NULL ) )
2817 bOk = sal_True;
2819 // transfer a possible error from the medium to the document
2820 SetError( pNewFile->GetErrorCode(), OUString( OSL_LOG_PREFIX ) );
2822 // notify the document that saving was done successfully
2823 if ( !bCopyTo )
2825 bOk = DoSaveCompleted( pNewFile );
2827 else
2828 bOk = DoSaveCompleted(0);
2830 if( bOk )
2832 if( !bCopyTo )
2833 SetModified( sal_False );
2835 else
2837 // TODO/LATER: the code below must be dead since the storage commit makes all the stuff
2838 // and the DoSaveCompleted call should not be able to fail in general
2840 DBG_ASSERT( !bCopyTo, "Error while reconnecting to medium, can't be handled!");
2841 SetError( pNewFile->GetErrorCode(), OUString( OSL_LOG_PREFIX ) );
2843 if ( !bCopyTo )
2845 // reconnect to the old medium
2846 sal_Bool bRet( sal_False );
2847 bRet = DoSaveCompleted( pMedium );
2848 DBG_ASSERT( bRet, "Error in DoSaveCompleted, can't be handled!");
2849 (void)bRet;
2852 // TODO/LATER: disconnect the new file from the storage for the case when pure saving is done
2853 // if storing has corrupted the file, probably it must be restored either here or
2854 // by the storage
2855 DELETEZ( pNewFile );
2858 else
2860 SetError( pNewFile->GetErrorCode(), OUString( OSL_LOG_PREFIX ) );
2862 // reconnect to the old storage
2863 DoSaveCompleted( 0 );
2865 DELETEZ( pNewFile );
2868 if ( bCopyTo )
2869 DELETEZ( pNewFile );
2870 else if( !bOk )
2871 SetModified( sal_True );
2873 return bOk;
2876 //------------------------------------------------------------------------
2878 sal_Bool SfxObjectShell::LoadFrom( SfxMedium& /*rMedium*/ )
2880 OSL_FAIL( "Base implementation, must not be called in general!" );
2881 return sal_True;
2884 //-------------------------------------------------------------------------
2885 sal_Bool SfxObjectShell::IsInformationLost()
2887 Sequence< PropertyValue > aProps = GetModel()->getArgs();
2888 OUString aFilterName;
2889 OUString aPreusedFilterName;
2890 for ( sal_Int32 nInd = 0; nInd < aProps.getLength(); nInd++ )
2892 if ( aProps[nInd].Name == "FilterName" )
2893 aProps[nInd].Value >>= aFilterName;
2894 else if ( aProps[nInd].Name == "PreusedFilterName" )
2895 aProps[nInd].Value >>= aPreusedFilterName;
2898 // if current filter can lead to information loss and it was used
2899 // for the latest store then the user should be asked to store in own format
2900 if ( !aFilterName.isEmpty() && aFilterName.equals( aPreusedFilterName ) )
2902 const SfxFilter *pFilt = GetMedium()->GetFilter();
2903 DBG_ASSERT( pFilt && aFilterName.equals( pFilt->GetName() ), "MediaDescriptor contains wrong filter!\n" );
2904 return ( pFilt && pFilt->IsAlienFormat() );
2907 return sal_False;
2910 //-------------------------------------------------------------------------
2911 sal_Bool SfxObjectShell::CanReload_Impl()
2913 /* [Description]
2915 Internal method for determining whether a reload of the document
2916 (as RevertToSaved or last known version) is possible.
2920 return pMedium && HasName() && !IsInModalMode() && !pImp->bForbidReload;
2923 //-------------------------------------------------------------------------
2925 sal_uInt16 SfxObjectShell::GetHiddenInformationState( sal_uInt16 nStates )
2927 sal_uInt16 nState = 0;
2928 if ( nStates & HIDDENINFORMATION_DOCUMENTVERSIONS )
2930 if ( GetMedium()->GetVersionList().getLength() )
2931 nState |= HIDDENINFORMATION_DOCUMENTVERSIONS;
2934 return nState;
2937 sal_Int16 SfxObjectShell::QueryHiddenInformation( HiddenWarningFact eFact, Window* pParent )
2939 sal_Int16 nRet = RET_YES;
2940 sal_uInt16 nResId = sal_uInt16();
2941 SvtSecurityOptions::EOption eOption = SvtSecurityOptions::EOption();
2943 switch ( eFact )
2945 case WhenSaving :
2947 nResId = STR_HIDDENINFO_CONTINUE_SAVING;
2948 eOption = SvtSecurityOptions::E_DOCWARN_SAVEORSEND;
2949 break;
2951 case WhenPrinting :
2953 nResId = STR_HIDDENINFO_CONTINUE_PRINTING;
2954 eOption = SvtSecurityOptions::E_DOCWARN_PRINT;
2955 break;
2957 case WhenSigning :
2959 nResId = STR_HIDDENINFO_CONTINUE_SIGNING;
2960 eOption = SvtSecurityOptions::E_DOCWARN_SIGNING;
2961 break;
2963 case WhenCreatingPDF :
2965 nResId = STR_HIDDENINFO_CONTINUE_CREATEPDF;
2966 eOption = SvtSecurityOptions::E_DOCWARN_CREATEPDF;
2967 break;
2969 default:
2970 assert(false); // this cannot happen
2973 if ( SvtSecurityOptions().IsOptionSet( eOption ) )
2975 String sMessage( SfxResId(STR_HIDDENINFO_CONTAINS).toString() );
2976 sal_uInt16 nWantedStates = HIDDENINFORMATION_RECORDEDCHANGES | HIDDENINFORMATION_NOTES;
2977 if ( eFact != WhenPrinting )
2978 nWantedStates |= HIDDENINFORMATION_DOCUMENTVERSIONS;
2979 sal_uInt16 nStates = GetHiddenInformationState( nWantedStates );
2980 bool bWarning = false;
2982 if ( ( nStates & HIDDENINFORMATION_RECORDEDCHANGES ) == HIDDENINFORMATION_RECORDEDCHANGES )
2984 sMessage += SfxResId(STR_HIDDENINFO_RECORDCHANGES).toString();
2985 sMessage += '\n';
2986 bWarning = true;
2988 if ( ( nStates & HIDDENINFORMATION_NOTES ) == HIDDENINFORMATION_NOTES )
2990 sMessage += SfxResId(STR_HIDDENINFO_NOTES).toString();
2991 sMessage += '\n';
2992 bWarning = true;
2994 if ( ( nStates & HIDDENINFORMATION_DOCUMENTVERSIONS ) == HIDDENINFORMATION_DOCUMENTVERSIONS )
2996 sMessage += SfxResId(STR_HIDDENINFO_DOCVERSIONS).toString();
2997 sMessage += '\n';
2998 bWarning = true;
3001 if ( bWarning )
3003 sMessage += '\n';
3004 sMessage += SfxResId(nResId).toString();
3005 WarningBox aWBox( pParent, WB_YES_NO | WB_DEF_NO, sMessage );
3006 nRet = aWBox.Execute();
3010 return nRet;
3013 sal_Bool SfxObjectShell::HasSecurityOptOpenReadOnly() const
3015 return sal_True;
3018 sal_Bool SfxObjectShell::IsSecurityOptOpenReadOnly() const
3020 return IsLoadReadonly();
3023 void SfxObjectShell::SetSecurityOptOpenReadOnly( sal_Bool _b )
3025 SetLoadReadonly( _b );
3028 sal_Bool SfxObjectShell::LoadOwnFormat( SfxMedium& rMedium )
3030 RTL_LOGFILE_PRODUCT_CONTEXT( aLog, "PERFORMANCE SfxObjectShell::LoadOwnFormat" );
3031 if( RTL_LOGFILE_HASLOGFILE() )
3033 OString aString(
3034 OUStringToOString(rMedium.GetName(), RTL_TEXTENCODING_ASCII_US));
3035 RTL_LOGFILE_PRODUCT_CONTEXT_TRACE1(aLog, "loading \"%s\"", aString.getStr());
3038 uno::Reference< embed::XStorage > xStorage = rMedium.GetStorage();
3039 if ( xStorage.is() )
3041 // Password
3042 SFX_ITEMSET_ARG( rMedium.GetItemSet(), pPasswdItem, SfxStringItem, SID_PASSWORD, sal_False );
3043 if ( pPasswdItem || ERRCODE_IO_ABORT != CheckPasswd_Impl( this, SFX_APP()->GetPool(), pMedium ) )
3045 uno::Sequence< beans::NamedValue > aEncryptionData;
3046 if ( GetEncryptionData_Impl(pMedium->GetItemSet(), aEncryptionData) )
3050 // the following code must throw an exception in case of failure
3051 ::comphelper::OStorageHelper::SetCommonStorageEncryptionData( xStorage, aEncryptionData );
3053 catch( uno::Exception& )
3055 // TODO/LATER: handle the error code
3059 // load document
3060 return Load( rMedium );
3062 return sal_False;
3064 else
3065 return sal_False;
3068 sal_Bool SfxObjectShell::SaveAsOwnFormat( SfxMedium& rMedium )
3070 uno::Reference< embed::XStorage > xStorage = rMedium.GetStorage();
3071 if( xStorage.is() )
3073 sal_Int32 nVersion = rMedium.GetFilter()->GetVersion();
3075 // OASIS templates have own mediatypes ( SO7 also actually, but it is to late to use them here )
3076 sal_Bool bTemplate = ( rMedium.GetFilter()->IsOwnTemplateFormat() && nVersion > SOFFICE_FILEFORMAT_60 );
3078 const SfxFilter* pFilter = rMedium.GetFilter();
3079 bool bChart = false;
3080 if(pFilter->GetName() == OUString("chart8"))
3081 bChart = true;
3083 SetupStorage( xStorage, nVersion, bTemplate, bChart );
3084 #ifndef DISABLE_SCRIPTING
3085 if ( HasBasic() )
3087 // Initialize Basic
3088 GetBasicManager();
3090 // Save dialog/script container
3091 pImp->pBasicManager->storeLibrariesToStorage( xStorage );
3093 #endif
3094 return SaveAs( rMedium );
3096 else return sal_False;
3099 uno::Reference< embed::XStorage > SfxObjectShell::GetStorage()
3101 if ( !pImp->m_xDocStorage.is() )
3103 OSL_ENSURE( pImp->m_bCreateTempStor, "The storage must exist already!\n" );
3104 try {
3105 // no notification is required the storage is set the first time
3106 pImp->m_xDocStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
3107 OSL_ENSURE( pImp->m_xDocStorage.is(), "The method must either return storage or throw an exception!" );
3109 SetupStorage( pImp->m_xDocStorage, SOFFICE_FILEFORMAT_CURRENT, sal_False, false );
3110 pImp->m_bCreateTempStor = sal_False;
3111 SFX_APP()->NotifyEvent( SfxEventHint( SFX_EVENT_STORAGECHANGED, GlobalEventConfig::GetEventName(STR_EVENT_STORAGECHANGED), this ) );
3113 catch( uno::Exception& )
3115 // TODO/LATER: error handling?
3116 DBG_UNHANDLED_EXCEPTION();
3120 OSL_ENSURE( pImp->m_xDocStorage.is(), "The document storage must be created!" );
3121 return pImp->m_xDocStorage;
3125 sal_Bool SfxObjectShell::SaveChildren( sal_Bool bObjectsOnly )
3127 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SaveChildren" );
3129 sal_Bool bResult = sal_True;
3130 if ( pImp->mpObjectContainer )
3132 sal_Bool bOasis = ( SotStorage::GetVersion( GetStorage() ) > SOFFICE_FILEFORMAT_60 );
3133 GetEmbeddedObjectContainer().StoreChildren(bOasis,bObjectsOnly);
3136 return bResult;
3139 sal_Bool SfxObjectShell::SaveAsChildren( SfxMedium& rMedium )
3141 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SaveAsChildren" );
3143 sal_Bool bResult = sal_True;
3145 uno::Reference < embed::XStorage > xStorage = rMedium.GetStorage();
3146 if ( !xStorage.is() )
3147 return sal_False;
3149 if ( xStorage == GetStorage() )
3150 return SaveChildren();
3152 sal_Bool bOasis = sal_True;
3153 if ( pImp->mpObjectContainer )
3155 bOasis = ( SotStorage::GetVersion( xStorage ) > SOFFICE_FILEFORMAT_60 );
3156 GetEmbeddedObjectContainer().StoreAsChildren(bOasis,SFX_CREATE_MODE_EMBEDDED == eCreateMode,xStorage);
3159 if ( bResult )
3160 bResult = CopyStoragesOfUnknownMediaType( GetStorage(), xStorage );
3162 return bResult;
3165 sal_Bool SfxObjectShell::SaveCompletedChildren( sal_Bool bSuccess )
3167 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SaveCompletedChildren" );
3169 sal_Bool bResult = sal_True;
3171 if ( pImp->mpObjectContainer )
3173 uno::Sequence < OUString > aNames = GetEmbeddedObjectContainer().GetObjectNames();
3174 for ( sal_Int32 n=0; n<aNames.getLength(); n++ )
3176 uno::Reference < embed::XEmbeddedObject > xObj = GetEmbeddedObjectContainer().GetEmbeddedObject( aNames[n] );
3177 OSL_ENSURE( xObj.is(), "An empty entry in the embedded objects list!\n" );
3178 if ( xObj.is() )
3180 uno::Reference< embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
3181 if ( xPersist.is() )
3185 xPersist->saveCompleted( bSuccess );
3187 catch( uno::Exception& )
3189 // TODO/LATER: error handling
3190 bResult = sal_False;
3191 break;
3198 return bResult;
3201 sal_Bool SfxObjectShell::SwitchChildrenPersistance( const uno::Reference< embed::XStorage >& xStorage,
3202 sal_Bool bForceNonModified )
3204 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SwitchChildrenPersistence" );
3206 if ( !xStorage.is() )
3208 // TODO/LATER: error handling
3209 return sal_False;
3212 sal_Bool bResult = sal_True;
3214 if ( pImp->mpObjectContainer )
3215 pImp->mpObjectContainer->SetPersistentEntries(xStorage,bForceNonModified);
3217 return bResult;
3220 // Never call this method directly, always use the DoSaveCompleted call
3221 sal_Bool SfxObjectShell::SaveCompleted( const uno::Reference< embed::XStorage >& xStorage )
3223 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SaveCompleted" );
3225 sal_Bool bResult = sal_False;
3226 sal_Bool bSendNotification = sal_False;
3227 uno::Reference< embed::XStorage > xOldStorageHolder;
3229 #ifdef DBG_UTIL
3230 // check for wrong creation of object container
3231 sal_Bool bHasContainer = ( pImp->mpObjectContainer != 0 );
3232 #endif
3234 if ( !xStorage.is() || xStorage == GetStorage() )
3236 // no persistence change
3237 bResult = SaveCompletedChildren( sal_False );
3239 else
3241 if ( pImp->mpObjectContainer )
3242 GetEmbeddedObjectContainer().SwitchPersistence( xStorage );
3244 bResult = SwitchChildrenPersistance( xStorage, sal_True );
3247 if ( bResult )
3249 if ( xStorage.is() && pImp->m_xDocStorage != xStorage )
3251 // make sure that until the storage is assigned the object
3252 // container is not created by accident!
3253 DBG_ASSERT( bHasContainer == (pImp->mpObjectContainer != 0), "Wrong storage in object container!" );
3254 xOldStorageHolder = pImp->m_xDocStorage;
3255 pImp->m_xDocStorage = xStorage;
3256 bSendNotification = sal_True;
3258 if ( IsEnableSetModified() )
3259 SetModified( sal_False );
3262 else
3264 if ( pImp->mpObjectContainer )
3265 GetEmbeddedObjectContainer().SwitchPersistence( pImp->m_xDocStorage );
3267 // let already successfully connected objects be switched back
3268 SwitchChildrenPersistance( pImp->m_xDocStorage, sal_True );
3271 if ( bSendNotification )
3273 SFX_APP()->NotifyEvent( SfxEventHint( SFX_EVENT_STORAGECHANGED, GlobalEventConfig::GetEventName(STR_EVENT_STORAGECHANGED), this ) );
3276 return bResult;
3279 #if OSL_DEBUG_LEVEL > 0
3280 sal_Bool StoragesOfUnknownMediaTypeAreCopied_Impl( const uno::Reference< embed::XStorage >& xSource,
3281 const uno::Reference< embed::XStorage >& xTarget )
3283 OSL_ENSURE( xSource.is() && xTarget.is(), "Source and/or target storages are not available!\n" );
3284 if ( !xSource.is() || !xTarget.is() || xSource == xTarget )
3285 return sal_True;
3289 uno::Sequence< OUString > aSubElements = xSource->getElementNames();
3290 for ( sal_Int32 nInd = 0; nInd < aSubElements.getLength(); nInd++ )
3292 if ( xSource->isStorageElement( aSubElements[nInd] ) )
3294 OUString aMediaType;
3295 OUString aMediaTypePropName( "MediaType" );
3296 sal_Bool bGotMediaType = sal_False;
3300 uno::Reference< embed::XOptimizedStorage > xOptStorage( xSource, uno::UNO_QUERY_THROW );
3301 bGotMediaType =
3302 ( xOptStorage->getElementPropertyValue( aSubElements[nInd], aMediaTypePropName ) >>= aMediaType );
3304 catch( uno::Exception& )
3307 if ( !bGotMediaType )
3309 uno::Reference< embed::XStorage > xSubStorage;
3310 try {
3311 xSubStorage = xSource->openStorageElement( aSubElements[nInd], embed::ElementModes::READ );
3312 } catch( uno::Exception& )
3315 if ( !xSubStorage.is() )
3317 xSubStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
3318 xSource->copyStorageElementLastCommitTo( aSubElements[nInd], xSubStorage );
3321 uno::Reference< beans::XPropertySet > xProps( xSubStorage, uno::UNO_QUERY_THROW );
3322 bGotMediaType = ( xProps->getPropertyValue( aMediaTypePropName ) >>= aMediaType );
3325 // TODO/LATER: there should be a way to detect whether an object with such a MediaType can exist
3326 // probably it should be placed in the MimeType-ClassID table or in standalone table
3327 if ( !aMediaType.isEmpty()
3328 && aMediaType.compareToAscii( "application/vnd.sun.star.oleobject" ) != COMPARE_EQUAL )
3330 ::com::sun::star::datatransfer::DataFlavor aDataFlavor;
3331 aDataFlavor.MimeType = aMediaType;
3332 sal_uInt32 nFormat = SotExchange::GetFormat( aDataFlavor );
3334 switch ( nFormat )
3336 case SOT_FORMATSTR_ID_STARWRITER_60 :
3337 case SOT_FORMATSTR_ID_STARWRITERWEB_60 :
3338 case SOT_FORMATSTR_ID_STARWRITERGLOB_60 :
3339 case SOT_FORMATSTR_ID_STARDRAW_60 :
3340 case SOT_FORMATSTR_ID_STARIMPRESS_60 :
3341 case SOT_FORMATSTR_ID_STARCALC_60 :
3342 case SOT_FORMATSTR_ID_STARCHART_60 :
3343 case SOT_FORMATSTR_ID_STARMATH_60 :
3344 case SOT_FORMATSTR_ID_STARWRITER_8:
3345 case SOT_FORMATSTR_ID_STARWRITERWEB_8:
3346 case SOT_FORMATSTR_ID_STARWRITERGLOB_8:
3347 case SOT_FORMATSTR_ID_STARDRAW_8:
3348 case SOT_FORMATSTR_ID_STARIMPRESS_8:
3349 case SOT_FORMATSTR_ID_STARCALC_8:
3350 case SOT_FORMATSTR_ID_STARCHART_8:
3351 case SOT_FORMATSTR_ID_STARMATH_8:
3352 break;
3354 default:
3356 if ( !xTarget->hasByName( aSubElements[nInd] ) )
3357 return sal_False;
3364 catch( uno::Exception& )
3366 OSL_FAIL( "Cant check storage consistency!\n" );
3369 return sal_True;
3371 #endif
3373 sal_Bool SfxObjectShell::SwitchPersistance( const uno::Reference< embed::XStorage >& xStorage )
3375 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SwitchPersistance" );
3377 sal_Bool bResult = sal_False;
3378 #ifdef DBG_UTIL
3379 // check for wrong creation of object container
3380 sal_Bool bHasContainer = ( pImp->mpObjectContainer != 0 );
3381 #endif
3382 if ( xStorage.is() )
3384 if ( pImp->mpObjectContainer )
3385 GetEmbeddedObjectContainer().SwitchPersistence( xStorage );
3386 bResult = SwitchChildrenPersistance( xStorage );
3388 // TODO/LATER: substorages that have unknown mimetypes probably should be copied to the target storage here
3389 OSL_ENSURE( StoragesOfUnknownMediaTypeAreCopied_Impl( pImp->m_xDocStorage, xStorage ),
3390 "Some of substorages with unknown mimetypes is lost!" );
3393 if ( bResult )
3395 // make sure that until the storage is assigned the object container is not created by accident!
3396 DBG_ASSERT( bHasContainer == (pImp->mpObjectContainer != 0), "Wrong storage in object container!" );
3397 if ( pImp->m_xDocStorage != xStorage )
3398 DoSaveCompleted( new SfxMedium( xStorage, GetMedium()->GetBaseURL() ) );
3400 if ( IsEnableSetModified() )
3401 SetModified( sal_True ); // ???
3404 return bResult;
3407 sal_Bool SfxObjectShell::CopyStoragesOfUnknownMediaType( const uno::Reference< embed::XStorage >& xSource,
3408 const uno::Reference< embed::XStorage >& xTarget )
3410 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::CopyStoragesOfUnknownMediaType" );
3412 // This method does not commit the target storage and should not do it
3413 sal_Bool bResult = sal_True;
3417 uno::Sequence< OUString > aSubElements = xSource->getElementNames();
3418 for ( sal_Int32 nInd = 0; nInd < aSubElements.getLength(); nInd++ )
3420 if ( aSubElements[nInd] == "Configurations" )
3422 // The workaround for compatibility with SO7, "Configurations" substorage must be preserved
3423 if ( xSource->isStorageElement( aSubElements[nInd] ) )
3425 OSL_ENSURE( !xTarget->hasByName( aSubElements[nInd] ),
3426 "The target storage is an output storage, the element should not exist in the target!\n" );
3428 xSource->copyElementTo( aSubElements[nInd], xTarget, aSubElements[nInd] );
3431 else if ( xSource->isStorageElement( aSubElements[nInd] ) )
3433 OUString aMediaType;
3434 OUString aMediaTypePropName( "MediaType" );
3435 sal_Bool bGotMediaType = sal_False;
3439 uno::Reference< embed::XOptimizedStorage > xOptStorage( xSource, uno::UNO_QUERY_THROW );
3440 bGotMediaType =
3441 ( xOptStorage->getElementPropertyValue( aSubElements[nInd], aMediaTypePropName ) >>= aMediaType );
3443 catch( uno::Exception& )
3446 if ( !bGotMediaType )
3448 uno::Reference< embed::XStorage > xSubStorage;
3449 try {
3450 xSubStorage = xSource->openStorageElement( aSubElements[nInd], embed::ElementModes::READ );
3451 } catch( uno::Exception& )
3454 if ( !xSubStorage.is() )
3456 // TODO/LATER: as optimization in future a substorage of target storage could be used
3457 // instead of the temporary storage; this substorage should be removed later
3458 // if the MimeType is wrong
3459 xSubStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
3460 xSource->copyStorageElementLastCommitTo( aSubElements[nInd], xSubStorage );
3463 uno::Reference< beans::XPropertySet > xProps( xSubStorage, uno::UNO_QUERY_THROW );
3464 bGotMediaType = ( xProps->getPropertyValue( aMediaTypePropName ) >>= aMediaType );
3467 // TODO/LATER: there should be a way to detect whether an object with such a MediaType can exist
3468 // probably it should be placed in the MimeType-ClassID table or in standalone table
3469 if ( !aMediaType.isEmpty()
3470 && aMediaType.compareToAscii( "application/vnd.sun.star.oleobject" ) != COMPARE_EQUAL )
3472 ::com::sun::star::datatransfer::DataFlavor aDataFlavor;
3473 aDataFlavor.MimeType = aMediaType;
3474 sal_uInt32 nFormat = SotExchange::GetFormat( aDataFlavor );
3476 switch ( nFormat )
3478 case SOT_FORMATSTR_ID_STARWRITER_60 :
3479 case SOT_FORMATSTR_ID_STARWRITERWEB_60 :
3480 case SOT_FORMATSTR_ID_STARWRITERGLOB_60 :
3481 case SOT_FORMATSTR_ID_STARDRAW_60 :
3482 case SOT_FORMATSTR_ID_STARIMPRESS_60 :
3483 case SOT_FORMATSTR_ID_STARCALC_60 :
3484 case SOT_FORMATSTR_ID_STARCHART_60 :
3485 case SOT_FORMATSTR_ID_STARMATH_60 :
3486 case SOT_FORMATSTR_ID_STARWRITER_8:
3487 case SOT_FORMATSTR_ID_STARWRITERWEB_8:
3488 case SOT_FORMATSTR_ID_STARWRITERGLOB_8:
3489 case SOT_FORMATSTR_ID_STARDRAW_8:
3490 case SOT_FORMATSTR_ID_STARIMPRESS_8:
3491 case SOT_FORMATSTR_ID_STARCALC_8:
3492 case SOT_FORMATSTR_ID_STARCHART_8:
3493 case SOT_FORMATSTR_ID_STARMATH_8:
3494 break;
3496 default:
3498 OSL_ENSURE( aSubElements[nInd] == "Configurations2" || !xTarget->hasByName( aSubElements[nInd] ),
3499 "The target storage is an output storage, the element should not exist in the target!\n" );
3501 if ( !xTarget->hasByName( aSubElements[nInd] ) )
3503 xSource->copyElementTo( aSubElements[nInd], xTarget, aSubElements[nInd] );
3511 catch( uno::Exception& )
3513 bResult = sal_False;
3514 // TODO/LATER: a specific error could be provided
3517 return bResult;
3520 sal_Bool SfxObjectShell::GenerateAndStoreThumbnail( sal_Bool bEncrypted,
3521 sal_Bool bSigned,
3522 sal_Bool bIsTemplate,
3523 const uno::Reference< embed::XStorage >& xStor )
3525 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::GenerateAndStoreThumbnail" );
3527 sal_Bool bResult = sal_False;
3529 try {
3530 uno::Reference< embed::XStorage > xThumbnailStor =
3531 xStor->openStorageElement( OUString("Thumbnails"),
3532 embed::ElementModes::READWRITE );
3533 if ( xThumbnailStor.is() )
3535 uno::Reference< io::XStream > xStream = xThumbnailStor->openStreamElement(
3536 OUString("thumbnail.png"),
3537 embed::ElementModes::READWRITE );
3539 if ( xStream.is() && WriteThumbnail( bEncrypted, bSigned, bIsTemplate, xStream ) )
3541 uno::Reference< embed::XTransactedObject > xTransact( xThumbnailStor, uno::UNO_QUERY_THROW );
3542 xTransact->commit();
3543 bResult = sal_True;
3547 catch( uno::Exception& )
3551 return bResult;
3554 sal_Bool SfxObjectShell::WriteThumbnail( sal_Bool bEncrypted,
3555 sal_Bool bSigned,
3556 sal_Bool bIsTemplate,
3557 const uno::Reference< io::XStream >& xStream )
3559 sal_Bool bResult = sal_False;
3561 if ( xStream.is() )
3563 try {
3564 uno::Reference< io::XTruncate > xTruncate( xStream->getOutputStream(), uno::UNO_QUERY_THROW );
3565 xTruncate->truncate();
3567 uno::Reference < beans::XPropertySet > xSet( xStream, uno::UNO_QUERY );
3568 if ( xSet.is() )
3569 xSet->setPropertyValue( OUString("MediaType"),
3570 uno::makeAny( OUString("image/png") ) );
3571 if ( bEncrypted )
3573 sal_uInt16 nResID = GraphicHelper::getThumbnailReplacementIDByFactoryName_Impl(
3574 OUString::createFromAscii( GetFactory().GetShortName() ),
3575 bIsTemplate );
3576 if ( nResID )
3578 if ( !bSigned )
3580 bResult = GraphicHelper::getThumbnailReplacement_Impl( nResID, xStream );
3582 else
3584 // retrieve the bitmap and write a signature bitmap over it
3585 SfxResId aResId( nResID );
3586 BitmapEx aThumbBitmap( aResId );
3587 bResult = GraphicHelper::getSignedThumbnailFormatFromBitmap_Impl( aThumbBitmap, xStream );
3591 else
3593 ::boost::shared_ptr<GDIMetaFile> pMetaFile =
3594 GetPreviewMetaFile( sal_False );
3595 if ( pMetaFile )
3597 bResult = GraphicHelper::getThumbnailFormatFromGDI_Impl(
3598 pMetaFile.get(), bSigned, xStream );
3602 catch( uno::Exception& )
3606 return bResult;
3609 void SfxObjectShell::UpdateLinks()
3613 bool SfxObjectShell::LoadExternal( SfxMedium& )
3615 // Not implemented. It's an error if the code path ever comes here.
3616 return false;
3619 void SfxObjectShell::CheckConfigOptions()
3621 // not handled. Each app's shell needs to overwrite this method to add handler.
3622 SetConfigOptionsChecked(true);
3625 sal_Bool SfxObjectShell::IsConfigOptionsChecked() const
3627 return pImp->m_bConfigOptionsChecked;
3630 void SfxObjectShell::SetConfigOptionsChecked( sal_Bool bChecked )
3632 pImp->m_bConfigOptionsChecked = bChecked;
3635 sal_Bool SfxObjectShell::QuerySaveSizeExceededModules_Impl( const uno::Reference< task::XInteractionHandler >& xHandler )
3637 #ifdef DISABLE_SCRIPTING
3638 (void) xHandler;
3639 #else
3640 if ( !HasBasic() )
3641 return sal_True;
3643 if ( !pImp->pBasicManager->isValid() )
3644 GetBasicManager();
3645 uno::Sequence< OUString > sModules;
3646 if ( xHandler.is() )
3648 if( pImp->pBasicManager->LegacyPsswdBinaryLimitExceeded( sModules ) )
3650 ModuleSizeExceeded* pReq = new ModuleSizeExceeded( sModules );
3651 uno::Reference< task::XInteractionRequest > xReq( pReq );
3652 xHandler->handle( xReq );
3653 return pReq->isApprove();
3656 #endif
3657 // No interaction handler, default is to continue to save
3658 return sal_True;
3660 // -----------------------------------------------------------------------------
3661 uno::Reference< task::XInteractionHandler > SfxObjectShell::getInteractionHandler() const
3663 uno::Reference< task::XInteractionHandler > xRet;
3664 if ( GetMedium() )
3665 xRet = GetMedium()->GetInteractionHandler();
3666 return xRet;
3669 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */