merge the formfield patch from ooo-build
[ooovba.git] / sfx2 / source / doc / objstor.cxx
blob80f2b0c5f9bc498d925ebe9a307d0dce55ed6cfd
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: objstor.cxx,v $
10 * $Revision: 1.212.44.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sfx2.hxx"
34 #ifndef _MSGBOX_HXX //autogen
35 #include <vcl/msgbox.hxx>
36 #endif
37 #include <svtools/eitem.hxx>
38 #include <svtools/stritem.hxx>
39 #include <svtools/intitem.hxx>
40 #include <tools/zcodec.hxx>
41 #include <com/sun/star/frame/XStorable.hpp>
42 #include <com/sun/star/frame/XModel.hpp>
43 #include <com/sun/star/frame/XFrame.hpp>
44 #include <com/sun/star/document/XFilter.hpp>
45 #include <com/sun/star/document/XImporter.hpp>
46 #include <com/sun/star/document/XExporter.hpp>
47 #include <com/sun/star/document/FilterOptionsRequest.hpp>
48 #include <com/sun/star/document/XInteractionFilterOptions.hpp>
49 #include <com/sun/star/task/XInteractionHandler.hpp>
50 #include <com/sun/star/task/XInteractionAskLater.hpp>
51 #include <com/sun/star/task/FutureDocumentVersionProductUpdateRequest.hpp>
52 #include <com/sun/star/task/InteractionClassification.hpp>
53 #include <com/sun/star/lang/XInitialization.hpp>
54 #include <com/sun/star/document/MacroExecMode.hpp>
55 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
56 #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
57 #include <com/sun/star/ui/dialogs/XFilePicker.hpp>
58 #include <com/sun/star/beans/XPropertySetInfo.hpp>
59 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
60 #include <com/sun/star/beans/XPropertyAccess.hpp>
61 #include <com/sun/star/beans/PropertyValue.hpp>
62 #include <com/sun/star/beans/XPropertySet.hpp>
63 #include <com/sun/star/container/XNameAccess.hpp>
64 #include <com/sun/star/container/XSet.hpp>
65 #include <com/sun/star/embed/ElementModes.hpp>
66 #include <com/sun/star/embed/EmbedStates.hpp>
67 #include <com/sun/star/embed/Aspects.hpp>
68 #include <com/sun/star/embed/XTransactedObject.hpp>
69 #include <com/sun/star/embed/XEmbedPersist.hpp>
70 #include <com/sun/star/embed/XLinkageSupport.hpp>
71 #include <com/sun/star/embed/EntryInitModes.hpp>
72 #include <com/sun/star/embed/XOptimizedStorage.hpp>
73 #include <com/sun/star/io/XTruncate.hpp>
74 #include <com/sun/star/util/XModifiable.hpp>
75 #include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
77 #include <com/sun/star/document/XDocumentProperties.hpp>
78 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
79 #include <comphelper/processfactory.hxx>
80 #include <comphelper/configurationhelper.hxx>
81 #include <comphelper/interaction.hxx>
82 #include <svtools/sfxecode.hxx>
83 #include <svtools/securityoptions.hxx>
84 #include <cppuhelper/weak.hxx>
85 #include <comphelper/processfactory.hxx>
86 #include <tools/cachestr.hxx>
87 #include <svtools/addxmltostorageoptions.hxx>
88 #include <unotools/streamwrap.hxx>
90 #include <svtools/saveopt.hxx>
91 #include <svtools/useroptions.hxx>
92 #include <svtools/pathoptions.hxx>
93 #include <tools/urlobj.hxx>
94 #include <tools/diagnose_ex.h>
95 #include <unotools/localfilehelper.hxx>
96 #include <unotools/ucbhelper.hxx>
97 #include <unotools/tempfile.hxx>
98 #include <unotools/docinfohelper.hxx>
99 #include <ucbhelper/content.hxx>
100 #include <sot/storinfo.hxx>
101 #include <sot/exchange.hxx>
102 #include <sot/formats.hxx>
103 #include <comphelper/storagehelper.hxx>
104 #include <comphelper/seqstream.hxx>
105 #include <comphelper/documentconstants.hxx>
106 #include <comphelper/string.hxx>
107 #include <vcl/bitmapex.hxx>
108 #include <svtools/embedhlp.hxx>
109 #include <rtl/logfile.hxx>
110 #include <basic/modsizeexceeded.hxx>
111 #include <osl/file.hxx>
112 #include <com/sun/star/util/XMacroExpander.hpp>
113 #include <osl/process.h>
114 #include <osl/thread.hxx>
116 #include <sfx2/signaturestate.hxx>
117 #include <sfx2/app.hxx>
118 #include <sfx2/objsh.hxx>
119 #include <sfx2/childwin.hxx>
120 #include <sfx2/request.hxx>
121 #include "sfxresid.hxx"
122 #include <sfx2/docfile.hxx>
123 #include "fltfnc.hxx"
124 #include <sfx2/docfilt.hxx>
125 #include <sfx2/docfac.hxx>
126 #include "objshimp.hxx"
127 #include "sfxtypes.hxx"
128 #include "doc.hrc"
129 #include <sfx2/sfxsids.hrc>
130 #include <sfx2/module.hxx>
131 #include <sfx2/dispatch.hxx>
132 #include "openflag.hxx"
133 #include "helper.hxx"
134 #include <sfx2/filedlghelper.hxx>
135 #include <sfx2/event.hxx>
136 #include "fltoptint.hxx"
137 #include <sfx2/viewfrm.hxx>
138 #include "graphhelp.hxx"
139 #include "appbaslib.hxx"
140 #include "appdata.hxx"
142 #ifdef OS2
143 #include <osl/file.hxx>
144 #include <stdio.h>
145 #include <sys/ea.h>
146 #endif
148 #include "../appl/app.hrc"
150 extern sal_uInt32 CheckPasswd_Impl( SfxObjectShell*, SfxItemPool&, SfxMedium* );
152 using namespace ::com::sun::star;
153 using namespace ::com::sun::star::container;
154 using namespace ::com::sun::star::lang;
155 using namespace ::com::sun::star::ui::dialogs;
156 using namespace ::com::sun::star::uno;
157 using namespace ::com::sun::star::beans;
158 using namespace ::com::sun::star::ucb;
159 using namespace ::com::sun::star::task;
160 using namespace ::com::sun::star::document;
161 using namespace ::rtl;
162 using namespace ::cppu;
164 namespace css = ::com::sun::star;
166 class StatusThread : public osl::Thread
168 oslFileHandle m_handle;
170 public:
171 int volatile progressTicks;
173 StatusThread(oslFileHandle handle) :
174 osl::Thread(), m_handle(handle), progressTicks(0)
179 virtual void SAL_CALL run() {
180 sal_uInt64 nRead;
181 char buf[1024];
182 for(;;) {
183 oslFileError err=osl_readFile(m_handle, buf, sizeof(buf)-1, &nRead);
184 if (err!=osl_File_E_None || nRead<=0) {
185 break;
187 buf[nRead]=0;
188 progressTicks++;
194 static sal_Bool invokeExternalApp(String aAppName, ::rtl::OUString sourceParam, ::rtl::OUString targetParam, uno::Reference< ::com::sun::star::task::XStatusIndicator > xStatusIndicator)
196 static const char EXPAND_WILDCARD_CONST[] ="vnd.sun.star.expand:";
197 static const char SOURCE_WILDCARD_CONST[]="%source%";
198 static const char TARGET_WILDCARD_CONST[]="%target%";
199 // get macro expansion
200 uno::Reference< XMultiServiceFactory> xMS(::comphelper::getProcessServiceFactory(), UNO_QUERY);
201 uno::Reference< beans::XPropertySet > xProps(xMS, UNO_QUERY);
202 uno::Reference< XComponentContext > xContext(xProps->getPropertyValue(rtl::OUString::createFromAscii("DefaultContext")), UNO_QUERY);
203 uno::Reference< util::XMacroExpander > xExpander(xContext->getValueByName(::rtl::OUString::createFromAscii("/singletons/com.sun.star.util.theMacroExpander")), UNO_QUERY);
205 // parse preprocessing arguments
206 int c=aAppName.GetQuotedTokenCount('\"',',');
207 if (c<1) return sal_False;
208 rtl_uString **args=new rtl_uString*[c];
209 for(int i=0;i<c;i++) {
210 String aArg=aAppName.GetQuotedToken(i,'\"',',');
211 if (aArg.EqualsIgnoreCaseAscii(EXPAND_WILDCARD_CONST, 0, strlen(EXPAND_WILDCARD_CONST))) {
212 rtl::OUString argStr(aArg.GetBuffer()+strlen(EXPAND_WILDCARD_CONST));
213 aArg=xExpander->expandMacros(argStr);
214 } else if (aArg.EqualsIgnoreCaseAscii(SOURCE_WILDCARD_CONST, 0, strlen(SOURCE_WILDCARD_CONST))) {
215 aArg=sourceParam;
216 } else if (aArg.EqualsIgnoreCaseAscii(TARGET_WILDCARD_CONST, 0, strlen(TARGET_WILDCARD_CONST))) {
217 aArg=targetParam;
219 args[i]=rtl::OUString(aArg).pData;
220 rtl_uString_acquire(args[i]);
223 sal_Bool bOk=sal_False;
225 #ifndef NDEBUG
226 for (int p=0;p<c;p++) {
227 rtl::OString aOString = ::rtl::OUStringToOString (args[p], RTL_TEXTENCODING_UTF8);
228 printf("args[%i]=\"%s\"\n", p, aOString.getStr());
230 #endif
231 // invoke processing step
232 oslProcess pProcess=NULL;
233 oslFileHandle handle=NULL;
234 oslProcessError error=osl_executeProcess_WithRedirectedIO(
235 args[0],
236 args+1,
237 c-1,
238 /*osl_Process_NORMAL*/ osl_Process_HIDDEN,
240 NULL,
241 NULL,
243 &pProcess,
244 NULL,
245 &handle,
246 NULL
249 if (error==osl_Process_E_None) {
250 static const int MAXBARTICKS=1000;
251 StatusThread statusThread(handle);
252 statusThread.create();
253 if (xStatusIndicator.is()) {
254 xStatusIndicator->start(::rtl::OUString::createFromAscii("waiting for external application..."), MAXBARTICKS);
256 do {
257 TimeValue wait = {1, 0};
258 error=osl_joinProcessWithTimeout( pProcess, &wait);
259 if (xStatusIndicator.is()) {
260 xStatusIndicator->setValue(statusThread.progressTicks%MAXBARTICKS);
262 } while (error==osl_Process_E_TimedOut);
263 if (xStatusIndicator.is()) {
264 xStatusIndicator->end();
266 if (error==osl_Process_E_None) {
267 oslProcessInfo aProcessInfo;
268 aProcessInfo.Size = sizeof(aProcessInfo);
269 error = osl_getProcessInfo( pProcess, osl_Process_EXITCODE, &aProcessInfo );
270 if (error==osl_Process_E_None && aProcessInfo.Code == 0) {
271 bOk=sal_True;
274 statusThread.join();
276 osl_freeProcessHandle(pProcess);
278 for(int i=0;i<c;i++) {
279 rtl_uString_release(args[i]);
281 delete[] args;
282 return bOk;
286 //=========================================================================
287 void impl_addToModelCollection(const css::uno::Reference< css::frame::XModel >& xModel)
289 if (!xModel.is())
290 return;
292 css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = ::comphelper::getProcessServiceFactory();
293 css::uno::Reference< css::container::XSet > xModelCollection(
294 xSMGR->createInstance(::rtl::OUString::createFromAscii("com.sun.star.frame.GlobalEventBroadcaster")),
295 css::uno::UNO_QUERY);
296 if (xModelCollection.is())
300 xModelCollection->insert(css::uno::makeAny(xModel));
302 catch ( uno::Exception& )
304 OSL_ENSURE( sal_False, "The document seems to be in the collection already!\n" );
309 //=========================================================================
311 sal_Bool SfxObjectShell::Save()
313 return SaveChildren();
316 //--------------------------------------------------------------------------
318 sal_Bool SfxObjectShell::SaveAs( SfxMedium& rMedium )
320 return SaveAsChildren( rMedium );
323 //-------------------------------------------------------------------------
325 sal_Bool GetPasswd_Impl( const SfxItemSet* pSet, ::rtl::OUString& rPasswd )
327 const SfxPoolItem* pItem = NULL;
328 if ( pSet && SFX_ITEM_SET == pSet->GetItemState( SID_PASSWORD, sal_True, &pItem ) )
330 DBG_ASSERT( pItem->IsA( TYPE(SfxStringItem) ), "wrong item type" );
331 rPasswd = ( (const SfxStringItem*)pItem )->GetValue();
332 return sal_True;
334 return sal_False;
337 //-------------------------------------------------------------------------
338 sal_Bool SfxObjectShell::NoDependencyFromManifest_Impl( const uno::Reference< embed::XStorage >& xStorage )
340 uno::Sequence< ::rtl::OUString > aElements = xStorage->getElementNames();
341 for ( sal_Int32 nInd = 0; nInd < aElements.getLength(); nInd++ )
343 if ( xStorage->isStorageElement( aElements[nInd] ) )
345 // if there are other standard elements that do not need manifest.xml the following
346 // list can be extended
347 if ( !aElements[nInd].equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Pictures" ) ) )
348 && !aElements[nInd].equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Configurations" ) ) )
349 && !aElements[nInd].equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Configurations2" ) ) )
350 && !aElements[nInd].equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Thumbnails" ) ) )
351 && !aElements[nInd].equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Basic" ) ) ) )
353 // the substorage is not know as one that does not need manifest.xml
354 return sal_False;
359 return sal_True;
362 //-------------------------------------------------------------------------
363 sal_Bool SfxObjectShell::PutURLContentsToVersionStream_Impl(
364 ::rtl::OUString aURL,
365 const uno::Reference< embed::XStorage >& xDocStorage,
366 ::rtl::OUString aStreamName )
368 sal_Bool bResult = sal_False;
371 uno::Reference< embed::XStorage > xVersion = xDocStorage->openStorageElement(
372 ::rtl::OUString::createFromAscii( "Versions" ),
373 embed::ElementModes::READWRITE );
375 DBG_ASSERT( xVersion.is(),
376 "The method must throw an exception if the storage can not be opened!\n" );
377 if ( !xVersion.is() )
378 throw uno::RuntimeException();
380 uno::Reference< io::XStream > xVerStream = xVersion->openStreamElement(
381 aStreamName,
382 embed::ElementModes::READWRITE );
383 DBG_ASSERT( xVerStream.is(), "The method must throw an exception if the storage can not be opened!\n" );
384 if ( !xVerStream.is() )
385 throw uno::RuntimeException();
387 uno::Reference< io::XOutputStream > xOutStream = xVerStream->getOutputStream();
388 uno::Reference< io::XTruncate > xTrunc( xOutStream, uno::UNO_QUERY );
390 DBG_ASSERT( xTrunc.is(), "The output stream must exist and implement XTruncate interface!\n" );
391 if ( !xTrunc.is() )
392 throw RuntimeException();
394 uno::Reference< io::XInputStream > xTmpInStream =
395 ::comphelper::OStorageHelper::GetInputStreamFromURL( aURL );
396 DBG_ASSERT( xTmpInStream.is(), "The method must create the stream or throw an exception!\n" );
397 if ( !xTmpInStream.is() )
398 throw uno::RuntimeException();
400 xTrunc->truncate();
401 ::comphelper::OStorageHelper::CopyInputToOutput( xTmpInStream, xOutStream );
402 xOutStream->closeOutput();
404 uno::Reference< embed::XTransactedObject > xTransact( xVersion, uno::UNO_QUERY );
405 DBG_ASSERT( xTransact.is(), "The storage must implement XTransacted interface!\n" );
406 if ( xTransact.is() )
407 xTransact->commit();
409 bResult = sal_True;
411 catch( uno::Exception& )
413 // TODO/LATER: handle the error depending on exception
414 SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
417 return bResult;
420 //-------------------------------------------------------------------------
421 ::rtl::OUString SfxObjectShell::CreateTempCopyOfStorage_Impl( const uno::Reference< embed::XStorage >& xStorage )
423 ::rtl::OUString aTempURL = ::utl::TempFile().GetURL();
425 DBG_ASSERT( aTempURL.getLength(), "Can't create a temporary file!\n" );
426 if ( aTempURL.getLength() )
430 uno::Reference< embed::XStorage > xTempStorage =
431 ::comphelper::OStorageHelper::GetStorageFromURL( aTempURL, embed::ElementModes::READWRITE );
433 // the password will be transfered from the xStorage to xTempStorage by storage implemetation
434 xStorage->copyToStorage( xTempStorage );
436 // the temporary storage was commited by the previous method and it will die by refcount
438 catch ( uno::Exception& )
440 DBG_ERROR( "Creation of a storage copy is failed!" );
441 ::utl::UCBContentHelper::Kill( aTempURL );
443 aTempURL = ::rtl::OUString();
445 // TODO/LATER: may need error code setting based on exception
446 SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
450 return aTempURL;
453 //-------------------------------------------------------------------------
454 SvGlobalName SfxObjectShell::GetClassName() const
456 return GetFactory().GetClassId();
459 //-------------------------------------------------------------------------
460 void SfxObjectShell::SetupStorage( const uno::Reference< embed::XStorage >& xStorage,
461 sal_Int32 nVersion,
462 sal_Bool bTemplate ) const
464 uno::Reference< beans::XPropertySet > xProps( xStorage, uno::UNO_QUERY );
466 if ( xProps.is() )
468 SvGlobalName aName;
469 String aFullTypeName, aShortTypeName, aAppName;
470 sal_uInt32 nClipFormat=0;
472 FillClass( &aName, &nClipFormat, &aAppName, &aFullTypeName, &aShortTypeName, nVersion, bTemplate );
473 if ( nClipFormat )
475 // basic doesn't have a ClipFormat
476 // without MediaType the storage is not really usable, but currently the BasicIDE still
477 // is an SfxObjectShell and so we can't take this as an error
478 datatransfer::DataFlavor aDataFlavor;
479 SotExchange::GetFormatDataFlavor( nClipFormat, aDataFlavor );
480 if ( aDataFlavor.MimeType.getLength() )
484 xProps->setPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ), uno::makeAny( aDataFlavor.MimeType ) );
486 catch( uno::Exception& )
488 const_cast<SfxObjectShell*>( this )->SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
491 ::rtl::OUString aVersion;
492 SvtSaveOptions aSaveOpt;
493 SvtSaveOptions::ODFDefaultVersion nDefVersion = aSaveOpt.GetODFDefaultVersion();
495 // older versions can not have this property set, it exists only starting from ODF1.2
496 if ( nDefVersion >= SvtSaveOptions::ODFVER_012 )
497 aVersion = ODFVER_012_TEXT;
499 if ( aVersion.getLength() )
503 xProps->setPropertyValue( ::rtl::OUString::createFromAscii( "Version" ), uno::makeAny( aVersion ) );
505 catch( uno::Exception& )
514 //-------------------------------------------------------------------------
515 void SfxObjectShell::PrepareSecondTryLoad_Impl()
517 // only for internal use
518 pImp->m_xDocStorage = uno::Reference< embed::XStorage >();
519 pImp->m_bIsInit = sal_False;
520 ResetError();
523 //-------------------------------------------------------------------------
524 sal_Bool SfxObjectShell::GeneralInit_Impl( const uno::Reference< embed::XStorage >& xStorage,
525 sal_Bool bTypeMustBeSetAlready )
527 if ( pImp->m_bIsInit )
528 return sal_False;
530 pImp->m_bIsInit = sal_True;
531 if ( xStorage.is() )
533 // no notification is required the storage is set the first time
534 pImp->m_xDocStorage = xStorage;
536 try {
537 uno::Reference < beans::XPropertySet > xPropSet( xStorage, uno::UNO_QUERY_THROW );
538 Any a = xPropSet->getPropertyValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ) );
539 ::rtl::OUString aMediaType;
540 if ( !(a>>=aMediaType) || !aMediaType.getLength() )
542 if ( bTypeMustBeSetAlready )
544 SetError( ERRCODE_IO_BROKENPACKAGE, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
545 return sal_False;
548 SetupStorage( xStorage, SOFFICE_FILEFORMAT_CURRENT, sal_False );
551 catch ( uno::Exception& )
553 OSL_ENSURE( sal_False, "Can't check storage's mediatype!\n" );
556 else
557 pImp->m_bCreateTempStor = sal_True;
559 return sal_True;
562 //-------------------------------------------------------------------------
563 sal_Bool SfxObjectShell::InitNew( const uno::Reference< embed::XStorage >& xStorage )
565 return GeneralInit_Impl( xStorage, sal_False );
568 //-------------------------------------------------------------------------
569 sal_Bool SfxObjectShell::Load( SfxMedium& rMedium )
571 return GeneralInit_Impl( rMedium.GetStorage(), sal_True );
574 //-------------------------------------------------------------------------
575 sal_Bool SfxObjectShell::DoInitNew_Impl( const ::rtl::OUString& rName )
577 /* [Beschreibung]
581 if ( rName.getLength() )
583 DBG_ERROR( "This code is intended to be removed, the caller part must be checked!\n" );
584 return DoInitNew(0);
586 else
587 return DoInitNew(0);
591 sal_Bool SfxObjectShell::DoInitNew( SfxMedium* pMed )
592 /* [Beschreibung]
594 Diese von SvPersist geerbte virtuelle Methode wird gerufen, um
595 die SfxObjectShell-Instanz aus einem Storage (pStor != 0) bzw.
596 (pStor == 0) ganz neu zu initialisieren.
598 Wie alle Do...-Methoden liegt hier eine Steuerung vor, die eigentliche
599 Implementierung erfolgt, indem die ebenfalls virtuellen Methode
600 InitNew(SvStorate*) von der SfxObjectShell-Subclass implementiert wird.
602 F"ur pStor == 0 wird ein die SfxObjectShell-Instanz mit einem leeren
603 SfxMedium verbunden, sonst mit einem SfxMedium, welches auf den
604 als Parameter "ubergeben SvStorage verweist.
606 Erst nach InitNew() oder Load() ist das Objekt korrekt initialisiert.
608 [R"uckgabewert]
609 sal_True Das Objekt wurde initialisiert.
610 sal_False Das Objekt konnte nicht initialisiert werden
614 ModifyBlocker_Impl aBlock( this );
615 pMedium = pMed;
616 if ( !pMedium )
618 bIsTmp = sal_True;
619 pMedium = new SfxMedium;
622 pMedium->CanDisposeStorage_Impl( sal_True );
624 if ( InitNew( pMed ? pMed->GetStorage() : uno::Reference < embed::XStorage >() ) )
626 // empty documents always get their macros from the user, so there is no reason to restrict access
627 pImp->aMacroMode.allowMacroExecution();
628 if ( SFX_CREATE_MODE_EMBEDDED == eCreateMode )
629 SetTitle( String( SfxResId( STR_NONAME ) ));
631 uno::Reference< frame::XModel > xModel ( GetModel(), uno::UNO_QUERY );
632 if ( xModel.is() )
634 SfxItemSet *pSet = GetMedium()->GetItemSet();
635 uno::Sequence< beans::PropertyValue > aArgs;
636 TransformItems( SID_OPENDOC, *pSet, aArgs );
637 sal_Int32 nLength = aArgs.getLength();
638 aArgs.realloc( nLength + 1 );
639 aArgs[nLength].Name = DEFINE_CONST_UNICODE("Title");
640 aArgs[nLength].Value <<= ::rtl::OUString( GetTitle( SFX_TITLE_DETECT ) );
641 xModel->attachResource( ::rtl::OUString(), aArgs );
642 impl_addToModelCollection(xModel);
645 pImp->bInitialized = sal_True;
646 SetActivateEvent_Impl( SFX_EVENT_CREATEDOC );
647 SFX_APP()->NotifyEvent( SfxEventHint( SFX_EVENT_DOCCREATED, GlobalEventConfig::GetEventName(STR_EVENT_DOCCREATED), this ) );
648 return sal_True;
651 return sal_False;
654 //-------------------------------------------------------------------------
656 sal_Bool SfxObjectShell::ImportFromGeneratedStream_Impl(
657 const uno::Reference< io::XStream >& xStream,
658 const uno::Sequence< beans::PropertyValue >& aMediaDescr )
660 if ( !xStream.is() )
661 return sal_False;
663 if ( pMedium && pMedium->HasStorage_Impl() )
664 pMedium->CloseStorage();
666 sal_Bool bResult = sal_False;
670 uno::Reference< embed::XStorage > xStorage =
671 ::comphelper::OStorageHelper::GetStorageFromStream( xStream, embed::ElementModes::READWRITE );
673 if ( !xStorage.is() )
674 throw uno::RuntimeException();
676 if ( !pMedium )
677 pMedium = new SfxMedium( xStorage, String() );
678 else
679 pMedium->SetStorage_Impl( xStorage );
681 SfxAllItemSet aSet( SFX_APP()->GetPool() );
682 TransformParameters( SID_OPENDOC, aMediaDescr, aSet );
683 pMedium->GetItemSet()->Put( aSet );
684 pMedium->CanDisposeStorage_Impl( sal_False );
686 // allow the subfilter to reinit the model
687 if ( pImp->m_bIsInit )
688 pImp->m_bIsInit = sal_False;
690 if ( LoadOwnFormat( *pMedium ) )
692 bHasName = sal_True;
693 if ( !IsReadOnly() && IsLoadReadonly() )
694 SetReadOnlyUI();
696 bResult = sal_True;
697 OSL_ENSURE( pImp->m_xDocStorage == xStorage, "Wrong storage is used!\n" );
700 // now the medium can be disconnected from the storage
701 // the medium is not allowed to dispose the storage so CloseStorage() can be used
702 pMedium->CloseStorage();
704 catch( uno::Exception& )
708 return bResult;
711 //-------------------------------------------------------------------------
713 sal_Bool SfxObjectShell::DoLoad( SfxMedium *pMed )
715 ModifyBlocker_Impl aBlock( this );
717 if ( SFX_CREATE_MODE_EMBEDDED != eCreateMode )
718 GetpApp()->ShowStatusText( SfxResId(STR_DOC_LOADING) );
720 pMedium = pMed;
721 pMedium->CanDisposeStorage_Impl( sal_True );
723 sal_Bool bOk = sal_False;
724 const SfxFilter* pFilter = pMed->GetFilter();
725 SfxItemSet* pSet = pMedium->GetItemSet();
726 if( !pImp->nEventId )
728 SFX_ITEMSET_ARG(
729 pSet, pTemplateItem, SfxBoolItem,
730 SID_TEMPLATE, sal_False);
731 SetActivateEvent_Impl(
732 ( pTemplateItem && pTemplateItem->GetValue() )
733 ? SFX_EVENT_CREATEDOC : SFX_EVENT_OPENDOC );
737 SFX_ITEMSET_ARG( pSet, pBaseItem, SfxStringItem,
738 SID_BASEURL, sal_False);
739 String aBaseURL;
740 SFX_ITEMSET_ARG( pMedium->GetItemSet(), pSalvageItem, SfxStringItem, SID_DOC_SALVAGE, sal_False);
741 if( pBaseItem )
742 aBaseURL = pBaseItem->GetValue();
743 else
745 if ( pSalvageItem )
747 String aName( pMed->GetPhysicalName() );
748 ::utl::LocalFileHelper::ConvertPhysicalNameToURL( aName, aBaseURL );
750 else
751 aBaseURL = pMed->GetBaseURL();
753 pMed->GetItemSet()->Put( SfxStringItem( SID_DOC_BASEURL, aBaseURL ) );
755 pImp->nLoadedFlags = 0;
756 pImp->bModelInitialized = sal_False;
758 //TODO/LATER: make a clear strategy how to handle "UsesStorage" etc.
759 sal_Bool bOwnStorageFormat = IsOwnStorageFormat_Impl( *pMedium );
760 sal_Bool bHasStorage = IsPackageStorageFormat_Impl( *pMedium );
761 if ( pMedium->GetFilter() )
763 sal_uInt32 nError = HandleFilter( pMedium, this );
764 if ( nError != ERRCODE_NONE )
765 SetError( nError, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
767 if (pMedium->GetFilter()->GetFilterFlags() & SFX_FILTER_STARTPRESENTATION)
768 pSet->Put( SfxBoolItem( SID_DOC_STARTPRESENTATION, TRUE) );
771 EnableSetModified( sal_False );
773 pMedium->LockOrigFileOnDemand( sal_True, sal_False );
774 if ( GetError() == ERRCODE_NONE && bOwnStorageFormat && ( !pFilter || !( pFilter->GetFilterFlags() & SFX_FILTER_STARONEFILTER ) ) )
776 uno::Reference< embed::XStorage > xStorage;
777 if ( pMedium->GetError() == ERRCODE_NONE )
778 xStorage = pMedium->GetStorage();
780 if( xStorage.is() && pMedium->GetLastStorageCreationState() == ERRCODE_NONE )
782 DBG_ASSERT( pFilter, "No filter for storage found!" );
786 sal_Bool bWarnMediaTypeFallback = sal_False;
787 SFX_ITEMSET_ARG( pMedium->GetItemSet(), pRepairPackageItem, SfxBoolItem, SID_REPAIRPACKAGE, sal_False);
789 // treat the package as broken if the mediatype was retrieved as a fallback
790 uno::Reference< beans::XPropertySet > xStorProps( xStorage, uno::UNO_QUERY_THROW );
791 xStorProps->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaTypeFallbackUsed" ) ) )
792 >>= bWarnMediaTypeFallback;
794 if ( pRepairPackageItem && pRepairPackageItem->GetValue() )
796 // the macros in repaired documents should be disabled
797 pMedium->GetItemSet()->Put( SfxUInt16Item( SID_MACROEXECMODE, document::MacroExecMode::NEVER_EXECUTE ) );
799 // the mediatype was retrieved by using fallback solution but this is a repairing mode
800 // so it is acceptable to open the document if there is no contents that required manifest.xml
801 bWarnMediaTypeFallback = sal_False;
804 if ( bWarnMediaTypeFallback || !xStorage->getElementNames().getLength() )
805 SetError( ERRCODE_IO_BROKENPACKAGE, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
807 catch( uno::Exception& )
809 // TODO/LATER: may need error code setting based on exception
810 SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
813 // Load
814 if ( !GetError() )
816 pImp->nLoadedFlags = 0;
817 pImp->bModelInitialized = sal_False;
818 int end, pos = STRING_NOTFOUND;
819 String aUserData;
820 static const char PREPROCESS_CONST[]="Preprocess=<";
821 if (pFilter) {
822 aUserData=pFilter->GetUserData();
823 // check whether a prepocessing step is requested in the configuration
824 pos=aUserData.Search(::rtl::OUString::createFromAscii(PREPROCESS_CONST).getStr(), 0);
825 end=aUserData.Search( '>', pos+strlen(PREPROCESS_CONST));
827 if (pos!=STRING_NOTFOUND && end!=STRING_NOTFOUND) {
828 String aAppName(aUserData, pos+strlen(PREPROCESS_CONST), end-(pos+strlen(PREPROCESS_CONST)));
830 // setup status bar
831 SfxItemSet *pSet2 = pMed->GetItemSet();
832 const SfxUnoAnyItem *pItem=NULL;
833 SfxItemState ret=pSet2->GetItemState( SID_PROGRESS_STATUSBAR_CONTROL, TRUE, (const SfxPoolItem**)&pItem);
834 uno::Reference< ::com::sun::star::task::XStatusIndicator > xStatusIndicator;
835 if (ret==SFX_ITEM_SET && pItem!=NULL)
837 pItem->GetValue() >>= xStatusIndicator;
839 // create a copy
840 SfxMedium myMed(*pMed, sal_False);
841 ::utl::TempFile aTempFile;
842 myMed.SetName(aTempFile.GetURL(), sal_True);
843 myMed.SetPhysicalName_Impl(aTempFile.GetFileName());
844 myMed.ResetError();
845 myMed.CloseStorage();
846 myMed.CloseInStream();
847 myMed.SetTemporary(sal_True);
849 bOk = invokeExternalApp(aAppName, ::rtl::OUString(pMed->GetPhysicalName()), ::rtl::OUString(myMed.GetPhysicalName()), xStatusIndicator);
851 // load from copy
852 if (bOk) {
853 bOk = xStorage.is() && LoadOwnFormat( myMed );
855 } else {
856 // We process only errors from invokeExternalApp at this point
857 // The errors from the above LoadOwnFormat are processed later
858 SetError( ERRCODE_IO_CANTREAD, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
860 } else {
861 bOk = xStorage.is() && LoadOwnFormat( *pMed );
863 if ( bOk )
865 // the document loaded from template has no name
866 SFX_ITEMSET_ARG( pMedium->GetItemSet(), pTemplateItem, SfxBoolItem, SID_TEMPLATE, sal_False);
867 if ( !pTemplateItem || !pTemplateItem->GetValue() )
868 bHasName = sal_True;
870 if ( !IsReadOnly() && IsLoadReadonly() )
871 SetReadOnlyUI();
873 else
874 SetError( ERRCODE_ABORT, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
877 else
878 SetError( pMed->GetLastStorageCreationState(), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
880 else if ( GetError() == ERRCODE_NONE && InitNew(0) )
882 // Name vor ConvertFrom setzen, damit GetSbxObject() schon funktioniert
883 bHasName = sal_True;
884 SetName( SfxResId( STR_NONAME ) );
886 if( !bHasStorage )
887 pMedium->GetInStream();
888 else
889 pMedium->GetStorage();
891 if ( GetError() == ERRCODE_NONE )
893 pImp->nLoadedFlags = 0;
894 pImp->bModelInitialized = sal_False;
895 if ( pMedium->GetFilter() && ( pMedium->GetFilter()->GetFilterFlags() & SFX_FILTER_STARONEFILTER ) )
897 uno::Reference < beans::XPropertySet > xSet( GetModel(), uno::UNO_QUERY );
898 ::rtl::OUString sLockUpdates(::rtl::OUString::createFromAscii("LockUpdates"));
899 bool bSetProperty = true;
902 xSet->setPropertyValue( sLockUpdates, makeAny( (sal_Bool) sal_True ) );
904 catch(const beans::UnknownPropertyException& )
906 bSetProperty = false;
908 bOk = ImportFrom(*pMedium);
909 if(bSetProperty)
913 xSet->setPropertyValue( sLockUpdates, makeAny( (sal_Bool) sal_False ) );
915 catch(const beans::UnknownPropertyException& )
918 UpdateLinks();
919 FinishedLoading( SFX_LOADED_ALL );
921 else
923 bOk = ConvertFrom(*pMedium);
924 InitOwnModel_Impl();
929 if ( bOk )
933 ::ucbhelper::Content aContent( pMedium->GetName(), com::sun::star::uno::Reference < XCommandEnvironment >() );
934 com::sun::star::uno::Reference < XPropertySetInfo > xProps = aContent.getProperties();
935 if ( xProps.is() )
937 ::rtl::OUString aAuthor( RTL_CONSTASCII_USTRINGPARAM("Author") );
938 ::rtl::OUString aKeywords( RTL_CONSTASCII_USTRINGPARAM("Keywords") );
939 ::rtl::OUString aSubject( RTL_CONSTASCII_USTRINGPARAM("Subject") );
940 Any aAny;
941 ::rtl::OUString aValue;
942 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
943 GetModel(), uno::UNO_QUERY_THROW);
944 uno::Reference<document::XDocumentProperties> xDocProps
945 = xDPS->getDocumentProperties();
946 if ( xProps->hasPropertyByName( aAuthor ) )
948 aAny = aContent.getPropertyValue( aAuthor );
949 if ( ( aAny >>= aValue ) )
950 xDocProps->setAuthor(aValue);
952 if ( xProps->hasPropertyByName( aKeywords ) )
954 aAny = aContent.getPropertyValue( aKeywords );
955 if ( ( aAny >>= aValue ) )
956 xDocProps->setKeywords(
957 ::comphelper::string::convertCommaSeparated(aValue));
960 if ( xProps->hasPropertyByName( aSubject ) )
962 aAny = aContent.getPropertyValue( aSubject );
963 if ( ( aAny >>= aValue ) ) {
964 xDocProps->setSubject(aValue);
969 catch( Exception& )
973 // Falls nicht asynchron geladen wird selbst FinishedLoading aufrufen
974 if ( !( pImp->nLoadedFlags & SFX_LOADED_MAINDOCUMENT ) &&
975 ( !pMedium->GetFilter() || pMedium->GetFilter()->UsesStorage() )
977 FinishedLoading( SFX_LOADED_MAINDOCUMENT );
979 if( IsOwnStorageFormat_Impl(*pMed) && pMed->GetFilter() )
981 //???? dv DirEntry aDirEntry( pMed->GetPhysicalName() );
982 //???? dv SetFileName( aDirEntry.GetFull() );
984 Broadcast( SfxSimpleHint(SFX_HINT_NAMECHANGED) );
986 if ( SFX_CREATE_MODE_EMBEDDED != eCreateMode )
988 GetpApp()->HideStatusText();
990 SFX_ITEMSET_ARG( pMedium->GetItemSet(), pAsTempItem, SfxBoolItem, SID_TEMPLATE, sal_False);
991 SFX_ITEMSET_ARG( pMedium->GetItemSet(), pPreviewItem, SfxBoolItem, SID_PREVIEW, sal_False);
992 SFX_ITEMSET_ARG( pMedium->GetItemSet(), pHiddenItem, SfxBoolItem, SID_HIDDEN, sal_False);
993 if( bOk && pMedium->GetOrigURL().Len()
994 && !( pAsTempItem && pAsTempItem->GetValue() )
995 && !( pPreviewItem && pPreviewItem->GetValue() )
996 && !( pHiddenItem && pHiddenItem->GetValue() ) )
998 INetURLObject aUrl( pMedium->GetOrigURL() );
1000 if ( aUrl.GetProtocol() == INET_PROT_FILE )
1002 const SfxFilter* pOrgFilter = pMedium->GetOrigFilter();
1003 Application::AddToRecentDocumentList(
1004 aUrl.GetURLNoPass( INetURLObject::NO_DECODE ),
1005 (pOrgFilter) ? pOrgFilter->GetMimeType() : String() );
1010 #if 0
1011 if ( pMedium->HasStorage_Impl() )
1013 uno::Reference< XInteractionHandler > xHandler( pMedium->GetInteractionHandler() );
1014 if ( xHandler.is() && !SFX_APP()->Get_Impl()->bODFVersionWarningLater )
1016 uno::Reference<beans::XPropertySet> xStorageProps( pMedium->GetStorage(), uno::UNO_QUERY_THROW );
1017 ::rtl::OUString sVersion;
1020 xStorageProps->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Version" ) ) ) >>= sVersion;
1022 catch( const uno::Exception& )
1024 // Custom Property "ODFVersion" does not exist
1027 if ( sVersion.getLength() )
1029 double nVersion = sVersion.toDouble();
1030 if ( nVersion > 1.20001 && SfxObjectShell_Impl::NeedsOfficeUpdateDialog() )
1031 // ODF version greater than 1.2 - added some decimal places to be safe against floating point conversion errors (hack)
1033 ::rtl::OUString sDocumentURL( pMedium->GetOrigURL() );
1034 ::rtl::OUString aSystemFileURL;
1035 if ( osl::FileBase::getSystemPathFromFileURL( sDocumentURL, aSystemFileURL ) == osl::FileBase::E_None )
1036 sDocumentURL = aSystemFileURL;
1038 FutureDocumentVersionProductUpdateRequest aUpdateRequest;
1039 aUpdateRequest.Classification = InteractionClassification_QUERY;
1040 aUpdateRequest.DocumentURL = sDocumentURL;
1042 ::rtl::Reference< ::comphelper::OInteractionRequest > pRequest = new ::comphelper::OInteractionRequest( makeAny( aUpdateRequest ) );
1043 pRequest->addContinuation( new ::comphelper::OInteractionApprove );
1044 pRequest->addContinuation( new ::comphelper::OInteractionDisapprove );
1046 typedef ::comphelper::OInteraction< XInteractionAskLater > OInteractionAskLater;
1047 OInteractionAskLater* pLater = new OInteractionAskLater;
1048 pRequest->addContinuation( pLater );
1052 xHandler->handle( pRequest.get() );
1054 catch( const Exception& )
1056 DBG_UNHANDLED_EXCEPTION();
1058 if ( pLater->wasSelected() )
1059 SFX_APP()->Get_Impl()->bODFVersionWarningLater = true;
1064 #endif
1066 else
1067 GetpApp()->HideStatusText();
1069 return bOk;
1072 sal_uInt32 SfxObjectShell::HandleFilter( SfxMedium* pMedium, SfxObjectShell* pDoc )
1074 sal_uInt32 nError = ERRCODE_NONE;
1075 SfxItemSet* pSet = pMedium->GetItemSet();
1076 SFX_ITEMSET_ARG( pSet, pOptions, SfxStringItem, SID_FILE_FILTEROPTIONS, sal_False );
1077 SFX_ITEMSET_ARG( pSet, pData, SfxUnoAnyItem, SID_FILTER_DATA, sal_False );
1078 if ( !pData && !pOptions )
1080 com::sun::star::uno::Reference< XMultiServiceFactory > xServiceManager = ::comphelper::getProcessServiceFactory();
1081 com::sun::star::uno::Reference< XNameAccess > xFilterCFG;
1082 if( xServiceManager.is() )
1084 xFilterCFG = com::sun::star::uno::Reference< XNameAccess >(
1085 xServiceManager->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.document.FilterFactory" ) ),
1086 UNO_QUERY );
1089 if( xFilterCFG.is() )
1091 BOOL bAbort = FALSE;
1092 try {
1093 const SfxFilter* pFilter = pMedium->GetFilter();
1094 Sequence < PropertyValue > aProps;
1095 Any aAny = xFilterCFG->getByName( pFilter->GetName() );
1096 if ( aAny >>= aProps )
1098 sal_Int32 nPropertyCount = aProps.getLength();
1099 for( sal_Int32 nProperty=0; nProperty < nPropertyCount; ++nProperty )
1100 if( aProps[nProperty].Name.equals( ::rtl::OUString::createFromAscii("UIComponent")) )
1102 ::rtl::OUString aServiceName;
1103 aProps[nProperty].Value >>= aServiceName;
1104 if( aServiceName.getLength() )
1106 com::sun::star::uno::Reference< XInteractionHandler > rHandler = pMedium->GetInteractionHandler();
1107 if( rHandler.is() )
1109 // we need some properties in the media descriptor, so we have to make sure that they are in
1110 Any aStreamAny;
1111 aStreamAny <<= pMedium->GetInputStream();
1112 if ( pSet->GetItemState( SID_INPUTSTREAM ) < SFX_ITEM_SET )
1113 pSet->Put( SfxUnoAnyItem( SID_INPUTSTREAM, aStreamAny ) );
1114 if ( pSet->GetItemState( SID_FILE_NAME ) < SFX_ITEM_SET )
1115 pSet->Put( SfxStringItem( SID_FILE_NAME, pMedium->GetName() ) );
1116 if ( pSet->GetItemState( SID_FILTER_NAME ) < SFX_ITEM_SET )
1117 pSet->Put( SfxStringItem( SID_FILTER_NAME, pFilter->GetName() ) );
1119 Sequence< PropertyValue > rProperties;
1120 TransformItems( SID_OPENDOC, *pSet, rProperties, NULL );
1121 RequestFilterOptions* pFORequest = new RequestFilterOptions( pDoc->GetModel(), rProperties );
1123 com::sun::star::uno::Reference< XInteractionRequest > rRequest( pFORequest );
1124 rHandler->handle( rRequest );
1126 if ( !pFORequest->isAbort() )
1128 SfxAllItemSet aNewParams( pDoc->GetPool() );
1129 TransformParameters( SID_OPENDOC,
1130 pFORequest->getFilterOptions(),
1131 aNewParams,
1132 NULL );
1134 SFX_ITEMSET_ARG( &aNewParams,
1135 pFilterOptions,
1136 SfxStringItem,
1137 SID_FILE_FILTEROPTIONS,
1138 sal_False );
1139 if ( pFilterOptions )
1140 pSet->Put( *pFilterOptions );
1142 SFX_ITEMSET_ARG( &aNewParams,
1143 pFilterData,
1144 SfxUnoAnyItem,
1145 SID_FILTER_DATA,
1146 sal_False );
1147 if ( pFilterData )
1148 pSet->Put( *pFilterData );
1150 else
1151 bAbort = TRUE;
1155 break;
1159 if( bAbort )
1161 // filter options were not entered
1162 nError = ERRCODE_ABORT;
1165 catch( NoSuchElementException& )
1167 // the filter name is unknown
1168 nError = ERRCODE_IO_INVALIDPARAMETER;
1170 catch( Exception& )
1172 nError = ERRCODE_ABORT;
1177 return nError;
1180 //-------------------------------------------------------------------------
1182 sal_Bool SfxObjectShell::IsOwnStorageFormat_Impl(const SfxMedium &rMedium) const
1184 return !rMedium.GetFilter() || // Embedded
1185 ( rMedium.GetFilter()->IsOwnFormat() &&
1186 rMedium.GetFilter()->UsesStorage() &&
1187 rMedium.GetFilter()->GetVersion() >= SOFFICE_FILEFORMAT_60 );
1190 //-------------------------------------------------------------------------
1192 sal_Bool SfxObjectShell::IsPackageStorageFormat_Impl(const SfxMedium &rMedium) const
1194 return !rMedium.GetFilter() || // Embedded
1195 ( rMedium.GetFilter()->UsesStorage() &&
1196 rMedium.GetFilter()->GetVersion() >= SOFFICE_FILEFORMAT_60 );
1199 //-------------------------------------------------------------------------
1201 sal_Bool SfxObjectShell::DoSave()
1202 // DoSave wird nur noch ueber OLE aufgerufen. Sichern eigener Dokumente im SFX
1203 // laeuft uber DoSave_Impl, um das Anlegen von Backups zu ermoeglichen.
1204 // Save in eigenes Format jetzt auch wieder Hierueber
1206 sal_Bool bOk = sal_False ;
1208 ModifyBlocker_Impl aBlock( this );
1210 pImp->bIsSaving = sal_True;
1212 ::rtl::OUString aPasswd;
1213 if ( IsPackageStorageFormat_Impl( *GetMedium() ) )
1215 if ( GetPasswd_Impl( GetMedium()->GetItemSet(), aPasswd ) )
1219 //TODO/MBA: GetOutputStorage?! Special mode, because it's "Save"?!
1220 ::comphelper::OStorageHelper::SetCommonStoragePassword( GetMedium()->GetStorage(), aPasswd );
1221 bOk = sal_True;
1223 catch( uno::Exception& )
1225 SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
1228 DBG_ASSERT( bOk, "The root storage must allow to set common password!\n" );
1230 else
1231 bOk = sal_True;
1233 if ( HasBasic() )
1237 // The basic and dialogs related contents are still not able to proceed with save operation ( saveTo only )
1238 // so since the document storage is locked a workaround has to be used
1240 uno::Reference< embed::XStorage > xTmpStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
1241 DBG_ASSERT( xTmpStorage.is(), "If a storage can not be created an exception must be thrown!\n" );
1242 if ( !xTmpStorage.is() )
1243 throw uno::RuntimeException();
1245 ::rtl::OUString aBasicStorageName( RTL_CONSTASCII_USTRINGPARAM( "Basic" ) );
1246 ::rtl::OUString aDialogsStorageName( RTL_CONSTASCII_USTRINGPARAM( "Dialogs" ) );
1247 if ( GetMedium()->GetStorage()->hasByName( aBasicStorageName ) )
1248 GetMedium()->GetStorage()->copyElementTo( aBasicStorageName, xTmpStorage, aBasicStorageName );
1249 if ( GetMedium()->GetStorage()->hasByName( aDialogsStorageName ) )
1250 GetMedium()->GetStorage()->copyElementTo( aDialogsStorageName, xTmpStorage, aDialogsStorageName );
1252 GetBasicManager();
1254 // disconnect from the current storage
1255 pImp->pBasicManager->setStorage( xTmpStorage );
1257 // store to the current storage
1258 pImp->pBasicManager->storeLibrariesToStorage( GetMedium()->GetStorage() );
1260 // connect to the current storage back
1261 pImp->pBasicManager->setStorage( GetMedium()->GetStorage() );
1263 catch( uno::Exception& )
1265 SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
1266 bOk = sal_False;
1271 if ( bOk )
1272 bOk = Save();
1274 bOk = pMedium->Commit();
1277 //#88046
1278 // if ( bOk )
1279 // SetModified( sal_False );
1280 return bOk;
1283 void Lock_Impl( SfxObjectShell* pDoc, BOOL bLock )
1285 SfxViewFrame *pFrame= SfxViewFrame::GetFirst( pDoc );
1286 while ( pFrame )
1288 pFrame->GetDispatcher()->Lock( bLock );
1289 pFrame->Enable( !bLock );
1290 pFrame = SfxViewFrame::GetNext( *pFrame, pDoc );
1296 //-------------------------------------------------------------------------
1298 sal_Bool SfxObjectShell::SaveTo_Impl
1300 SfxMedium &rMedium, // Medium, in das gespeichert werden soll
1301 const SfxItemSet* pSet
1304 /* [Beschreibung]
1306 Schreibt den aktuellen Inhalt in das Medium rMedium.
1307 Ist das Zielmedium kein Storage, so wird ueber ein temporaeres
1308 Medium gespeichert, sonst direkt, da das Medium transacted
1309 geschaltet ist, wenn wir es selbst geoeffnet haben und falls wir
1310 Server sind entweder der Container einen transacted Storage zur
1311 Verfuegung stellt oder selbst einen temporaeren Storage erzeugt hat.
1315 RTL_LOGFILE_PRODUCT_CONTEXT( aLog, "PERFORMANCE SfxObjectShell::SaveTo_Impl" );
1316 if( RTL_LOGFILE_HASLOGFILE() )
1318 ByteString aString( rMedium.GetName(), RTL_TEXTENCODING_ASCII_US );
1319 RTL_LOGFILE_PRODUCT_CONTEXT_TRACE1( aLog, "saving \"%s\"", aString.GetBuffer() );
1322 AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Begin" ) ) );
1324 ModifyBlocker_Impl aMod(this);
1326 const SfxFilter *pFilter = rMedium.GetFilter();
1327 if ( !pFilter )
1329 // if no filter was set, use the default filter
1330 // this should be changed in the feature, it should be an error!
1331 DBG_ERROR("No filter set!");
1332 pFilter = GetFactory().GetFilterContainer()->GetAnyFilter( SFX_FILTER_IMPORT | SFX_FILTER_EXPORT );
1333 rMedium.SetFilter(pFilter);
1336 sal_Bool bStorageBasedSource = IsPackageStorageFormat_Impl( *pMedium );
1337 sal_Bool bStorageBasedTarget = IsPackageStorageFormat_Impl( rMedium );
1338 sal_Bool bOwnSource = IsOwnStorageFormat_Impl( *pMedium );
1339 sal_Bool bOwnTarget = IsOwnStorageFormat_Impl( rMedium );
1341 // Examine target format to determine whether to query if any password
1342 // protected libraries exceed the size we can handler
1343 if ( bOwnTarget && !QuerySaveSizeExceededModules_Impl( rMedium.GetInteractionHandler() ) )
1345 SetError( ERRCODE_IO_ABORT, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
1346 return sal_False;
1349 sal_Bool bNeedsDisconnectionOnFail = sal_False;
1351 sal_Bool bStoreToSameLocation = sal_False;
1353 // the detection whether the script is changed should be done before saving
1354 sal_Bool bTryToPreserveScriptSignature = sal_False;
1355 // no way to detect whether a filter is oasis format, have to wait for saving process
1356 sal_Bool bNoPreserveForOasis = sal_False;
1357 if ( bOwnSource && bOwnTarget
1358 && ( pImp->nScriptingSignatureState == SIGNATURESTATE_SIGNATURES_OK
1359 || pImp->nScriptingSignatureState == SIGNATURESTATE_SIGNATURES_NOTVALIDATED
1360 || pImp->nScriptingSignatureState == SIGNATURESTATE_SIGNATURES_INVALID ) )
1362 AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "MacroSignaturePreserving" ) ) );
1364 // the checking of the library modified state iterates over the libraries, should be done only when required
1365 // currently the check is commented out since it is broken, we have to check the signature every time we save
1366 // TODO/LATER: let isAnyContainerModified() work!
1367 bTryToPreserveScriptSignature = sal_True; // !pImp->pBasicManager->isAnyContainerModified();
1368 if ( bTryToPreserveScriptSignature )
1370 // check that the storage format stays the same
1371 SvtSaveOptions aSaveOpt;
1372 SvtSaveOptions::ODFDefaultVersion nVersion = aSaveOpt.GetODFDefaultVersion();
1374 ::rtl::OUString aODFVersion;
1377 uno::Reference < beans::XPropertySet > xPropSet( GetStorage(), uno::UNO_QUERY_THROW );
1378 xPropSet->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Version" ) ) ) >>= aODFVersion;
1380 catch( uno::Exception& )
1383 // preserve only if the same filter has been used
1384 bTryToPreserveScriptSignature = pMedium->GetFilter() && pFilter && pMedium->GetFilter()->GetFilterName() == pFilter->GetFilterName();
1386 bNoPreserveForOasis = (
1387 (aODFVersion.equals( ODFVER_012_TEXT ) && nVersion == SvtSaveOptions::ODFVER_011) ||
1388 (!aODFVersion.getLength() && nVersion >= SvtSaveOptions::ODFVER_012)
1393 sal_Bool bCopyTo = sal_False;
1394 SfxItemSet *pMedSet = rMedium.GetItemSet();
1395 if( pMedSet )
1397 SFX_ITEMSET_ARG( pMedSet, pSaveToItem, SfxBoolItem, SID_SAVETO, sal_False );
1398 bCopyTo = GetCreateMode() == SFX_CREATE_MODE_EMBEDDED ||
1399 (pSaveToItem && pSaveToItem->GetValue());
1402 // use UCB for case sensitive/insensitive file name comparison
1403 if ( pMedium
1404 && pMedium->GetName().CompareIgnoreCaseToAscii( "private:stream", 14 ) != COMPARE_EQUAL
1405 && rMedium.GetName().CompareIgnoreCaseToAscii( "private:stream", 14 ) != COMPARE_EQUAL
1406 && SfxMedium::EqualURLs( pMedium->GetName(), rMedium.GetName() ) )
1408 bStoreToSameLocation = sal_True;
1409 AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Save" ) ) );
1411 if ( pMedium->DocNeedsFileDateCheck() )
1412 rMedium.CheckFileDate( pMedium->GetInitFileDate( sal_False ) );
1414 if ( bCopyTo && GetCreateMode() != SFX_CREATE_MODE_EMBEDDED )
1416 // export to the same location is vorbidden
1417 SetError( ERRCODE_IO_CANTWRITE, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
1419 else
1421 // before we overwrite the original file, we will make a backup if there is a demand for that
1422 // if the backup is not created here it will be created internally and will be removed in case of successful saving
1423 const sal_Bool bDoBackup = SvtSaveOptions().IsBackup();
1424 if ( bDoBackup )
1426 AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "DoBackup" ) ) );
1427 rMedium.DoBackup_Impl();
1428 if ( rMedium.GetError() )
1430 SetError( rMedium.GetErrorCode(), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
1431 rMedium.ResetError();
1435 if ( bStorageBasedSource && bStorageBasedTarget )
1437 // The active storage must be switched. The simple saving is not enough.
1438 // The problem is that the target medium contains target MediaDescriptor.
1440 // In future the switch of the persistance could be done on stream level:
1441 // a new wrapper service will be implemented that allows to exchange
1442 // persistance on the fly. So the real persistance will be set
1443 // to that stream only after successful commit of the storage.
1444 // TODO/LATER:
1445 // create wrapper stream based on the URL
1446 // create a new storage based on this stream
1447 // store to this new storage
1448 // commit the new storage
1449 // call saveCompleted based with this new storage ( get rid of old storage and "frees" URL )
1450 // commit the wrapper stream ( the stream will connect the URL only on commit, after that it will hold it )
1451 // if the last step is failed the stream should stay to be transacted and should be commited on any flush
1452 // so we can forget the stream in any way and the next storage commit will flush it
1454 AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Save: Own to Own" ) ) );
1456 bNeedsDisconnectionOnFail = DisconnectStorage_Impl(
1457 *pMedium, rMedium );
1458 if ( bNeedsDisconnectionOnFail
1459 || ConnectTmpStorage_Impl( pMedium->GetStorage(), pMedium ) )
1461 pMedium->CloseAndRelease();
1463 // TODO/LATER: for now the medium must be closed since it can already contain streams from old medium
1464 // in future those streams should not be copied in case a valid target url is provided,
1465 // if the url is not provided ( means the document is based on a stream ) this code is not
1466 // reachable.
1467 rMedium.CloseAndRelease();
1468 rMedium.GetOutputStorage();
1471 else if ( !bStorageBasedSource && !bStorageBasedTarget )
1473 // the source and the target formats are alien
1474 // just disconnect the stream from the source format
1475 // so that the target medium can use it
1477 AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Save: Alien to Alien" ) ) );
1479 pMedium->CloseAndRelease();
1480 rMedium.CloseAndRelease();
1481 rMedium.CreateTempFileNoCopy();
1482 rMedium.GetOutStream();
1484 else if ( !bStorageBasedSource && bStorageBasedTarget )
1486 // the source format is an alien one but the target
1487 // format is an own one so just disconnect the source
1488 // medium
1490 AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Save: Alien to Own" ) ) );
1492 pMedium->CloseAndRelease();
1493 rMedium.CloseAndRelease();
1494 rMedium.GetOutputStorage();
1496 else // means if ( bStorageBasedSource && !bStorageBasedTarget )
1498 // the source format is an own one but the target is
1499 // an alien format, just connect the source to temporary
1500 // storage
1502 AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Save: Own to Alien" ) ) );
1504 bNeedsDisconnectionOnFail = DisconnectStorage_Impl(
1505 *pMedium, rMedium );
1506 if ( bNeedsDisconnectionOnFail
1507 || ConnectTmpStorage_Impl( pMedium->GetStorage(), pMedium ) )
1509 pMedium->CloseAndRelease();
1510 rMedium.CloseAndRelease();
1511 rMedium.CreateTempFileNoCopy();
1512 rMedium.GetOutStream();
1517 else
1519 // This is SaveAs or export action, prepare the target medium
1520 // the alien filters still might write directly to the file, that is of course a bug,
1521 // but for now the framework has to be ready for it
1522 // TODO/LATER: let the medium be prepared for alien formats as well
1524 AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "SaveAs/Export" ) ) );
1526 rMedium.CloseAndRelease();
1527 if ( bStorageBasedTarget )
1529 rMedium.GetOutputStorage();
1533 // TODO/LATER: error handling
1534 if( rMedium.GetErrorCode() || pMedium->GetErrorCode() || GetErrorCode() )
1535 return sal_False;
1537 AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Locking" ) ) );
1539 rMedium.LockOrigFileOnDemand( sal_False, sal_False );
1541 if ( bStorageBasedTarget )
1543 if ( rMedium.GetErrorCode() )
1544 return sal_False;
1546 // If the filter is a "cross export" filter ( f.e. a filter for exporting an impress document from
1547 // a draw document ), the ClassId of the destination storage is different from the ClassId of this
1548 // document. It can be retrieved from the default filter for the desired target format
1549 long nFormat = rMedium.GetFilter()->GetFormat();
1550 SfxFilterMatcher& rMatcher = SFX_APP()->GetFilterMatcher();
1551 const SfxFilter *pFilt = rMatcher.GetFilter4ClipBoardId( nFormat );
1552 if ( pFilt )
1554 if ( pFilt->GetServiceName() != rMedium.GetFilter()->GetServiceName() )
1556 //REMOVE rMedium.GetStorage()->SetClass( SvFactory::GetServerName( nFormat ), nFormat, pFilt->GetTypeName() );
1557 datatransfer::DataFlavor aDataFlavor;
1558 SotExchange::GetFormatDataFlavor( nFormat, aDataFlavor );
1562 uno::Reference< beans::XPropertySet > xProps( rMedium.GetStorage(), uno::UNO_QUERY );
1563 DBG_ASSERT( xProps.is(), "The storage implementation must implement XPropertySet!" );
1564 if ( !xProps.is() )
1565 throw uno::RuntimeException();
1567 xProps->setPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ),
1568 uno::makeAny( aDataFlavor.MimeType ) );
1570 catch( uno::Exception& )
1577 // TODO/LATER: error handling
1578 if( rMedium.GetErrorCode() || pMedium->GetErrorCode() || GetErrorCode() )
1579 return sal_False;
1581 sal_Bool bOldStat = pImp->bForbidReload;
1582 pImp->bForbidReload = sal_True;
1584 // lock user interface while saving the document
1585 Lock_Impl( this, sal_True );
1587 sal_Bool bOk = sal_False;
1588 // TODO/LATER: get rid of bOk
1590 if( bOwnTarget && !( pFilter->GetFilterFlags() & SFX_FILTER_STARONEFILTER ) )
1592 AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Storing in own format." ) ) );
1593 uno::Reference< embed::XStorage > xMedStorage = rMedium.GetStorage();
1594 if ( !xMedStorage.is() )
1596 // no saving without storage, unlock UI and return
1597 Lock_Impl( this, sal_False );
1598 pImp->bForbidReload = bOldStat;
1599 AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Storing failed, still no error set." ) ) );
1600 return sal_False;
1603 // transfer password from the parameters to the storage
1604 ::rtl::OUString aPasswd;
1605 sal_Bool bPasswdProvided = sal_False;
1606 if ( GetPasswd_Impl( rMedium.GetItemSet(), aPasswd ) )
1608 bPasswdProvided = sal_True;
1609 try {
1610 ::comphelper::OStorageHelper::SetCommonStoragePassword( xMedStorage, aPasswd );
1611 bOk = sal_True;
1613 catch( uno::Exception& )
1615 DBG_ERROR( "Setting of common encryption key failed!" );
1616 SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
1619 else
1620 bOk = sal_True;
1622 pFilter = rMedium.GetFilter();
1624 const SfxStringItem *pVersionItem = pSet ? (const SfxStringItem*)
1625 SfxRequest::GetItem( pSet, SID_DOCINFO_COMMENTS, sal_False, TYPE(SfxStringItem) ) : NULL;
1626 ::rtl::OUString aTmpVersionURL;
1628 if ( bOk )
1630 bOk = sal_False;
1631 // currently the case that the storage is the same should be impossible
1632 if ( xMedStorage == GetStorage() )
1634 OSL_ENSURE( !pVersionItem, "This scenario is impossible currently!\n" );
1635 AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Should be impossible." ) ) );
1636 // usual save procedure
1637 bOk = Save();
1639 else
1641 // save to target
1642 AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Save as own format." ) ) );
1643 bOk = SaveAsOwnFormat( rMedium );
1644 if ( bOk && pVersionItem )
1646 AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "pVersionItem != NULL" ) ) );
1647 aTmpVersionURL = CreateTempCopyOfStorage_Impl( xMedStorage );
1648 bOk = ( aTmpVersionURL.getLength() > 0 );
1654 if ( bOk && GetCreateMode() != SFX_CREATE_MODE_EMBEDDED && !bPasswdProvided )
1656 // store the thumbnail representation image
1657 // the thumbnail is not stored in case of encrypted document
1658 AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Thumbnail creation." ) ) );
1659 if ( !GenerateAndStoreThumbnail( bPasswdProvided,
1660 sal_False,
1661 pFilter->IsOwnTemplateFormat(),
1662 xMedStorage ) )
1664 // TODO: error handling
1665 OSL_ENSURE( sal_False, "Couldn't store thumbnail representation!" );
1669 if ( bOk )
1671 if ( pImp->bIsSaving || pImp->bPreserveVersions )
1673 AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Preserve versions." ) ) );
1676 Sequence < util::RevisionTag > aVersions = rMedium.GetVersionList();
1677 if ( aVersions.getLength() )
1679 // copy the version streams
1680 ::rtl::OUString aVersionsName( RTL_CONSTASCII_USTRINGPARAM( "Versions" ) );
1681 uno::Reference< embed::XStorage > xNewVerStor = xMedStorage->openStorageElement(
1682 aVersionsName,
1683 embed::ElementModes::READWRITE );
1684 uno::Reference< embed::XStorage > xOldVerStor = GetStorage()->openStorageElement(
1685 aVersionsName,
1686 embed::ElementModes::READ );
1687 if ( !xNewVerStor.is() || !xOldVerStor.is() )
1688 throw uno::RuntimeException();
1690 for ( sal_Int32 n=0; n<aVersions.getLength(); n++ )
1692 if ( xOldVerStor->hasByName( aVersions[n].Identifier ) )
1693 xOldVerStor->copyElementTo( aVersions[n].Identifier, xNewVerStor, aVersions[n].Identifier );
1696 uno::Reference< embed::XTransactedObject > xTransact( xNewVerStor, uno::UNO_QUERY );
1697 if ( xTransact.is() )
1698 xTransact->commit();
1701 catch( uno::Exception& )
1703 AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Preserve versions has failed." ) ) );
1704 DBG_ERROR( "Couldn't copy versions!\n" );
1705 bOk = sal_False;
1706 // TODO/LATER: a specific error could be set
1710 if ( bOk && pVersionItem )
1712 // store a version also
1713 const SfxStringItem *pAuthorItem = pSet ? (const SfxStringItem*)
1714 SfxRequest::GetItem( pSet, SID_DOCINFO_AUTHOR, sal_False, TYPE(SfxStringItem) ) : NULL;
1716 // version comment
1717 util::RevisionTag aInfo;
1718 aInfo.Comment = pVersionItem->GetValue();
1720 // version author
1721 String aAuthor;
1722 if ( pAuthorItem )
1723 aInfo.Author = pAuthorItem->GetValue();
1724 else
1725 // if not transferred as a parameter, get it from user settings
1726 aInfo.Author = SvtUserOptions().GetFullName();
1728 DateTime aTime;
1729 aInfo.TimeStamp.Day = aTime.GetDay();
1730 aInfo.TimeStamp.Month = aTime.GetMonth();
1731 aInfo.TimeStamp.Year = aTime.GetYear();
1732 aInfo.TimeStamp.Hours = aTime.GetHour();
1733 aInfo.TimeStamp.Minutes = aTime.GetMin();
1734 aInfo.TimeStamp.Seconds = aTime.GetSec();
1736 if ( bOk )
1738 // add new version information into the versionlist and save the versionlist
1739 // the version list must have been transferred from the "old" medium before
1740 rMedium.AddVersion_Impl( aInfo );
1741 rMedium.SaveVersionList_Impl( sal_True );
1742 bOk = PutURLContentsToVersionStream_Impl( aTmpVersionURL, xMedStorage, aInfo.Identifier );
1745 else if ( bOk && ( pImp->bIsSaving || pImp->bPreserveVersions ) )
1747 rMedium.SaveVersionList_Impl( sal_True );
1751 if ( aTmpVersionURL.getLength() )
1752 ::utl::UCBContentHelper::Kill( aTmpVersionURL );
1754 else
1756 AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Storing in alien format." ) ) );
1757 // it's a "SaveAs" in an alien format
1758 if ( rMedium.GetFilter() && ( rMedium.GetFilter()->GetFilterFlags() & SFX_FILTER_STARONEFILTER ) )
1759 bOk = ExportTo( rMedium );
1760 else
1761 bOk = ConvertTo( rMedium );
1763 // after saving the document, the temporary object storage must be updated
1764 // if the old object storage was not a temporary one, it will be updated also, because it will be used
1765 // as a source for copying the objects into the new temporary storage that will be created below
1766 // updating means: all child objects must be stored into it
1767 // ( same as on loading, where these objects are copied to the temporary storage )
1768 // but don't commit these changes, because in the case when the old object storage is not a temporary one,
1769 // all changes will be written into the original file !
1771 if( bOk && !bCopyTo )
1772 // we also don't touch any graphical replacements here
1773 bOk = SaveChildren( TRUE );
1776 if (bOk) { // commit *before* we do the conversion!
1777 bOk = rMedium.Commit();
1780 uno::Reference< embed::XStorage > xNewTmpStorage;
1781 if (bOk) {
1782 String aUserData=pFilter->GetUserData();
1783 // check whether a postprocessing step is requested in the configuration
1784 static const char POSTPROCESS_CONST[]="Postprocess=<";
1785 int pos=aUserData.Search(::rtl::OUString::createFromAscii(POSTPROCESS_CONST).getStr(), 0);
1786 int end=aUserData.Search( '>', pos+strlen(POSTPROCESS_CONST));
1787 if (pos!=STRING_NOTFOUND && end!=STRING_NOTFOUND) {
1788 String aAppName(aUserData, pos+strlen(POSTPROCESS_CONST), end-(pos+strlen(POSTPROCESS_CONST)));
1790 // setup status bar
1791 SfxItemSet *pSet2 = rMedium.GetItemSet();
1792 const SfxUnoAnyItem *pItem=NULL;
1793 SfxItemState ret=pSet2->GetItemState( SID_PROGRESS_STATUSBAR_CONTROL, TRUE, (const SfxPoolItem**)&pItem);
1794 uno::Reference< ::com::sun::star::task::XStatusIndicator > xStatusIndicator;
1795 if (ret==SFX_ITEM_SET && pItem!=NULL)
1797 pItem->GetValue() >>= xStatusIndicator;
1800 // create copy
1801 ::rtl::OUString aTmpVersionURL = CreateTempCopyOfStorage_Impl( rMedium.GetStorage() );
1802 rMedium.CloseAndRelease();
1804 rtl::OUString aSourceFile;
1805 osl::FileBase::getSystemPathFromFileURL(aTmpVersionURL, aSourceFile);
1806 String aTargetFile(rMedium.GetPhysicalName());
1808 // remove the current target file after it was copied
1809 // the postprocess might crash and the unprocessed file would confuse users
1810 String aTargetFileURL;
1811 ::utl::LocalFileHelper::ConvertPhysicalNameToURL( aTargetFile, aTargetFileURL );
1812 osl_removeFile(::rtl::OUString(aTargetFileURL).pData);
1814 bOk=invokeExternalApp(aAppName, aSourceFile, aTargetFile, xStatusIndicator);
1816 if (bOk) {
1817 // create a new tmp storage
1818 xNewTmpStorage=::comphelper::OStorageHelper::GetStorageFromURL( aTmpVersionURL, embed::ElementModes::READWRITE );
1819 // it does not make sense to reopen the file if it was not saved correctly
1820 rMedium.ReOpen();
1825 if (bOk && xNewTmpStorage.is()) {
1826 rMedium.SetStorage_Impl(xNewTmpStorage);
1829 if ( bOk )
1831 // if ODF version of oasis format changes on saving the signature should not be preserved
1832 if ( bOk && bTryToPreserveScriptSignature && bNoPreserveForOasis )
1833 bTryToPreserveScriptSignature = ( SotStorage::GetVersion( rMedium.GetStorage() ) == SOFFICE_FILEFORMAT_60 );
1835 uno::Reference< security::XDocumentDigitalSignatures > xDDSigns;
1836 if ( bOk && bTryToPreserveScriptSignature )
1838 AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Copying scripting signature." ) ) );
1840 // if the scripting code was not changed and it is signed the signature should be preserved
1841 // unfortunately at this point we have only information whether the basic code has changed or not
1842 // so the only way is to check the signature if the basic was not changed
1845 // get the ODF version of the new medium
1846 uno::Sequence< uno::Any > aArgs( 1 );
1847 aArgs[0] <<= ::rtl::OUString();
1850 uno::Reference < beans::XPropertySet > xPropSet( rMedium.GetStorage(), uno::UNO_QUERY_THROW );
1851 aArgs[0] = xPropSet->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Version" ) ) );
1853 catch( uno::Exception& )
1857 xDDSigns = uno::Reference< security::XDocumentDigitalSignatures >(
1858 comphelper::getProcessServiceFactory()->createInstanceWithArguments(
1859 rtl::OUString(
1860 RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.security.DocumentDigitalSignatures" ) ),
1861 aArgs ),
1862 uno::UNO_QUERY_THROW );
1864 ::rtl::OUString aScriptSignName = xDDSigns->getScriptingContentSignatureDefaultStreamName();
1866 if ( aScriptSignName.getLength() )
1868 pMedium->Close();
1870 // target medium is still not commited, it should not be closed
1871 // commit the package storage and close it, but leave the streams open
1872 rMedium.StorageCommit_Impl();
1873 rMedium.CloseStorage();
1875 uno::Reference< embed::XStorage > xReadOrig = pMedium->GetZipStorageToSign_Impl();
1876 if ( !xReadOrig.is() )
1877 throw uno::RuntimeException();
1878 uno::Reference< embed::XStorage > xMetaInf = xReadOrig->openStorageElement(
1879 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "META-INF" ) ),
1880 embed::ElementModes::READ );
1882 uno::Reference< embed::XStorage > xTarget = rMedium.GetZipStorageToSign_Impl( sal_False );
1883 if ( !xTarget.is() )
1884 throw uno::RuntimeException();
1885 uno::Reference< embed::XStorage > xTargetMetaInf = xTarget->openStorageElement(
1886 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "META-INF" ) ),
1887 embed::ElementModes::READWRITE );
1889 if ( xMetaInf.is() && xTargetMetaInf.is() )
1891 xMetaInf->copyElementTo( aScriptSignName, xTargetMetaInf, aScriptSignName );
1893 uno::Reference< embed::XTransactedObject > xTransact( xTargetMetaInf, uno::UNO_QUERY );
1894 if ( xTransact.is() )
1895 xTransact->commit();
1897 xTargetMetaInf->dispose();
1899 // now check the copied signature
1900 uno::Sequence< security::DocumentSignatureInformation > aInfos =
1901 xDDSigns->verifyScriptingContentSignatures( xTarget,
1902 uno::Reference< io::XInputStream >() );
1903 sal_uInt16 nState = ImplCheckSignaturesInformation( aInfos );
1904 if ( nState == SIGNATURESTATE_SIGNATURES_OK || nState == SIGNATURESTATE_SIGNATURES_NOTVALIDATED
1905 || nState == SIGNATURESTATE_SIGNATURES_PARTIAL_OK)
1907 rMedium.SetCachedSignatureState_Impl( nState );
1909 // commit the ZipStorage from target medium
1910 xTransact.set( xTarget, uno::UNO_QUERY );
1911 if ( xTransact.is() )
1912 xTransact->commit();
1914 else
1916 // it should not happen, the copies signature is invalid!
1917 // throw the changes away
1918 OSL_ASSERT( "An invalid signature was copied!" );
1923 catch( uno::Exception& )
1927 pMedium->Close();
1928 rMedium.CloseZipStorage_Impl();
1931 AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Medium commit." ) ) );
1933 // transfer data to its destinated location
1934 // the medium commits the storage or the stream it is based on
1935 RegisterTransfer( rMedium );
1937 if ( bOk )
1939 AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Storing is successful." ) ) );
1940 bOk = rMedium.Commit();
1942 // if the target medium is an alien format and the "old" medium was an own format and the "old" medium
1943 // has a name, the object storage must be exchanged, because now we need a new temporary storage
1944 // as object storage
1945 if ( !bCopyTo && bStorageBasedSource && !bStorageBasedTarget )
1947 if ( bStoreToSameLocation )
1949 // if the old medium already disconnected from document storage, the storage still must
1950 // be switched if backup file is used
1951 if ( bNeedsDisconnectionOnFail )
1952 ConnectTmpStorage_Impl( pImp->m_xDocStorage, NULL );
1954 else if ( pMedium->GetName().Len()
1955 || ( pMedium->HasStorage_Impl() && pMedium->WillDisposeStorageOnClose_Impl() ) )
1957 OSL_ENSURE( pMedium->GetName().Len(), "Fallback is used, the medium without name should not dispose the storage!\n" );
1958 // copy storage of old medium to new temporary storage and take this over
1959 if( !ConnectTmpStorage_Impl( pMedium->GetStorage(), pMedium ) )
1961 AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Process after storing has failed." ) ) );
1962 bOk = sal_False;
1967 else
1969 AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Storing has failed." ) ) );
1971 // in case the document storage was connected to backup temporarely it must be disconnected now
1972 if ( bNeedsDisconnectionOnFail )
1973 ConnectTmpStorage_Impl( pImp->m_xDocStorage, NULL );
1977 // unlock user interface
1978 Lock_Impl( this, sal_False );
1979 pImp->bForbidReload = bOldStat;
1981 if ( bOk )
1985 ::ucbhelper::Content aContent( rMedium.GetName(), com::sun::star::uno::Reference < XCommandEnvironment >() );
1986 com::sun::star::uno::Reference < XPropertySetInfo > xProps = aContent.getProperties();
1987 if ( xProps.is() )
1989 ::rtl::OUString aAuthor( RTL_CONSTASCII_USTRINGPARAM("Author") );
1990 ::rtl::OUString aKeywords( RTL_CONSTASCII_USTRINGPARAM("Keywords") );
1991 ::rtl::OUString aSubject( RTL_CONSTASCII_USTRINGPARAM("Subject") );
1992 Any aAny;
1994 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
1995 GetModel(), uno::UNO_QUERY_THROW);
1996 uno::Reference<document::XDocumentProperties> xDocProps
1997 = xDPS->getDocumentProperties();
1999 if ( xProps->hasPropertyByName( aAuthor ) )
2001 aAny <<= xDocProps->getAuthor();
2002 aContent.setPropertyValue( aAuthor, aAny );
2004 if ( xProps->hasPropertyByName( aKeywords ) )
2006 aAny <<= ::comphelper::string::convertCommaSeparated(
2007 xDocProps->getKeywords());
2008 aContent.setPropertyValue( aKeywords, aAny );
2010 if ( xProps->hasPropertyByName( aSubject ) )
2012 aAny <<= xDocProps->getSubject();
2013 aContent.setPropertyValue( aSubject, aAny );
2017 catch( Exception& )
2021 #ifdef OS2
2023 #define CHAR_POINTER(THE_OUSTRING) ::rtl::OUStringToOString (THE_OUSTRING, RTL_TEXTENCODING_UTF8).pData->buffer
2024 // Header for a single-valued ASCII EA data item
2025 typedef struct _EA_ASCII_header {
2026 USHORT usAttr; /* value: EAT_ASCII */
2027 USHORT usLen; /* length of data */
2028 CHAR szType[_MAX_PATH]; /* ASCII data fits in here ... */
2029 } EA_ASCII_HEADER;
2030 char filePath[_MAX_PATH];
2031 char fileExt[_MAX_PATH];
2032 char docType[_MAX_PATH];
2033 int rc;
2034 oslFileError eRet;
2035 ::rtl::OUString aSystemFileURL;
2036 const ::rtl::OUString aFileURL = rMedium.GetName();
2037 // close medium
2038 rMedium.Close();
2040 // convert file URL to system path
2041 if (osl::FileBase::getSystemPathFromFileURL( aFileURL, aSystemFileURL) == osl::FileBase::E_None) {
2042 EA_ASCII_HEADER eaAscii;
2043 struct _ea eaType;
2044 strcpy( filePath, CHAR_POINTER( aSystemFileURL));
2045 strcpy( docType, CHAR_POINTER( rMedium.GetFilter()->GetServiceName()));
2046 #if OSL_DEBUG_LEVEL>1
2047 printf( "file name: %s\n", filePath);
2048 printf( "filter name: %s\n", CHAR_POINTER(rMedium.GetFilter()->GetFilterName()));
2049 printf( "service name: %s\n", docType);
2050 #endif
2051 // initialize OS/2 EA data structure
2052 eaAscii.usAttr = EAT_ASCII;
2053 _splitpath ( filePath, NULL, NULL, NULL, fileExt);
2054 if (!stricmp( fileExt, ".pdf"))
2055 strcpy( eaAscii.szType, "Acrobat Document");
2056 else if (!strcmp( docType, "com.sun.star.text.TextDocument"))
2057 strcpy( eaAscii.szType, "OpenOfficeOrg Writer Document");
2058 else if (!strcmp( docType, "com.sun.star.sheet.SpreadsheetDocument"))
2059 strcpy( eaAscii.szType, "OpenOfficeOrg Calc Document");
2060 else if (!strcmp( docType, "com.sun.star.presentation.PresentationDocument"))
2061 strcpy( eaAscii.szType, "OpenOfficeOrg Impress Document");
2062 else if (!strcmp( docType, "com.sun.star.drawing.DrawingDocument"))
2063 strcpy( eaAscii.szType, "OpenOfficeOrg Draw Document");
2064 else
2065 strcpy( eaAscii.szType, "OpenOfficeOrg Document");
2066 eaAscii.usLen = strlen( eaAscii.szType);
2067 // fill libc EA data structure
2068 eaType.flags = 0;
2069 eaType.size = sizeof(USHORT)*2 + eaAscii.usLen;
2070 eaType.value = &eaAscii;
2071 // put EA to file
2072 rc = _ea_put( &eaType, filePath, 0, ".TYPE");
2073 #if OSL_DEBUG_LEVEL>1
2074 printf( "ea name: %s, rc %d, errno %d\n", eaAscii.szType, rc, errno);
2075 #endif
2078 #endif
2082 return bOk;
2085 //------------------------------------------------------------------------
2086 sal_Bool SfxObjectShell::DisconnectStorage_Impl( SfxMedium& rSrcMedium, SfxMedium& rTargetMedium )
2088 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::DisconnectStorage_Impl" );
2090 // this method disconnects the storage from source medium, and attaches it to the backup created by the target medium
2092 uno::Reference< embed::XStorage > xStorage = rSrcMedium.GetStorage();
2094 sal_Bool bResult = sal_False;
2095 if ( xStorage == pImp->m_xDocStorage )
2099 uno::Reference< embed::XOptimizedStorage > xOptStorage( xStorage, uno::UNO_QUERY_THROW );
2100 ::rtl::OUString aBackupURL = rTargetMedium.GetBackup_Impl();
2101 if ( aBackupURL.getLength() )
2103 // the following call will only compare stream sizes
2104 // TODO/LATER: this is a very risky part, since if the URL contents are different from the storage
2105 // contents, the storag will be broken
2106 xOptStorage->attachToURL( aBackupURL, sal_True );
2108 // the storage is successfuly attached to backup, thus it it owned by the document not by the medium
2109 rSrcMedium.CanDisposeStorage_Impl( sal_False );
2110 bResult = sal_True;
2113 catch ( uno::Exception& )
2117 OSL_ENSURE( bResult, "Storage disconnecting has failed - affects performance!" );
2119 return bResult;
2122 //------------------------------------------------------------------------
2124 sal_Bool SfxObjectShell::ConnectTmpStorage_Impl(
2125 const uno::Reference< embed::XStorage >& xStorage,
2126 SfxMedium* pMediumArg )
2128 /* [Beschreibung]
2130 Arbeitet die Applikation auf einem temporaeren Storage,
2131 so darf der temporaere Storage nicht aus dem SaveCompleted
2132 genommen werden. Daher wird in diesem Fall schon hier an
2133 den neuen Storage connected. SaveCompleted tut dann nichts.
2138 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::ConnectTmpStorage_Impl" );
2140 sal_Bool bResult = sal_False;
2142 if ( xStorage.is() )
2146 // the empty argument means that the storage will create temporary stream itself
2147 uno::Reference< embed::XOptimizedStorage > xOptStorage( xStorage, uno::UNO_QUERY_THROW );
2148 xOptStorage->writeAndAttachToStream( uno::Reference< io::XStream >() );
2150 // the storage is successfuly disconnected from the original sources, thus the medium must not dispose it
2151 if ( pMediumArg )
2152 pMediumArg->CanDisposeStorage_Impl( sal_False );
2154 bResult = sal_True;
2156 catch( uno::Exception& )
2160 // if switching of the storage does not work for any reason ( nonroot storage for example ) use the old method
2161 if ( !bResult ) try
2163 uno::Reference< embed::XStorage > xTmpStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
2165 DBG_ASSERT( xTmpStorage.is(), "If a storage can not be created an exception must be thrown!\n" );
2166 if ( !xTmpStorage.is() )
2167 throw uno::RuntimeException();
2169 // TODO/LATER: may be it should be done in SwitchPersistence also
2170 // TODO/LATER: find faster way to copy storage; perhaps sharing with backup?!
2171 xStorage->copyToStorage( xTmpStorage );
2172 //CopyStoragesOfUnknownMediaType( xStorage, xTmpStorage );
2173 bResult = SaveCompleted( xTmpStorage );
2175 if ( bResult )
2176 pImp->pBasicManager->setStorage( xTmpStorage );
2178 catch( uno::Exception& )
2181 if ( !bResult )
2183 // TODO/LATER: may need error code setting based on exception
2184 SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
2188 return bResult;
2191 //-------------------------------------------------------------------------
2193 sal_Bool SfxObjectShell::DoSaveObjectAs( SfxMedium& rMedium, BOOL bCommit )
2195 sal_Bool bOk = sal_False;
2197 ModifyBlocker_Impl aBlock( this );
2199 uno::Reference < embed::XStorage > xNewStor = rMedium.GetStorage();
2200 if ( !xNewStor.is() )
2201 return sal_False;
2203 uno::Reference < beans::XPropertySet > xPropSet( xNewStor, uno::UNO_QUERY );
2204 if ( xPropSet.is() )
2206 Any a = xPropSet->getPropertyValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ) );
2207 ::rtl::OUString aMediaType;
2208 if ( !(a>>=aMediaType) || !aMediaType.getLength() )
2210 OSL_ENSURE( sal_False, "The mediatype must be set already!\n" );
2211 SetupStorage( xNewStor, SOFFICE_FILEFORMAT_CURRENT, sal_False );
2214 pImp->bIsSaving = sal_False;
2215 bOk = SaveAsOwnFormat( rMedium );
2217 if ( bCommit )
2219 try {
2220 uno::Reference< embed::XTransactedObject > xTransact( xNewStor, uno::UNO_QUERY_THROW );
2221 xTransact->commit();
2223 catch( uno::Exception& )
2225 DBG_ERROR( "The strotage was not commited on DoSaveAs!\n" );
2231 return bOk;
2234 //-------------------------------------------------------------------------
2235 // TODO/LATER: may be the call must be removed completelly
2236 sal_Bool SfxObjectShell::DoSaveAs( SfxMedium& rMedium )
2238 // hier kommen nur Root-Storages rein, die via Temp-File gespeichert werden
2239 rMedium.CreateTempFileNoCopy();
2240 SetError(rMedium.GetErrorCode(), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
2241 if ( GetError() )
2242 return sal_False;
2244 // copy version list from "old" medium to target medium, so it can be used on saving
2245 if ( pImp->bPreserveVersions )
2246 rMedium.TransferVersionList_Impl( *pMedium );
2248 sal_Bool bRet = SaveTo_Impl( rMedium, NULL );
2249 if ( !bRet )
2250 SetError(rMedium.GetErrorCode(), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
2251 return bRet;
2254 //-------------------------------------------------------------------------
2256 sal_Bool SfxObjectShell::DoSaveCompleted( SfxMedium* pNewMed )
2258 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::DoSaveCompleted" );
2260 sal_Bool bOk = sal_True;
2261 sal_Bool bMedChanged = pNewMed && pNewMed!=pMedium;
2262 /* sal_Bool bCreatedTempStor = pNewMed && pMedium &&
2263 IsPackageStorageFormat_Impl(*pMedium) &&
2264 !IsPackageStorageFormat_Impl(*pNewMed) &&
2265 pMedium->GetName().Len();
2267 DBG_ASSERT( !pNewMed || pNewMed->GetError() == ERRCODE_NONE, "DoSaveCompleted: Medium has error!" );
2269 // delete Medium (and Storage!) after all notifications
2270 SfxMedium* pOld = pMedium;
2271 if ( bMedChanged )
2273 pMedium = pNewMed;
2274 pMedium->CanDisposeStorage_Impl( sal_True );
2277 const SfxFilter *pFilter = pMedium ? pMedium->GetFilter() : 0;
2278 if ( pNewMed )
2280 if( bMedChanged )
2282 if( pNewMed->GetName().Len() )
2283 bHasName = sal_True;
2284 Broadcast( SfxSimpleHint(SFX_HINT_NAMECHANGED) );
2285 getDocProperties()->setGenerator(
2286 ::utl::DocInfoHelper::GetGeneratorString() );
2289 uno::Reference< embed::XStorage > xStorage;
2290 if ( !pFilter || IsPackageStorageFormat_Impl( *pMedium ) )
2292 uno::Reference < embed::XStorage > xOld = GetStorage();
2294 // when the package based medium is broken and has no storage or if the storage
2295 // is the same as the document storage the current document storage should be preserved
2296 xStorage = pMedium->GetStorage();
2297 bOk = SaveCompleted( xStorage );
2298 if ( bOk && xStorage.is() && xOld != xStorage
2299 && (!pOld || !pOld->HasStorage_Impl() || xOld != pOld->GetStorage() ) )
2301 // old own storage was not controlled by old Medium -> dispose it
2302 try {
2303 xOld->dispose();
2304 } catch( uno::Exception& )
2306 // the storage is disposed already
2307 // can happen during reload scenario when the medium has disposed it during the closing
2308 // will be fixed in one of the next milestones
2312 else
2314 //REMOVE if( pFilter->UsesStorage() )
2315 //REMOVE pMedium->GetStorage();
2316 //REMOVE else if( pMedium->GetOpenMode() & STREAM_WRITE )
2317 if( pMedium->GetOpenMode() & STREAM_WRITE )
2318 pMedium->GetInStream();
2319 xStorage = GetStorage();
2322 // TODO/LATER: may be this code will be replaced, but not sure
2323 // Set storage in document library containers
2324 pImp->pBasicManager->setStorage( xStorage );
2326 else
2328 if( pMedium )
2330 if( pFilter && !IsPackageStorageFormat_Impl( *pMedium ) && (pMedium->GetOpenMode() & STREAM_WRITE ))
2332 pMedium->ReOpen();
2333 bOk = SaveCompletedChildren( sal_False );
2335 else
2336 bOk = SaveCompleted( NULL );
2338 // entweder Save oder ConvertTo
2339 else
2340 bOk = SaveCompleted( NULL );
2343 if ( bOk && pNewMed )
2345 if( bMedChanged )
2347 delete pOld;
2349 uno::Reference< frame::XModel > xModel = GetModel();
2350 if ( xModel.is() )
2352 ::rtl::OUString aURL = pNewMed->GetOrigURL();
2353 uno::Sequence< beans::PropertyValue > aMediaDescr;
2354 TransformItems( SID_OPENDOC, *pNewMed->GetItemSet(), aMediaDescr );
2357 xModel->attachResource( aURL, aMediaDescr );
2359 catch( uno::Exception& )
2363 // before the title regenerated the document must loose the signatures
2364 pImp->nDocumentSignatureState = SIGNATURESTATE_NOSIGNATURES;
2365 pImp->nScriptingSignatureState = pNewMed->GetCachedSignatureState_Impl();
2366 OSL_ENSURE( pImp->nScriptingSignatureState != SIGNATURESTATE_SIGNATURES_BROKEN, "The signature must not be broken at this place" );
2367 pImp->bSignatureErrorIsShown = sal_False;
2369 // TODO/LATER: in future the medium must control own signature state, not the document
2370 pNewMed->SetCachedSignatureState_Impl( SIGNATURESTATE_NOSIGNATURES ); // set the default value back
2372 // Titel neu setzen
2373 if ( pNewMed->GetName().Len() && SFX_CREATE_MODE_EMBEDDED != eCreateMode )
2374 InvalidateName();
2375 SetModified(sal_False); // nur bei gesetztem Medium zur"ucksetzen
2376 Broadcast( SfxSimpleHint(SFX_HINT_MODECHANGED) );
2378 // this is the end of the saving process, it is possible that the file was changed
2379 // between medium commit and this step ( attributes change and so on )
2380 // so get the file date again
2381 if ( pNewMed->DocNeedsFileDateCheck() )
2382 pNewMed->GetInitFileDate( sal_True );
2386 pMedium->ClearBackup_Impl();
2387 pMedium->LockOrigFileOnDemand( sal_True, sal_False );
2389 return bOk;
2392 //-------------------------------------------------------------------------
2394 sal_Bool SfxObjectShell::ConvertFrom
2396 SfxMedium& /*rMedium*/ /* <SfxMedium>, welches die Quell-Datei beschreibt
2397 (z.B. Dateiname, <SfxFilter>, Open-Modi etc.) */
2400 /* [Beschreibung]
2402 Diese Methode wird zum Laden von Dokumenten "uber alle Filter gerufen,
2403 die nicht SFX_FILTER_OWN sind oder f"ur die kein Clipboard-Format
2404 registriert wurde (also kein Storage-Format benutzen). Mit anderen Worten:
2405 mit dieser Methode wird importiert.
2407 Das hier zu "offende File sollte "uber 'rMedium' ge"offnet werden,
2408 um die richtigen Open-Modi zu gew"ahrleisten. Insbesondere wenn das
2409 Format beibehalten wird (nur m"oglich bei SFX_FILTER_SIMULATE oder
2410 SFX_FILTER_ONW) mu\s die Datei STREAM_SHARE_DENYWRITE ge"offnet werden.
2413 [R"uckgabewert]
2415 sal_Bool sal_True
2416 Das Dokument konnte geladen werden.
2418 sal_False
2419 Das Dokument konnte nicht geladen werden, ein
2420 Fehlercode ist mit <SvMedium::GetError()const> zu
2421 erhalten.
2424 [Beispiel]
2426 sal_Bool DocSh::ConvertFrom( SfxMedium &rMedium )
2428 SvStreamRef xStream = rMedium.GetInStream();
2429 if( xStream.is() )
2431 xStream->SetBufferSize(4096);
2432 *xStream >> ...;
2434 // NICHT 'rMedium.CloseInStream()' rufen! File gelockt halten!
2435 return SVSTREAM_OK == rMedium.GetError();
2438 return sal_False;
2442 [Querverweise]
2444 <SfxObjectShell::ConvertTo(SfxMedium&)>
2445 <SFX_FILTER_REGISTRATION>
2448 return sal_False;
2451 sal_Bool SfxObjectShell::InsertFrom( SfxMedium& rMedium )
2453 ::rtl::OUString aTypeName( rMedium.GetFilter()->GetTypeName() );
2454 ::rtl::OUString aFilterName( rMedium.GetFilter()->GetFilterName() );
2456 uno::Reference< lang::XMultiServiceFactory > xMan = ::comphelper::getProcessServiceFactory();
2457 uno::Reference < lang::XMultiServiceFactory > xFilterFact (
2458 xMan->createInstance( DEFINE_CONST_UNICODE( "com.sun.star.document.FilterFactory" ) ), uno::UNO_QUERY );
2460 uno::Sequence < beans::PropertyValue > aProps;
2461 uno::Reference < container::XNameAccess > xFilters ( xFilterFact, uno::UNO_QUERY );
2462 if ( xFilters->hasByName( aFilterName ) )
2464 xFilters->getByName( aFilterName ) >>= aProps;
2465 rMedium.GetItemSet()->Put( SfxStringItem( SID_FILTER_NAME, aFilterName ) );
2468 ::rtl::OUString aFilterImplName;
2469 sal_Int32 nFilterProps = aProps.getLength();
2470 for ( sal_Int32 nFilterProp = 0; nFilterProp<nFilterProps; nFilterProp++ )
2472 const beans::PropertyValue& rFilterProp = aProps[nFilterProp];
2473 if ( rFilterProp.Name.compareToAscii("FilterService") == COMPARE_EQUAL )
2475 rFilterProp.Value >>= aFilterImplName;
2476 break;
2480 uno::Reference< document::XFilter > xLoader;
2481 if ( aFilterImplName.getLength() )
2483 try{
2484 xLoader = uno::Reference< document::XFilter >
2485 ( xFilterFact->createInstanceWithArguments( aFilterName, uno::Sequence < uno::Any >() ), uno::UNO_QUERY );
2486 }catch(const uno::Exception&)
2487 { xLoader.clear(); }
2489 if ( xLoader.is() )
2491 // #131744#: it happens that xLoader does not support xImporter!
2492 try{
2493 uno::Reference< lang::XComponent > xComp( GetModel(), uno::UNO_QUERY_THROW );
2494 uno::Reference< document::XImporter > xImporter( xLoader, uno::UNO_QUERY_THROW );
2495 xImporter->setTargetDocument( xComp );
2497 uno::Sequence < beans::PropertyValue > lDescriptor;
2498 rMedium.GetItemSet()->Put( SfxStringItem( SID_FILE_NAME, rMedium.GetName() ) );
2499 TransformItems( SID_OPENDOC, *rMedium.GetItemSet(), lDescriptor );
2501 com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue > aArgs ( lDescriptor.getLength() );
2502 com::sun::star::beans::PropertyValue * pNewValue = aArgs.getArray();
2503 const com::sun::star::beans::PropertyValue * pOldValue = lDescriptor.getConstArray();
2504 const OUString sInputStream ( RTL_CONSTASCII_USTRINGPARAM ( "InputStream" ) );
2506 sal_Bool bHasInputStream = sal_False;
2507 BOOL bHasBaseURL = FALSE;
2508 sal_Int32 i;
2509 sal_Int32 nEnd = lDescriptor.getLength();
2511 for ( i = 0; i < nEnd; i++ )
2513 pNewValue[i] = pOldValue[i];
2514 if ( pOldValue [i].Name == sInputStream )
2515 bHasInputStream = sal_True;
2516 else if ( pOldValue[i].Name.equalsAsciiL ( RTL_CONSTASCII_STRINGPARAM ( "DocumentBaseURL" ) ) )
2517 bHasBaseURL = sal_True;
2520 if ( !bHasInputStream )
2522 aArgs.realloc ( ++nEnd );
2523 aArgs[nEnd-1].Name = sInputStream;
2524 aArgs[nEnd-1].Value <<= com::sun::star::uno::Reference < com::sun::star::io::XInputStream > ( new utl::OSeekableInputStreamWrapper ( *rMedium.GetInStream() ) );
2527 if ( !bHasBaseURL )
2529 aArgs.realloc ( ++nEnd );
2530 aArgs[nEnd-1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "DocumentBaseURL" ) );
2531 aArgs[nEnd-1].Value <<= rMedium.GetBaseURL();
2534 aArgs.realloc( ++nEnd );
2535 aArgs[nEnd-1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "InsertMode" ) );
2536 aArgs[nEnd-1].Value <<= (sal_Bool) sal_True;
2538 return xLoader->filter( aArgs );
2539 }catch(const uno::Exception&)
2543 return sal_False;
2546 sal_Bool SfxObjectShell::ImportFrom( SfxMedium& rMedium )
2548 ::rtl::OUString aTypeName( rMedium.GetFilter()->GetTypeName() );
2549 ::rtl::OUString aFilterName( rMedium.GetFilter()->GetFilterName() );
2551 uno::Reference< lang::XMultiServiceFactory > xMan = ::comphelper::getProcessServiceFactory();
2552 uno::Reference < lang::XMultiServiceFactory > xFilterFact (
2553 xMan->createInstance( DEFINE_CONST_UNICODE( "com.sun.star.document.FilterFactory" ) ), uno::UNO_QUERY );
2555 uno::Sequence < beans::PropertyValue > aProps;
2556 uno::Reference < container::XNameAccess > xFilters ( xFilterFact, uno::UNO_QUERY );
2557 if ( xFilters->hasByName( aFilterName ) )
2559 xFilters->getByName( aFilterName ) >>= aProps;
2560 rMedium.GetItemSet()->Put( SfxStringItem( SID_FILTER_NAME, aFilterName ) );
2563 ::rtl::OUString aFilterImplName;
2564 sal_Int32 nFilterProps = aProps.getLength();
2565 for ( sal_Int32 nFilterProp = 0; nFilterProp<nFilterProps; nFilterProp++ )
2567 const beans::PropertyValue& rFilterProp = aProps[nFilterProp];
2568 if ( rFilterProp.Name.compareToAscii("FilterService") == COMPARE_EQUAL )
2570 rFilterProp.Value >>= aFilterImplName;
2571 break;
2575 uno::Reference< document::XFilter > xLoader;
2576 if ( aFilterImplName.getLength() )
2578 try{
2579 xLoader = uno::Reference< document::XFilter >
2580 ( xFilterFact->createInstanceWithArguments( aFilterName, uno::Sequence < uno::Any >() ), uno::UNO_QUERY );
2581 }catch(const uno::Exception&)
2582 { xLoader.clear(); }
2584 if ( xLoader.is() )
2586 // #131744#: it happens that xLoader does not support xImporter!
2587 try{
2588 uno::Reference< lang::XComponent > xComp( GetModel(), uno::UNO_QUERY_THROW );
2589 uno::Reference< document::XImporter > xImporter( xLoader, uno::UNO_QUERY_THROW );
2590 xImporter->setTargetDocument( xComp );
2592 uno::Sequence < beans::PropertyValue > lDescriptor;
2593 rMedium.GetItemSet()->Put( SfxStringItem( SID_FILE_NAME, rMedium.GetName() ) );
2594 TransformItems( SID_OPENDOC, *rMedium.GetItemSet(), lDescriptor );
2596 com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue > aArgs ( lDescriptor.getLength() );
2597 com::sun::star::beans::PropertyValue * pNewValue = aArgs.getArray();
2598 const com::sun::star::beans::PropertyValue * pOldValue = lDescriptor.getConstArray();
2599 const OUString sInputStream ( RTL_CONSTASCII_USTRINGPARAM ( "InputStream" ) );
2601 sal_Bool bHasInputStream = sal_False;
2602 BOOL bHasBaseURL = FALSE;
2603 sal_Int32 i;
2604 sal_Int32 nEnd = lDescriptor.getLength();
2606 for ( i = 0; i < nEnd; i++ )
2608 pNewValue[i] = pOldValue[i];
2609 if ( pOldValue [i].Name == sInputStream )
2610 bHasInputStream = sal_True;
2611 else if ( pOldValue[i].Name.equalsAsciiL ( RTL_CONSTASCII_STRINGPARAM ( "DocumentBaseURL" ) ) )
2612 bHasBaseURL = sal_True;
2615 if ( !bHasInputStream )
2617 aArgs.realloc ( ++nEnd );
2618 aArgs[nEnd-1].Name = sInputStream;
2619 aArgs[nEnd-1].Value <<= com::sun::star::uno::Reference < com::sun::star::io::XInputStream > ( new utl::OSeekableInputStreamWrapper ( *rMedium.GetInStream() ) );
2622 if ( !bHasBaseURL )
2624 aArgs.realloc ( ++nEnd );
2625 aArgs[nEnd-1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "DocumentBaseURL" ) );
2626 aArgs[nEnd-1].Value <<= rMedium.GetBaseURL();
2629 return xLoader->filter( aArgs );
2630 }catch(const uno::Exception&)
2634 return sal_False;
2637 sal_Bool SfxObjectShell::ExportTo( SfxMedium& rMedium )
2639 ::rtl::OUString aTypeName( rMedium.GetFilter()->GetTypeName() );
2640 ::rtl::OUString aFilterName( rMedium.GetFilter()->GetFilterName() );
2641 uno::Reference< document::XExporter > xExporter;
2644 uno::Reference< lang::XMultiServiceFactory > xMan = ::comphelper::getProcessServiceFactory();
2645 uno::Reference < lang::XMultiServiceFactory > xFilterFact (
2646 xMan->createInstance( DEFINE_CONST_UNICODE( "com.sun.star.document.FilterFactory" ) ), uno::UNO_QUERY );
2648 uno::Sequence < beans::PropertyValue > aProps;
2649 uno::Reference < container::XNameAccess > xFilters ( xFilterFact, uno::UNO_QUERY );
2650 if ( xFilters->hasByName( aFilterName ) )
2651 xFilters->getByName( aFilterName ) >>= aProps;
2653 ::rtl::OUString aFilterImplName;
2654 sal_Int32 nFilterProps = aProps.getLength();
2655 for ( sal_Int32 nFilterProp = 0; nFilterProp<nFilterProps; nFilterProp++ )
2657 const beans::PropertyValue& rFilterProp = aProps[nFilterProp];
2658 if ( rFilterProp.Name.compareToAscii("FilterService") == COMPARE_EQUAL )
2660 rFilterProp.Value >>= aFilterImplName;
2661 break;
2665 if ( aFilterImplName.getLength() )
2667 try{
2668 xExporter = uno::Reference< document::XExporter >
2669 ( xFilterFact->createInstanceWithArguments( aFilterName, uno::Sequence < uno::Any >() ), uno::UNO_QUERY );
2670 }catch(const uno::Exception&)
2671 { xExporter.clear(); }
2675 if ( xExporter.is() )
2677 try{
2678 uno::Reference< lang::XComponent > xComp( GetModel(), uno::UNO_QUERY_THROW );
2679 uno::Reference< document::XFilter > xFilter( xExporter, uno::UNO_QUERY_THROW );
2680 xExporter->setSourceDocument( xComp );
2682 com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue > aOldArgs;
2683 SfxItemSet* pItems = rMedium.GetItemSet();
2684 TransformItems( SID_SAVEASDOC, *pItems, aOldArgs );
2686 const com::sun::star::beans::PropertyValue * pOldValue = aOldArgs.getConstArray();
2687 com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue > aArgs ( aOldArgs.getLength() );
2688 com::sun::star::beans::PropertyValue * pNewValue = aArgs.getArray();
2690 // put in the REAL file name, and copy all PropertyValues
2691 const OUString sOutputStream ( RTL_CONSTASCII_USTRINGPARAM ( "OutputStream" ) );
2692 const OUString sStream ( RTL_CONSTASCII_USTRINGPARAM ( "StreamForOutput" ) );
2693 BOOL bHasOutputStream = FALSE;
2694 BOOL bHasStream = FALSE;
2695 BOOL bHasBaseURL = FALSE;
2696 sal_Int32 i;
2697 sal_Int32 nEnd = aOldArgs.getLength();
2699 for ( i = 0; i < nEnd; i++ )
2701 pNewValue[i] = pOldValue[i];
2702 if ( pOldValue[i].Name.equalsAsciiL ( RTL_CONSTASCII_STRINGPARAM ( "FileName" ) ) )
2703 pNewValue[i].Value <<= OUString ( rMedium.GetName() );
2704 else if ( pOldValue[i].Name == sOutputStream )
2705 bHasOutputStream = sal_True;
2706 else if ( pOldValue[i].Name == sStream )
2707 bHasStream = sal_True;
2708 else if ( pOldValue[i].Name.equalsAsciiL ( RTL_CONSTASCII_STRINGPARAM ( "DocumentBaseURL" ) ) )
2709 bHasBaseURL = sal_True;
2712 if ( !bHasOutputStream )
2714 aArgs.realloc ( ++nEnd );
2715 aArgs[nEnd-1].Name = sOutputStream;
2716 aArgs[nEnd-1].Value <<= com::sun::star::uno::Reference < com::sun::star::io::XOutputStream > ( new utl::OOutputStreamWrapper ( *rMedium.GetOutStream() ) );
2719 // add stream as well, for OOX export and maybe others
2720 if ( !bHasStream )
2722 aArgs.realloc ( ++nEnd );
2723 aArgs[nEnd-1].Name = sStream;
2724 aArgs[nEnd-1].Value <<= com::sun::star::uno::Reference < com::sun::star::io::XStream > ( new utl::OStreamWrapper ( *rMedium.GetOutStream() ) );
2727 if ( !bHasBaseURL )
2729 aArgs.realloc ( ++nEnd );
2730 aArgs[nEnd-1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "DocumentBaseURL" ) );
2731 aArgs[nEnd-1].Value <<= rMedium.GetBaseURL( sal_True );
2734 return xFilter->filter( aArgs );
2735 }catch(const uno::Exception&)
2739 return sal_False;
2742 //-------------------------------------------------------------------------
2744 sal_Bool SfxObjectShell::ConvertTo
2746 SfxMedium& /*rMedium*/ /* <SfxMedium>, welches die Ziel-Datei beschreibt
2747 (z.B. Dateiname, <SfxFilter>, Open-Modi etc.) */
2750 /* [Beschreibung]
2752 Diese Methode wird zum Speichern von Dokumenten "uber alle Filter gerufen,
2753 die nicht SFX_FILTER_OWN sind oder f"ur die kein Clipboard-Format
2754 registriert wurde (also kein Storage-Format benutzen). Mit anderen Worten:
2755 mit dieser Methode wird exportiert.
2757 Das hier zu "offende File sollte "uber 'rMedium' ge"offnet werden,
2758 um die richtigen Open-Modi zu gew"ahrleisten. Insbesondere wenn das
2759 Format beibehalten wird (nur m"oglich bei SFX_FILTER_SIMULATE oder
2760 SFX_FILTER_ONW) mu\s die Datei auch nach dem Speichern im Modus
2761 STREAM_SHARE_DENYWRITE ge"offnet bleiben.
2764 [R"uckgabewert]
2766 sal_Bool sal_True
2767 Das Dokument konnte gespeichert werden.
2769 sal_False
2770 Das Dokument konnte nicht gespeichert werden, ein
2771 Fehlercode ist mit <SvMedium::GetError()const> zu
2772 erhalten.
2775 [Beispiel]
2777 sal_Bool DocSh::ConvertTo( SfxMedium &rMedium )
2779 SvStreamRef xStream = rMedium.GetOutStream();
2780 if ( xStream.is() )
2782 xStream->SetBufferSize(4096);
2783 *xStream << ...;
2785 rMedium.CloseOutStream(); // "offnet automatisch wieder den InStream
2786 return SVSTREAM_OK == rMedium.GetError();
2788 return sal_False ;
2792 [Querverweise]
2794 <SfxObjectShell::ConvertFrom(SfxMedium&)>
2795 <SFX_FILTER_REGISTRATION>
2799 return sal_False;
2802 //-------------------------------------------------------------------------
2804 sal_Bool SfxObjectShell::DoSave_Impl( const SfxItemSet* pArgs )
2806 SfxMedium* pRetrMedium = GetMedium();
2807 const SfxFilter* pFilter = pRetrMedium->GetFilter();
2809 // copy the original itemset, but remove the "version" item, because pMediumTmp
2810 // is a new medium "from scratch", so no version should be stored into it
2811 SfxItemSet* pSet = new SfxAllItemSet(*pRetrMedium->GetItemSet());
2812 pSet->ClearItem( SID_VERSION );
2814 // create a medium as a copy; this medium is only for writingm, because it uses the same name as the original one
2815 // writing is done through a copy, that will be transferred to the target ( of course after calling HandsOff )
2816 SfxMedium* pMediumTmp = new SfxMedium( pRetrMedium->GetName(), pRetrMedium->GetOpenMode(), pRetrMedium->IsDirect(), pFilter, pSet );
2817 pMediumTmp->SetLongName( pRetrMedium->GetLongName() );
2818 // pMediumTmp->CreateTempFileNoCopy();
2819 if ( pMediumTmp->GetErrorCode() != ERRCODE_NONE )
2821 SetError( pMediumTmp->GetError(), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
2822 delete pMediumTmp;
2823 return sal_False;
2826 // copy version list from "old" medium to target medium, so it can be used on saving
2827 pMediumTmp->TransferVersionList_Impl( *pRetrMedium );
2829 if ( pFilter && ( pFilter->GetFilterFlags() & SFX_FILTER_PACKED ) )
2830 SetError( GetMedium()->Unpack_Impl( pRetrMedium->GetPhysicalName() ), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
2833 // an interaction handler here can aquire only in case of GUI Saving
2834 // and should be removed after the saving is done
2835 com::sun::star::uno::Reference< XInteractionHandler > xInteract;
2836 SFX_ITEMSET_ARG( pArgs, pxInteractionItem, SfxUnoAnyItem, SID_INTERACTIONHANDLER, sal_False );
2837 if ( pxInteractionItem && ( pxInteractionItem->GetValue() >>= xInteract ) && xInteract.is() )
2838 pMediumTmp->GetItemSet()->Put( SfxUnoAnyItem( SID_INTERACTIONHANDLER, makeAny( xInteract ) ) );
2840 sal_Bool bSaved = sal_False;
2841 if( !GetError() && SaveTo_Impl( *pMediumTmp, pArgs ) )
2843 bSaved = sal_True;
2845 if( pMediumTmp->GetItemSet() )
2847 pMediumTmp->GetItemSet()->ClearItem( SID_INTERACTIONHANDLER );
2848 pMediumTmp->GetItemSet()->ClearItem( SID_PROGRESS_STATUSBAR_CONTROL );
2851 SetError(pMediumTmp->GetErrorCode(), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
2853 //REMOVE if ( !IsHandsOff() )
2854 //REMOVE pMediumTmp->Close();
2856 sal_Bool bOpen( sal_False );
2857 bOpen = DoSaveCompleted( pMediumTmp );
2858 DBG_ASSERT(bOpen,"Fehlerbehandlung fuer DoSaveCompleted nicht implementiert");
2860 else
2862 // transfer error code from medium to objectshell
2863 SetError( pMediumTmp->GetError(), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
2865 // reconnect to object storage
2866 //REMOVE if ( IsHandsOff() )
2867 //REMOVE {
2868 //REMOVE if ( !DoSaveCompleted( pRetrMedium ) )
2869 //REMOVE DBG_ERROR("Case not handled - no way to get a storage!");
2870 //REMOVE }
2871 //REMOVE else
2872 DoSaveCompleted( 0 );
2874 if( pRetrMedium->GetItemSet() )
2876 pRetrMedium->GetItemSet()->ClearItem( SID_INTERACTIONHANDLER );
2877 pRetrMedium->GetItemSet()->ClearItem( SID_PROGRESS_STATUSBAR_CONTROL );
2880 delete pMediumTmp;
2883 SetModified( !bSaved );
2884 return bSaved;
2887 //-------------------------------------------------------------------------
2889 sal_Bool SfxObjectShell::Save_Impl( const SfxItemSet* pSet )
2891 if ( IsReadOnly() )
2893 SetError( ERRCODE_SFX_DOCUMENTREADONLY, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
2894 return sal_False;
2897 DBG_CHKTHIS(SfxObjectShell, 0);
2899 pImp->bIsSaving = sal_True;
2900 sal_Bool bSaved = FALSE;
2901 SFX_ITEMSET_ARG( GetMedium()->GetItemSet(), pSalvageItem, SfxStringItem, SID_DOC_SALVAGE, sal_False);
2902 if ( pSalvageItem )
2904 SFX_ITEMSET_ARG( GetMedium()->GetItemSet(), pFilterItem, SfxStringItem, SID_FILTER_NAME, sal_False);
2905 String aFilterName;
2906 const SfxFilter *pFilter = NULL;
2907 if ( pFilterItem )
2908 pFilter = SfxFilterMatcher( String::CreateFromAscii( GetFactory().GetShortName()) ).GetFilter4FilterName( aFilterName );
2910 SfxMedium *pMed = new SfxMedium(
2911 pSalvageItem->GetValue(), STREAM_READWRITE | STREAM_SHARE_DENYWRITE | STREAM_TRUNC, sal_False, pFilter );
2913 SFX_ITEMSET_ARG( GetMedium()->GetItemSet(), pPasswordItem, SfxStringItem, SID_PASSWORD, sal_False );
2914 if ( pPasswordItem )
2915 pMed->GetItemSet()->Put( *pPasswordItem );
2917 bSaved = DoSaveAs( *pMed );
2918 if ( bSaved )
2919 bSaved = DoSaveCompleted( pMed );
2920 else
2921 delete pMed;
2923 else
2924 bSaved = DoSave_Impl( pSet );
2925 return bSaved;
2928 //-------------------------------------------------------------------------
2930 sal_Bool SfxObjectShell::CommonSaveAs_Impl
2932 const INetURLObject& aURL,
2933 const String& aFilterName,
2934 SfxItemSet* aParams
2937 if( aURL.HasError() )
2939 SetError( ERRCODE_IO_INVALIDPARAMETER, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
2940 return sal_False;
2943 if ( aURL != INetURLObject( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "private:stream" ) ) ) )
2945 // gibt es schon ein Doc mit dem Namen?
2946 SfxObjectShell* pDoc = 0;
2947 for ( SfxObjectShell* pTmp = SfxObjectShell::GetFirst();
2948 pTmp && !pDoc;
2949 pTmp = SfxObjectShell::GetNext(*pTmp) )
2951 if( ( pTmp != this ) && pTmp->GetMedium() )
2953 INetURLObject aCompare( pTmp->GetMedium()->GetName() );
2954 if ( aCompare == aURL )
2955 pDoc = pTmp;
2958 if ( pDoc )
2960 // dann Fehlermeldeung: "schon offen"
2961 SetError(ERRCODE_SFX_ALREADYOPEN, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ));
2962 return sal_False;
2966 DBG_ASSERT( aURL.GetProtocol() != INET_PROT_NOT_VALID, "Illegal URL!" );
2967 DBG_ASSERT( aParams->Count() != 0, "fehlerhafte Parameter");
2969 SFX_ITEMSET_ARG( aParams, pSaveToItem, SfxBoolItem, SID_SAVETO, sal_False );
2970 sal_Bool bSaveTo = pSaveToItem ? pSaveToItem->GetValue() : sal_False;
2972 const SfxFilter* pFilter = GetFactory().GetFilterContainer()->GetFilter4FilterName( aFilterName );
2973 if ( !pFilter
2974 || !pFilter->CanExport()
2975 || (!bSaveTo && !pFilter->CanImport()) )
2977 SetError( ERRCODE_IO_INVALIDPARAMETER, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
2978 return sal_False;
2981 SFX_ITEMSET_ARG( aParams, pCopyStreamItem, SfxBoolItem, SID_COPY_STREAM_IF_POSSIBLE, sal_False );
2982 if ( bSaveTo && pCopyStreamItem && pCopyStreamItem->GetValue() && !IsModified() )
2984 if ( pMedium->TryDirectTransfer( aURL.GetMainURL( INetURLObject::NO_DECODE ), *aParams ) )
2985 return sal_True;
2987 aParams->ClearItem( SID_COPY_STREAM_IF_POSSIBLE );
2989 pImp->bPasswd = aParams && SFX_ITEM_SET == aParams->GetItemState(SID_PASSWORD);
2991 SfxMedium *pActMed = GetMedium();
2992 const INetURLObject aActName(pActMed->GetName());
2994 BOOL bWasReadonly = IsReadOnly();
2996 if ( aURL == aActName && aURL != INetURLObject( OUString::createFromAscii( "private:stream" ) )
2997 && IsReadOnly() )
2999 SetError(ERRCODE_SFX_DOCUMENTREADONLY, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ));
3000 return sal_False;
3003 // this notification should be already sent by caller in sfxbasemodel
3004 // SFX_APP()->NotifyEvent(SfxEventHint( bSaveTo? SFX_EVENT_SAVETODOC : SFX_EVENT_SAVEASDOC,this));
3006 if( SFX_ITEM_SET != aParams->GetItemState(SID_UNPACK) && SvtSaveOptions().IsSaveUnpacked() )
3007 aParams->Put( SfxBoolItem( SID_UNPACK, sal_False ) );
3009 ::rtl::OUString aTempFileURL;
3010 if ( IsDocShared() )
3011 aTempFileURL = pMedium->GetURLObject().GetMainURL( INetURLObject::NO_DECODE );
3013 if ( PreDoSaveAs_Impl(aURL.GetMainURL( INetURLObject::NO_DECODE ),aFilterName,aParams))
3015 pImp->bWaitingForPicklist = sal_True;
3017 // Daten am Medium updaten
3018 SfxItemSet *pSet = GetMedium()->GetItemSet();
3019 pSet->ClearItem( SID_INTERACTIONHANDLER );
3020 pSet->ClearItem( SID_PROGRESS_STATUSBAR_CONTROL );
3021 pSet->ClearItem( SID_STANDARD_DIR );
3022 pSet->ClearItem( SID_PATH );
3024 if ( !bSaveTo )
3026 pSet->ClearItem( SID_REFERER );
3027 pSet->ClearItem( SID_POSTDATA );
3028 pSet->ClearItem( SID_TEMPLATE );
3029 pSet->ClearItem( SID_DOC_READONLY );
3030 pSet->ClearItem( SID_CONTENTTYPE );
3031 pSet->ClearItem( SID_CHARSET );
3032 pSet->ClearItem( SID_FILTER_NAME );
3033 pSet->ClearItem( SID_OPTIONS );
3034 //pSet->ClearItem( SID_FILE_FILTEROPTIONS );
3035 pSet->ClearItem( SID_VERSION );
3036 //pSet->ClearItem( SID_USE_FILTEROPTIONS );
3037 pSet->ClearItem( SID_EDITDOC );
3038 pSet->ClearItem( SID_OVERWRITE );
3039 pSet->ClearItem( SID_DEFAULTFILEPATH );
3040 pSet->ClearItem( SID_DEFAULTFILENAME );
3042 SFX_ITEMSET_GET( (*aParams), pFilterItem, SfxStringItem, SID_FILTER_NAME, sal_False );
3043 if ( pFilterItem )
3044 pSet->Put( *pFilterItem );
3046 SFX_ITEMSET_GET( (*aParams), pOptionsItem, SfxStringItem, SID_OPTIONS, sal_False );
3047 if ( pOptionsItem )
3048 pSet->Put( *pOptionsItem );
3050 SFX_ITEMSET_GET( (*aParams), pFilterOptItem, SfxStringItem, SID_FILE_FILTEROPTIONS, sal_False );
3051 if ( pFilterOptItem )
3052 pSet->Put( *pFilterOptItem );
3054 if ( IsDocShared() && aTempFileURL.getLength() )
3056 // this is a shared document that has to be disconnected from the old location
3057 FreeSharedFile( aTempFileURL );
3059 if ( pFilter->IsOwnFormat()
3060 && pFilter->UsesStorage()
3061 && pFilter->GetVersion() >= SOFFICE_FILEFORMAT_60 )
3063 // the target format is the own format
3064 // the target document must be shared
3065 SwitchToShared( sal_True, sal_False );
3070 if ( bWasReadonly && !bSaveTo )
3071 Broadcast( SfxSimpleHint(SFX_HINT_MODECHANGED) );
3073 return sal_True;
3075 else
3076 return sal_False;
3079 //-------------------------------------------------------------------------
3081 sal_Bool SfxObjectShell::PreDoSaveAs_Impl
3083 const String& rFileName,
3084 const String& aFilterName,
3085 SfxItemSet* pParams
3088 // copy all items stored in the itemset of the current medium
3089 SfxAllItemSet* pMergedParams = new SfxAllItemSet( *pMedium->GetItemSet() );
3091 // in "SaveAs" title and password will be cleared ( maybe the new itemset contains new values, otherwise they will be empty )
3092 pMergedParams->ClearItem( SID_PASSWORD );
3093 pMergedParams->ClearItem( SID_DOCINFO_TITLE );
3095 pMergedParams->ClearItem( SID_INPUTSTREAM );
3096 pMergedParams->ClearItem( SID_STREAM );
3097 pMergedParams->ClearItem( SID_CONTENT );
3098 pMergedParams->ClearItem( SID_DOC_READONLY );
3100 pMergedParams->ClearItem( SID_REPAIRPACKAGE );
3102 // "SaveAs" will never store any version information - it's a complete new file !
3103 pMergedParams->ClearItem( SID_VERSION );
3105 // merge the new parameters into the copy
3106 // all values present in both itemsets will be overwritten by the new parameters
3107 if( pParams )
3108 pMergedParams->Put( *pParams );
3109 //DELETEZ( pParams );
3111 #ifdef DBG_UTIL
3112 if ( pMergedParams->GetItemState( SID_DOC_SALVAGE) >= SFX_ITEM_SET )
3113 DBG_ERROR("Salvage item present in Itemset, check the parameters!");
3114 #endif
3116 // should be unneccessary - too hot to handle!
3117 pMergedParams->ClearItem( SID_DOC_SALVAGE );
3119 // take over the new merged itemset
3120 pParams = pMergedParams;
3122 // create a medium for the target URL
3123 SfxMedium *pNewFile = new SfxMedium( rFileName, STREAM_READWRITE | STREAM_SHARE_DENYWRITE | STREAM_TRUNC, sal_False, 0, pParams );
3125 // set filter; if no filter is given, take the default filter of the factory
3126 if ( aFilterName.Len() )
3127 pNewFile->SetFilter( GetFactory().GetFilterContainer()->GetFilter4FilterName( aFilterName ) );
3128 else
3129 pNewFile->SetFilter( GetFactory().GetFilterContainer()->GetAnyFilter( SFX_FILTER_IMPORT | SFX_FILTER_EXPORT ) );
3131 //REMOVE // saving is alway done using a temporary file
3132 //REMOVE pNewFile->CreateTempFileNoCopy();
3133 if ( pNewFile->GetErrorCode() != ERRCODE_NONE )
3135 // creating temporary file failed ( f.e. floppy disk not inserted! )
3136 SetError( pNewFile->GetError(), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
3137 delete pNewFile;
3138 return sal_False;
3141 // check if a "SaveTo" is wanted, no "SaveAs"
3142 SFX_ITEMSET_ARG( pParams, pSaveToItem, SfxBoolItem, SID_SAVETO, sal_False );
3143 sal_Bool bCopyTo = GetCreateMode() == SFX_CREATE_MODE_EMBEDDED || (pSaveToItem && pSaveToItem->GetValue());
3145 // distinguish between "Save" and "SaveAs"
3146 pImp->bIsSaving = sal_False;
3148 // copy version list from "old" medium to target medium, so it can be used on saving
3149 if ( pImp->bPreserveVersions )
3150 pNewFile->TransferVersionList_Impl( *pMedium );
3153 if ( GetMedium()->GetFilter() && ( GetMedium()->GetFilter()->GetFilterFlags() & SFX_FILTER_PACKED ) )
3155 SfxMedium *pMed = bCopyTo ? pMedium : pNewFile;
3156 pNewFile->SetError( GetMedium()->Unpack_Impl( pMed->GetPhysicalName() ) , ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
3159 // Save the document ( first as temporary file, then transfer to the target URL by committing the medium )
3160 sal_Bool bOk = sal_False;
3161 if ( !pNewFile->GetErrorCode() && SaveTo_Impl( *pNewFile, NULL ) )
3163 bOk = sal_True;
3165 // transfer a possible error from the medium to the document
3166 SetError( pNewFile->GetErrorCode(), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
3168 // notify the document that saving was done successfully
3169 //REMOVE if ( bCopyTo )
3170 //REMOVE {
3171 //REMOVE if ( IsHandsOff() )
3172 //REMOVE bOk = DoSaveCompleted( pMedium );
3173 //REMOVE }
3174 //REMOVE else
3175 if ( !bCopyTo )
3177 // Muss !!!
3178 //REMOVE if ( bToOwnFormat )
3179 //REMOVE SetFileName( pNewFile->GetPhysicalName() );
3181 bOk = DoSaveCompleted( pNewFile );
3183 else
3184 bOk = DoSaveCompleted(0);
3186 if( bOk )
3188 if( !bCopyTo )
3189 SetModified( sal_False );
3191 else
3193 // TODO/LATER: the code below must be dead since the storage commit makes all the stuff
3194 // and the DoSaveCompleted call should not be able to fail in general
3196 DBG_ASSERT( !bCopyTo, "Error while reconnecting to medium, can't be handled!");
3197 SetError( pNewFile->GetErrorCode(), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
3199 if ( !bCopyTo )
3201 // reconnect to the old medium
3202 BOOL bRet( FALSE );
3203 bRet = DoSaveCompleted( pMedium );
3204 DBG_ASSERT( bRet, "Error in DoSaveCompleted, can't be handled!");
3207 // TODO/LATER: disconnect the new file from the storage for the case when pure saving is done
3208 // if storing has corrupted the file, probably it must be restored either here or
3209 // by the storage
3210 DELETEZ( pNewFile );
3213 // TODO/LATER: there is no need in the following code in case HandsOff is not used,
3214 // hope we will not have to introduce it back
3215 //REMOVE String aPasswd;
3216 //REMOVE if ( IsOwnStorageFormat_Impl( *GetMedium() ) && GetPasswd_Impl( GetMedium()->GetItemSet(), aPasswd ) )
3217 //REMOVE {
3218 //REMOVE try
3219 //REMOVE {
3220 //REMOVE // the following code must throw an exception in case of failure
3221 //REMOVE ::comphelper::OStorageHelper::SetCommonStoragePassword( GetMedium->GetStorage(), aPasswd );
3222 //REMOVE }
3223 //REMOVE catch( uno::Exception& )
3224 //REMOVE {
3225 //REMOVE // TODO: handle the error
3226 //REMOVE }
3227 //REMOVE }
3229 else
3231 SetError( pNewFile->GetErrorCode(), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
3233 //REMOVE // reconnect to the old storage
3234 //REMOVE if ( IsHandsOff() )
3235 //REMOVE DoSaveCompleted( pMedium );
3236 //REMOVE else
3237 DoSaveCompleted( 0 );
3239 DELETEZ( pNewFile );
3242 if ( bCopyTo )
3243 DELETEZ( pNewFile );
3244 else if( !bOk )
3245 SetModified( sal_True );
3247 return bOk;
3250 //------------------------------------------------------------------------
3252 sal_Bool SfxObjectShell::LoadFrom( SfxMedium& /*rMedium*/ )
3254 DBG_ERROR( "Base implementation, must not be called in general!" );
3255 return sal_True;
3258 //-------------------------------------------------------------------------
3259 sal_Bool SfxObjectShell::IsInformationLost()
3261 Sequence< PropertyValue > aProps = GetModel()->getArgs();
3262 ::rtl::OUString aFilterName;
3263 ::rtl::OUString aPreusedFilterName;
3264 for ( sal_Int32 nInd = 0; nInd < aProps.getLength(); nInd++ )
3266 if ( aProps[nInd].Name.equalsAscii( "FilterName" ) )
3267 aProps[nInd].Value >>= aFilterName;
3268 else if ( aProps[nInd].Name.equalsAscii( "PreusedFilterName" ) )
3269 aProps[nInd].Value >>= aPreusedFilterName;
3272 // if current filter can lead to information loss and it was used
3273 // for the latest store then the user should be asked to store in own format
3274 if ( aFilterName.getLength() && aFilterName.equals( aPreusedFilterName ) )
3276 const SfxFilter *pFilt = GetMedium()->GetFilter();
3277 DBG_ASSERT( pFilt && aFilterName.equals( pFilt->GetName() ), "MediaDescriptor contains wrong filter!\n" );
3278 return ( pFilt && pFilt->IsAlienFormat() && !(pFilt->GetFilterFlags() & SFX_FILTER_SILENTEXPORT ) );
3281 return sal_False;
3284 //-------------------------------------------------------------------------
3285 sal_Bool SfxObjectShell::CanReload_Impl()
3287 /* [Beschreibung]
3289 Interne Methode zum Feststellen, ob eine erneutes Laden des
3290 Dokuments (auch als RevertToSaved oder LastVersion bekannt)
3291 m"oglich ist.
3295 return pMedium && HasName() && !IsInModalMode() && !pImp->bForbidReload;
3298 //-------------------------------------------------------------------------
3300 sal_uInt16 SfxObjectShell::GetHiddenInformationState( sal_uInt16 nStates )
3302 sal_uInt16 nState = 0;
3303 if ( nStates & HIDDENINFORMATION_DOCUMENTVERSIONS )
3305 if ( GetMedium()->GetVersionList().getLength() )
3306 nState |= HIDDENINFORMATION_DOCUMENTVERSIONS;
3309 return nState;
3312 sal_Int16 SfxObjectShell::QueryHiddenInformation( HiddenWarningFact eFact, Window* pParent )
3314 sal_Int16 nRet = RET_YES;
3315 USHORT nResId = 0;
3316 SvtSecurityOptions::EOption eOption = static_cast< SvtSecurityOptions::EOption >( -1 );
3318 switch ( eFact )
3320 case WhenSaving :
3322 nResId = STR_HIDDENINFO_CONTINUE_SAVING;
3323 eOption = SvtSecurityOptions::E_DOCWARN_SAVEORSEND;
3324 break;
3326 case WhenPrinting :
3328 nResId = STR_HIDDENINFO_CONTINUE_PRINTING;
3329 eOption = SvtSecurityOptions::E_DOCWARN_PRINT;
3330 break;
3332 case WhenSigning :
3334 nResId = STR_HIDDENINFO_CONTINUE_SIGNING;
3335 eOption = SvtSecurityOptions::E_DOCWARN_SIGNING;
3336 break;
3338 case WhenCreatingPDF :
3340 nResId = STR_HIDDENINFO_CONTINUE_CREATEPDF;
3341 eOption = SvtSecurityOptions::E_DOCWARN_CREATEPDF;
3342 break;
3344 default:
3346 DBG_ERRORFILE( "SfxObjectShell::DetectHiddenInformation(): what fact?" );
3350 if ( eOption != -1 && SvtSecurityOptions().IsOptionSet( eOption ) )
3352 String sMessage( SfxResId( STR_HIDDENINFO_CONTAINS ) );
3353 sal_uInt16 nWantedStates = HIDDENINFORMATION_RECORDEDCHANGES | HIDDENINFORMATION_NOTES;
3354 if ( eFact != WhenPrinting )
3355 nWantedStates |= HIDDENINFORMATION_DOCUMENTVERSIONS;
3356 sal_uInt16 nStates = GetHiddenInformationState( nWantedStates );
3357 bool bWarning = false;
3359 if ( ( nStates & HIDDENINFORMATION_RECORDEDCHANGES ) == HIDDENINFORMATION_RECORDEDCHANGES )
3361 sMessage += String( SfxResId( STR_HIDDENINFO_RECORDCHANGES ) );
3362 sMessage += '\n';
3363 bWarning = true;
3365 if ( ( nStates & HIDDENINFORMATION_NOTES ) == HIDDENINFORMATION_NOTES )
3367 sMessage += String( SfxResId( STR_HIDDENINFO_NOTES ) );
3368 sMessage += '\n';
3369 bWarning = true;
3371 if ( ( nStates & HIDDENINFORMATION_DOCUMENTVERSIONS ) == HIDDENINFORMATION_DOCUMENTVERSIONS )
3373 sMessage += String( SfxResId( STR_HIDDENINFO_DOCVERSIONS ) );
3374 sMessage += '\n';
3375 bWarning = true;
3378 if ( bWarning )
3380 sMessage += '\n';
3381 sMessage += String( SfxResId( nResId ) );
3382 WarningBox aWBox( pParent, WB_YES_NO | WB_DEF_NO, sMessage );
3383 nRet = aWBox.Execute();
3387 return nRet;
3390 sal_Bool SfxObjectShell::HasSecurityOptOpenReadOnly() const
3392 return sal_True;
3395 sal_Bool SfxObjectShell::IsSecurityOptOpenReadOnly() const
3397 return IsLoadReadonly();
3400 void SfxObjectShell::SetSecurityOptOpenReadOnly( sal_Bool _b )
3402 SetLoadReadonly( _b );
3405 sal_Bool SfxObjectShell::LoadOwnFormat( SfxMedium& rMedium )
3407 RTL_LOGFILE_PRODUCT_CONTEXT( aLog, "PERFORMANCE SfxObjectShell::LoadOwnFormat" );
3408 if( RTL_LOGFILE_HASLOGFILE() )
3410 ByteString aString( rMedium.GetName(), RTL_TEXTENCODING_ASCII_US );
3411 RTL_LOGFILE_PRODUCT_CONTEXT_TRACE1( aLog, "loading \"%s\"", aString.GetBuffer() );
3414 uno::Reference< embed::XStorage > xStorage = rMedium.GetStorage();
3415 if ( xStorage.is() )
3417 //REMOVE if ( rMedium.GetFileVersion() )
3418 //REMOVE xStor->SetVersion( rMedium.GetFileVersion() );
3420 // Password
3421 SFX_ITEMSET_ARG( rMedium.GetItemSet(), pPasswdItem, SfxStringItem, SID_PASSWORD, sal_False );
3422 if ( pPasswdItem || ERRCODE_IO_ABORT != CheckPasswd_Impl( this, SFX_APP()->GetPool(), pMedium ) )
3424 ::rtl::OUString aPasswd;
3425 if ( GetPasswd_Impl(pMedium->GetItemSet(), aPasswd) )
3429 // the following code must throw an exception in case of failure
3430 ::comphelper::OStorageHelper::SetCommonStoragePassword( xStorage, aPasswd );
3432 catch( uno::Exception& )
3434 // TODO/LATER: handle the error code
3438 // load document
3439 return Load( rMedium );
3441 return sal_False;
3443 else
3444 return sal_False;
3447 sal_Bool SfxObjectShell::SaveAsOwnFormat( SfxMedium& rMedium )
3449 uno::Reference< embed::XStorage > xStorage = rMedium.GetStorage();
3450 if( xStorage.is() )
3452 sal_Int32 nVersion = rMedium.GetFilter()->GetVersion();
3454 // OASIS templates have own mediatypes ( SO7 also actually, but it is to late to use them here )
3455 sal_Bool bTemplate = ( rMedium.GetFilter()->IsOwnTemplateFormat() && nVersion > SOFFICE_FILEFORMAT_60 );
3457 SetupStorage( xStorage, nVersion, bTemplate );
3459 if ( HasBasic() )
3461 // Initialize Basic
3462 GetBasicManager();
3464 // Save dialog/script container
3465 pImp->pBasicManager->storeLibrariesToStorage( xStorage );
3468 return SaveAs( rMedium );
3470 else return sal_False;
3473 uno::Reference< embed::XStorage > SfxObjectShell::GetStorage()
3475 if ( !pImp->m_xDocStorage.is() )
3477 OSL_ENSURE( pImp->m_bCreateTempStor, "The storage must exist already!\n" );
3478 try {
3479 // no notification is required the storage is set the first time
3480 pImp->m_xDocStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
3481 OSL_ENSURE( pImp->m_xDocStorage.is(), "The method must either return storage or throw an exception!" );
3483 SetupStorage( pImp->m_xDocStorage, SOFFICE_FILEFORMAT_CURRENT, sal_False );
3484 pImp->m_bCreateTempStor = sal_False;
3485 SFX_APP()->NotifyEvent( SfxEventHint( SFX_EVENT_STORAGECHANGED, GlobalEventConfig::GetEventName(STR_EVENT_STORAGECHANGED), this ) );
3487 catch( uno::Exception& )
3489 // TODO/LATER: error handling?
3493 OSL_ENSURE( pImp->m_xDocStorage.is(), "The document storage must be created!" );
3494 return pImp->m_xDocStorage;
3498 sal_Bool SfxObjectShell::SaveChildren( BOOL bObjectsOnly )
3500 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SaveChildren" );
3502 sal_Bool bResult = sal_True;
3503 if ( pImp->mpObjectContainer )
3505 sal_Bool bOasis = ( SotStorage::GetVersion( GetStorage() ) > SOFFICE_FILEFORMAT_60 );
3506 GetEmbeddedObjectContainer().StoreChildren(bOasis,bObjectsOnly);
3509 return bResult;
3512 sal_Bool SfxObjectShell::SaveAsChildren( SfxMedium& rMedium )
3514 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SaveAsChildren" );
3516 sal_Bool bResult = sal_True;
3518 uno::Reference < embed::XStorage > xStorage = rMedium.GetStorage();
3519 if ( !xStorage.is() )
3520 return sal_False;
3522 if ( xStorage == GetStorage() )
3523 return SaveChildren();
3525 sal_Bool bOasis = sal_True;
3526 if ( pImp->mpObjectContainer )
3528 bOasis = ( SotStorage::GetVersion( xStorage ) > SOFFICE_FILEFORMAT_60 );
3529 GetEmbeddedObjectContainer().StoreAsChildren(bOasis,SFX_CREATE_MODE_EMBEDDED == eCreateMode,xStorage);
3532 if ( bResult )
3533 bResult = CopyStoragesOfUnknownMediaType( GetStorage(), xStorage );
3535 return bResult;
3538 sal_Bool SfxObjectShell::SaveCompletedChildren( sal_Bool bSuccess )
3540 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SaveCompletedChildren" );
3542 sal_Bool bResult = sal_True;
3544 if ( pImp->mpObjectContainer )
3546 uno::Sequence < ::rtl::OUString > aNames = GetEmbeddedObjectContainer().GetObjectNames();
3547 for ( sal_Int32 n=0; n<aNames.getLength(); n++ )
3549 uno::Reference < embed::XEmbeddedObject > xObj = GetEmbeddedObjectContainer().GetEmbeddedObject( aNames[n] );
3550 OSL_ENSURE( xObj.is(), "An empty entry in the embedded objects list!\n" );
3551 if ( xObj.is() )
3553 uno::Reference< embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
3554 if ( xPersist.is() )
3558 xPersist->saveCompleted( bSuccess );
3560 catch( uno::Exception& )
3562 // TODO/LATER: error handling
3563 bResult = sal_False;
3564 break;
3571 return bResult;
3574 sal_Bool SfxObjectShell::SwitchChildrenPersistance( const uno::Reference< embed::XStorage >& xStorage,
3575 sal_Bool bForceNonModified )
3577 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SwitchChildrenPersistence" );
3579 if ( !xStorage.is() )
3581 // TODO/LATER: error handling
3582 return sal_False;
3585 sal_Bool bResult = sal_True;
3587 if ( pImp->mpObjectContainer )
3588 pImp->mpObjectContainer->SetPersistentEntries(xStorage,bForceNonModified);
3590 return bResult;
3593 // Never call this method directly, always use the DoSaveCompleted call
3594 sal_Bool SfxObjectShell::SaveCompleted( const uno::Reference< embed::XStorage >& xStorage )
3596 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SaveCompleted" );
3598 sal_Bool bResult = sal_False;
3599 sal_Bool bSendNotification = sal_False;
3600 uno::Reference< embed::XStorage > xOldStorageHolder;
3602 #ifdef DBG_UTIL
3603 // check for wrong creation of object container
3604 BOOL bHasContainer = ( pImp->mpObjectContainer != 0 );
3605 #endif
3607 if ( !xStorage.is() || xStorage == GetStorage() )
3609 // no persistence change
3610 bResult = SaveCompletedChildren( sal_False );
3612 else
3614 if ( pImp->mpObjectContainer )
3615 GetEmbeddedObjectContainer().SwitchPersistence( xStorage );
3617 bResult = SwitchChildrenPersistance( xStorage, sal_True );
3620 if ( bResult )
3622 if ( xStorage.is() && pImp->m_xDocStorage != xStorage )
3624 // make sure that until the storage is assigned the object container is not created by accident!
3625 DBG_ASSERT( bHasContainer == (pImp->mpObjectContainer != 0), "Wrong storage in object container!" );
3626 xOldStorageHolder = pImp->m_xDocStorage;
3627 pImp->m_xDocStorage = xStorage;
3628 bSendNotification = sal_True;
3630 if ( IsEnableSetModified() )
3631 SetModified( sal_False );
3634 else
3636 if ( pImp->mpObjectContainer )
3637 GetEmbeddedObjectContainer().SwitchPersistence( pImp->m_xDocStorage );
3639 // let already successfully connected objects be switched back
3640 SwitchChildrenPersistance( pImp->m_xDocStorage, sal_True );
3643 if ( bSendNotification )
3645 SFX_APP()->NotifyEvent( SfxEventHint( SFX_EVENT_STORAGECHANGED, GlobalEventConfig::GetEventName(STR_EVENT_STORAGECHANGED), this ) );
3648 return bResult;
3652 sal_Bool StoragesOfUnknownMediaTypeAreCopied_Impl( const uno::Reference< embed::XStorage >& xSource,
3653 const uno::Reference< embed::XStorage >& xTarget )
3655 OSL_ENSURE( xSource.is() && xTarget.is(), "Source and/or target storages are not available!\n" );
3656 if ( !xSource.is() || !xTarget.is() || xSource == xTarget )
3657 return sal_True;
3661 uno::Sequence< ::rtl::OUString > aSubElements = xSource->getElementNames();
3662 for ( sal_Int32 nInd = 0; nInd < aSubElements.getLength(); nInd++ )
3664 if ( xSource->isStorageElement( aSubElements[nInd] ) )
3666 ::rtl::OUString aMediaType;
3667 ::rtl::OUString aMediaTypePropName( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) );
3668 sal_Bool bGotMediaType = sal_False;
3672 uno::Reference< embed::XOptimizedStorage > xOptStorage( xSource, uno::UNO_QUERY_THROW );
3673 bGotMediaType =
3674 ( xOptStorage->getElementPropertyValue( aSubElements[nInd], aMediaTypePropName ) >>= aMediaType );
3676 catch( uno::Exception& )
3679 if ( !bGotMediaType )
3681 uno::Reference< embed::XStorage > xSubStorage;
3682 try {
3683 xSubStorage = xSource->openStorageElement( aSubElements[nInd], embed::ElementModes::READ );
3684 } catch( uno::Exception& )
3687 if ( !xSubStorage.is() )
3689 xSubStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
3690 xSource->copyStorageElementLastCommitTo( aSubElements[nInd], xSubStorage );
3693 uno::Reference< beans::XPropertySet > xProps( xSubStorage, uno::UNO_QUERY_THROW );
3694 bGotMediaType = ( xProps->getPropertyValue( aMediaTypePropName ) >>= aMediaType );
3697 // TODO/LATER: there should be a way to detect whether an object with such a MediaType can exist
3698 // probably it should be placed in the MimeType-ClassID table or in standalone table
3699 if ( aMediaType.getLength()
3700 && aMediaType.compareToAscii( "application/vnd.sun.star.oleobject" ) != COMPARE_EQUAL )
3702 ::com::sun::star::datatransfer::DataFlavor aDataFlavor;
3703 aDataFlavor.MimeType = aMediaType;
3704 sal_uInt32 nFormat = SotExchange::GetFormat( aDataFlavor );
3706 switch ( nFormat )
3708 case SOT_FORMATSTR_ID_STARWRITER_60 :
3709 case SOT_FORMATSTR_ID_STARWRITERWEB_60 :
3710 case SOT_FORMATSTR_ID_STARWRITERGLOB_60 :
3711 case SOT_FORMATSTR_ID_STARDRAW_60 :
3712 case SOT_FORMATSTR_ID_STARIMPRESS_60 :
3713 case SOT_FORMATSTR_ID_STARCALC_60 :
3714 case SOT_FORMATSTR_ID_STARCHART_60 :
3715 case SOT_FORMATSTR_ID_STARMATH_60 :
3716 case SOT_FORMATSTR_ID_STARWRITER_8:
3717 case SOT_FORMATSTR_ID_STARWRITERWEB_8:
3718 case SOT_FORMATSTR_ID_STARWRITERGLOB_8:
3719 case SOT_FORMATSTR_ID_STARDRAW_8:
3720 case SOT_FORMATSTR_ID_STARIMPRESS_8:
3721 case SOT_FORMATSTR_ID_STARCALC_8:
3722 case SOT_FORMATSTR_ID_STARCHART_8:
3723 case SOT_FORMATSTR_ID_STARMATH_8:
3724 break;
3726 default:
3728 if ( !xTarget->hasByName( aSubElements[nInd] ) )
3729 return sal_False;
3736 catch( uno::Exception& )
3738 OSL_ENSURE( sal_False, "Cant check storage consistency!\n" );
3741 return sal_True;
3745 sal_Bool SfxObjectShell::SwitchPersistance( const uno::Reference< embed::XStorage >& xStorage )
3747 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SwitchPersistance" );
3749 sal_Bool bResult = sal_False;
3750 #ifdef DBG_UTIL
3751 // check for wrong creation of object container
3752 BOOL bHasContainer = ( pImp->mpObjectContainer != 0 );
3753 #endif
3754 if ( xStorage.is() )
3756 if ( pImp->mpObjectContainer )
3757 GetEmbeddedObjectContainer().SwitchPersistence( xStorage );
3758 bResult = SwitchChildrenPersistance( xStorage );
3760 // TODO/LATER: substorages that have unknown mimetypes probably should be copied to the target storage here
3761 OSL_ENSURE( StoragesOfUnknownMediaTypeAreCopied_Impl( pImp->m_xDocStorage, xStorage ),
3762 "Some of substorages with unknown mimetypes is lost!" );
3765 if ( bResult )
3767 // make sure that until the storage is assigned the object container is not created by accident!
3768 DBG_ASSERT( bHasContainer == (pImp->mpObjectContainer != 0), "Wrong storage in object container!" );
3769 if ( pImp->m_xDocStorage != xStorage )
3770 DoSaveCompleted( new SfxMedium( xStorage, GetMedium()->GetBaseURL() ) );
3772 if ( IsEnableSetModified() )
3773 SetModified( sal_True ); // ???
3776 return bResult;
3779 sal_Bool SfxObjectShell::CopyStoragesOfUnknownMediaType( const uno::Reference< embed::XStorage >& xSource,
3780 const uno::Reference< embed::XStorage >& xTarget )
3782 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::CopyStoragesOfUnknownMediaType" );
3784 // This method does not commit the target storage and should not do it
3785 sal_Bool bResult = sal_True;
3789 uno::Sequence< ::rtl::OUString > aSubElements = xSource->getElementNames();
3790 for ( sal_Int32 nInd = 0; nInd < aSubElements.getLength(); nInd++ )
3792 if ( aSubElements[nInd].equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Configurations" ) ) ) )
3794 // The workaround for compatibility with SO7, "Configurations" substorage must be preserved
3795 if ( xSource->isStorageElement( aSubElements[nInd] ) )
3797 OSL_ENSURE( !xTarget->hasByName( aSubElements[nInd] ),
3798 "The target storage is an output storage, the element should not exist in the target!\n" );
3800 xSource->copyElementTo( aSubElements[nInd], xTarget, aSubElements[nInd] );
3803 else if ( xSource->isStorageElement( aSubElements[nInd] ) )
3805 ::rtl::OUString aMediaType;
3806 ::rtl::OUString aMediaTypePropName( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) );
3807 sal_Bool bGotMediaType = sal_False;
3811 uno::Reference< embed::XOptimizedStorage > xOptStorage( xSource, uno::UNO_QUERY_THROW );
3812 bGotMediaType =
3813 ( xOptStorage->getElementPropertyValue( aSubElements[nInd], aMediaTypePropName ) >>= aMediaType );
3815 catch( uno::Exception& )
3818 if ( !bGotMediaType )
3820 uno::Reference< embed::XStorage > xSubStorage;
3821 try {
3822 xSubStorage = xSource->openStorageElement( aSubElements[nInd], embed::ElementModes::READ );
3823 } catch( uno::Exception& )
3826 if ( !xSubStorage.is() )
3828 // TODO/LATER: as optimization in future a substorage of target storage could be used
3829 // instead of the temporary storage; this substorage should be removed later
3830 // if the MimeType is wrong
3831 xSubStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
3832 xSource->copyStorageElementLastCommitTo( aSubElements[nInd], xSubStorage );
3835 uno::Reference< beans::XPropertySet > xProps( xSubStorage, uno::UNO_QUERY_THROW );
3836 bGotMediaType = ( xProps->getPropertyValue( aMediaTypePropName ) >>= aMediaType );
3839 // TODO/LATER: there should be a way to detect whether an object with such a MediaType can exist
3840 // probably it should be placed in the MimeType-ClassID table or in standalone table
3841 if ( aMediaType.getLength()
3842 && aMediaType.compareToAscii( "application/vnd.sun.star.oleobject" ) != COMPARE_EQUAL )
3844 ::com::sun::star::datatransfer::DataFlavor aDataFlavor;
3845 aDataFlavor.MimeType = aMediaType;
3846 sal_uInt32 nFormat = SotExchange::GetFormat( aDataFlavor );
3848 switch ( nFormat )
3850 case SOT_FORMATSTR_ID_STARWRITER_60 :
3851 case SOT_FORMATSTR_ID_STARWRITERWEB_60 :
3852 case SOT_FORMATSTR_ID_STARWRITERGLOB_60 :
3853 case SOT_FORMATSTR_ID_STARDRAW_60 :
3854 case SOT_FORMATSTR_ID_STARIMPRESS_60 :
3855 case SOT_FORMATSTR_ID_STARCALC_60 :
3856 case SOT_FORMATSTR_ID_STARCHART_60 :
3857 case SOT_FORMATSTR_ID_STARMATH_60 :
3858 case SOT_FORMATSTR_ID_STARWRITER_8:
3859 case SOT_FORMATSTR_ID_STARWRITERWEB_8:
3860 case SOT_FORMATSTR_ID_STARWRITERGLOB_8:
3861 case SOT_FORMATSTR_ID_STARDRAW_8:
3862 case SOT_FORMATSTR_ID_STARIMPRESS_8:
3863 case SOT_FORMATSTR_ID_STARCALC_8:
3864 case SOT_FORMATSTR_ID_STARCHART_8:
3865 case SOT_FORMATSTR_ID_STARMATH_8:
3866 break;
3868 default:
3870 OSL_ENSURE(
3871 aSubElements[nInd].equalsAscii( "Configurations2" ) || !xTarget->hasByName( aSubElements[nInd] ),
3872 "The target storage is an output storage, the element should not exist in the target!\n" );
3874 if ( !xTarget->hasByName( aSubElements[nInd] ) )
3876 xSource->copyElementTo( aSubElements[nInd], xTarget, aSubElements[nInd] );
3884 catch( uno::Exception& )
3886 bResult = sal_False;
3887 // TODO/LATER: a specific error could be provided
3890 return bResult;
3893 sal_Bool SfxObjectShell::GenerateAndStoreThumbnail( sal_Bool bEncrypted,
3894 sal_Bool bSigned,
3895 sal_Bool bIsTemplate,
3896 const uno::Reference< embed::XStorage >& xStor )
3898 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::GenerateAndStoreThumbnail" );
3900 sal_Bool bResult = sal_False;
3902 try {
3903 uno::Reference< embed::XStorage > xThumbnailStor =
3904 xStor->openStorageElement( ::rtl::OUString::createFromAscii( "Thumbnails" ),
3905 embed::ElementModes::READWRITE );
3906 if ( xThumbnailStor.is() )
3908 uno::Reference< io::XStream > xStream = xThumbnailStor->openStreamElement(
3909 ::rtl::OUString::createFromAscii( "thumbnail.png" ),
3910 embed::ElementModes::READWRITE );
3912 if ( xStream.is() && WriteThumbnail( bEncrypted, bSigned, bIsTemplate, xStream ) )
3914 uno::Reference< embed::XTransactedObject > xTransact( xThumbnailStor, uno::UNO_QUERY_THROW );
3915 xTransact->commit();
3916 bResult = sal_True;
3920 catch( uno::Exception& )
3924 return bResult;
3927 sal_Bool SfxObjectShell::WriteThumbnail( sal_Bool bEncrypted,
3928 sal_Bool bSigned,
3929 sal_Bool bIsTemplate,
3930 const uno::Reference< io::XStream >& xStream )
3932 sal_Bool bResult = sal_False;
3934 if ( xStream.is() )
3936 try {
3937 uno::Reference< io::XTruncate > xTruncate( xStream->getOutputStream(), uno::UNO_QUERY_THROW );
3938 xTruncate->truncate();
3940 if ( bEncrypted )
3942 sal_uInt16 nResID = GraphicHelper::getThumbnailReplacementIDByFactoryName_Impl(
3943 ::rtl::OUString::createFromAscii( GetFactory().GetShortName() ),
3944 bIsTemplate );
3945 if ( nResID )
3947 if ( !bSigned )
3949 bResult = GraphicHelper::getThumbnailReplacement_Impl( nResID, xStream );
3951 else
3953 // retrieve the bitmap and write a signature bitmap over it
3954 SfxResId aResId( nResID );
3955 BitmapEx aThumbBitmap( aResId );
3956 bResult = GraphicHelper::getSignedThumbnailFormatFromBitmap_Impl( aThumbBitmap, xStream );
3960 else
3962 ::boost::shared_ptr<GDIMetaFile> pMetaFile =
3963 GetPreviewMetaFile( sal_False );
3964 if ( pMetaFile )
3966 bResult = GraphicHelper::getThumbnailFormatFromGDI_Impl(
3967 pMetaFile.get(), bSigned, xStream );
3971 catch( uno::Exception& )
3975 return bResult;
3978 void SfxObjectShell::UpdateLinks()
3982 bool SfxObjectShell::GetApplicationFlag(SfxApplicationFlagType eFlagType)
3984 return false;
3987 sal_Bool SfxObjectShell::QuerySaveSizeExceededModules_Impl( const uno::Reference< task::XInteractionHandler >& xHandler )
3989 if ( !HasBasic() )
3990 return sal_True;
3992 if ( !pImp->pBasicManager->isValid() )
3993 GetBasicManager();
3994 uno::Sequence< rtl::OUString > sModules;
3995 if ( xHandler.is() )
3997 if( pImp->pBasicManager->LegacyPsswdBinaryLimitExceeded( sModules ) )
3999 ModuleSizeExceeded* pReq = new ModuleSizeExceeded( sModules );
4000 uno::Reference< task::XInteractionRequest > xReq( pReq );
4001 xHandler->handle( xReq );
4002 return pReq->isApprove();
4005 // No interaction handler, default is to continue to save
4006 return sal_True;
4008 // -----------------------------------------------------------------------------
4009 uno::Reference< task::XInteractionHandler > SfxObjectShell::getInteractionHandler() const
4011 uno::Reference< task::XInteractionHandler > xRet;
4012 if ( GetMedium() )
4013 xRet = GetMedium()->GetInteractionHandler();
4014 return xRet;