1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <config_features.h>
21 
22 #include <arrdecl.hxx>
23 #include <map>
24 
25 #include <cppuhelper/implbase.hxx>
26 #include <cppuhelper/weakref.hxx>
27 
28 #include <com/sun/star/util/XCloseable.hpp>
29 #include <com/sun/star/frame/XComponentLoader.hpp>
30 #include <com/sun/star/frame/Desktop.hpp>
31 #include <com/sun/star/util/XCloseBroadcaster.hpp>
32 #include <com/sun/star/util/XCloseListener.hpp>
33 #include <com/sun/star/util/XModifyBroadcaster.hpp>
34 #include <com/sun/star/beans/XPropertySet.hpp>
35 #include <com/sun/star/frame/XTitle.hpp>
36 #include <osl/file.hxx>
37 #include <rtl/instance.hxx>
38 #include <sal/log.hxx>
39 #include <vcl/weld.hxx>
40 #include <vcl/svapp.hxx>
41 #include <vcl/window.hxx>
42 #include <svl/eitem.hxx>
43 #include <svl/lstner.hxx>
44 #include <sfx2/sfxhelp.hxx>
45 #include <basic/sbstar.hxx>
46 #include <svl/stritem.hxx>
47 #include <basic/sbx.hxx>
48 #include <unotools/configmgr.hxx>
49 #include <unotools/eventcfg.hxx>
50 
51 #include <sfx2/objsh.hxx>
52 #include <sfx2/signaturestate.hxx>
53 #include <sfx2/sfxmodelfactory.hxx>
54 
55 #include <basic/sbuno.hxx>
56 #include <svtools/sfxecode.hxx>
57 #include <svtools/ehdl.hxx>
58 #include <unotools/printwarningoptions.hxx>
59 #include <comphelper/processfactory.hxx>
60 
61 #include <com/sun/star/document/XStorageBasedDocument.hpp>
62 #include <com/sun/star/script/DocumentDialogLibraryContainer.hpp>
63 #include <com/sun/star/script/DocumentScriptLibraryContainer.hpp>
64 #include <com/sun/star/document/XEmbeddedScripts.hpp>
65 #include <com/sun/star/document/XScriptInvocationContext.hpp>
66 #include <com/sun/star/ucb/ContentCreationException.hpp>
67 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
68 
69 #include <svl/urihelper.hxx>
70 #include <unotools/pathoptions.hxx>
71 #include <svl/sharecontrolfile.hxx>
72 #include <unotools/ucbhelper.hxx>
73 #include <svtools/asynclink.hxx>
74 #include <tools/diagnose_ex.h>
75 #include <tools/globname.hxx>
76 #include <tools/debug.hxx>
77 #include <comphelper/classids.hxx>
78 
79 #include <sfx2/app.hxx>
80 #include <sfx2/docfac.hxx>
81 #include <sfx2/docfile.hxx>
82 #include <sfx2/event.hxx>
83 #include <sfx2/dispatch.hxx>
84 #include <sfx2/viewsh.hxx>
85 #include <sfx2/viewfrm.hxx>
86 #include <sfx2/sfxresid.hxx>
87 #include <objshimp.hxx>
88 #include <sfxtypes.hxx>
89 #include <sfx2/evntconf.hxx>
90 #include <sfx2/request.hxx>
91 #include <sfx2/strings.hrc>
92 #include <appdata.hxx>
93 #include <sfx2/sfxsids.hrc>
94 #include <basic/basmgr.hxx>
95 #include <sfx2/QuerySaveDocument.hxx>
96 #include <sfx2/msg.hxx>
97 #include <appbaslib.hxx>
98 #include <sfx2/sfxbasemodel.hxx>
99 #include <sfx2/sfxuno.hxx>
100 #include <shellimpl.hxx>
101 #include <sfx2/notebookbar/SfxNotebookBar.hxx>
102 #include <sfx2/infobar.hxx>
103 
104 #include <basic/basicmanagerrepository.hxx>
105 
106 using namespace ::com::sun::star;
107 using namespace ::com::sun::star::uno;
108 using namespace ::com::sun::star::script;
109 using namespace ::com::sun::star::frame;
110 using namespace ::com::sun::star::document;
111 
112 using ::basic::BasicManagerRepository;
113 #include <uno/mapping.hxx>
114 
115 #include <sfxslots.hxx>
116 
117 namespace {
118 
119 class theCurrentComponent : public rtl::Static< WeakReference< XInterface >, theCurrentComponent > {};
120 
121 #if HAVE_FEATURE_SCRIPTING
122 
123 // remember all registered components for VBA compatibility, to be able to remove them on disposing the model
124 typedef ::std::map< XInterface*, OUString > VBAConstantNameMap;
125 static VBAConstantNameMap s_aRegisteredVBAConstants;
126 
lclGetVBAGlobalConstName(const Reference<XInterface> & rxComponent)127 OUString lclGetVBAGlobalConstName( const Reference< XInterface >& rxComponent )
128 {
129     OSL_ENSURE( rxComponent.is(), "lclGetVBAGlobalConstName - missing component" );
130 
131     VBAConstantNameMap::iterator aIt = s_aRegisteredVBAConstants.find( rxComponent.get() );
132     if( aIt != s_aRegisteredVBAConstants.end() )
133         return aIt->second;
134 
135     uno::Reference< beans::XPropertySet > xProps( rxComponent, uno::UNO_QUERY );
136     if( xProps.is() ) try
137     {
138         OUString aConstName;
139         xProps->getPropertyValue("VBAGlobalConstantName") >>= aConstName;
140         return aConstName;
141     }
142     catch (const uno::Exception&) // not supported
143     {
144     }
145     return OUString();
146 }
147 
148 #endif
149 
150 } // namespace
151 
152 
153 class SfxModelListener_Impl : public ::cppu::WeakImplHelper< css::util::XCloseListener >
154 {
155     SfxObjectShell* mpDoc;
156 public:
SfxModelListener_Impl(SfxObjectShell * pDoc)157     explicit SfxModelListener_Impl( SfxObjectShell* pDoc ) : mpDoc(pDoc) {};
158     virtual void SAL_CALL queryClosing( const css::lang::EventObject& aEvent, sal_Bool bDeliverOwnership ) override ;
159     virtual void SAL_CALL notifyClosing( const css::lang::EventObject& aEvent ) override ;
160     virtual void SAL_CALL disposing( const css::lang::EventObject& aEvent ) override ;
161 
162 };
163 
queryClosing(const css::lang::EventObject &,sal_Bool)164 void SAL_CALL SfxModelListener_Impl::queryClosing( const css::lang::EventObject& , sal_Bool )
165 {
166 }
167 
notifyClosing(const css::lang::EventObject &)168 void SAL_CALL SfxModelListener_Impl::notifyClosing( const css::lang::EventObject& )
169 {
170     SolarMutexGuard aSolarGuard;
171     mpDoc->Broadcast( SfxHint(SfxHintId::Deinitializing) );
172 }
173 
disposing(const css::lang::EventObject & _rEvent)174 void SAL_CALL SfxModelListener_Impl::disposing( const css::lang::EventObject& _rEvent )
175 {
176     // am I ThisComponent in AppBasic?
177     SolarMutexGuard aSolarGuard;
178     if ( SfxObjectShell::GetCurrentComponent() == _rEvent.Source )
179     {
180         // remove ThisComponent reference from AppBasic
181         SfxObjectShell::SetCurrentComponent( Reference< XInterface >() );
182     }
183 
184 #if HAVE_FEATURE_SCRIPTING
185     /*  Remove VBA component from AppBasic. As every application registers its
186         own current component, the disposed component may not be the "current
187         component" of the SfxObjectShell. */
188     if ( _rEvent.Source.is() )
189     {
190         VBAConstantNameMap::iterator aIt = s_aRegisteredVBAConstants.find( _rEvent.Source.get() );
191         if ( aIt != s_aRegisteredVBAConstants.end() )
192         {
193             if ( BasicManager* pAppMgr = SfxApplication::GetBasicManager() )
194                 pAppMgr->SetGlobalUNOConstant( aIt->second, Any( Reference< XInterface >() ) );
195             s_aRegisteredVBAConstants.erase( aIt );
196         }
197     }
198 #endif
199 
200     if ( !mpDoc->Get_Impl()->bClosing )
201         // GCC crashes when already in the destructor, so first query the Flag
202         mpDoc->DoClose();
203 }
204 
205 
SfxObjectShell_Impl(SfxObjectShell & _rDocShell)206 SfxObjectShell_Impl::SfxObjectShell_Impl( SfxObjectShell& _rDocShell )
207     :mpObjectContainer(nullptr)
208     ,rDocShell( _rDocShell )
209     ,aMacroMode( *this )
210     ,pProgress( nullptr)
211     ,nTime( DateTime::SYSTEM )
212     ,nVisualDocumentNumber( USHRT_MAX)
213     ,nDocumentSignatureState( SignatureState::UNKNOWN )
214     ,nScriptingSignatureState( SignatureState::UNKNOWN )
215     ,bClosing( false)
216     ,bIsSaving( false)
217     ,bIsNamedVisible( false)
218     ,bIsAbortingImport ( false)
219     ,bInPrepareClose( false )
220     ,bPreparedForClose( false )
221     ,bForbidReload( false )
222     ,bBasicInitialized( false )
223     ,bIsPrintJobCancelable( true )
224     ,bOwnsStorage( true )
225     ,bInitialized( false )
226     ,bModelInitialized( false )
227     ,bPreserveVersions( true )
228     ,m_bMacroSignBroken( false )
229     ,m_bNoBasicCapabilities( false )
230     ,m_bDocRecoverySupport( true )
231     ,bQueryLoadTemplate( true )
232     ,bLoadReadonly( false )
233     ,bUseUserData( true )
234     ,bUseThumbnailSave( true )
235     ,bSaveVersionOnClose( false )
236     ,m_bSharedXMLFlag( false )
237     ,m_bAllowShareControlFileClean( true )
238     ,m_bConfigOptionsChecked( false )
239     ,m_bMacroCallsSeenWhileLoading( false )
240     ,lErr(ERRCODE_NONE)
241     ,nEventId ( SfxEventHintId::NONE )
242     ,nLoadedFlags ( SfxLoadedFlags::ALL )
243     ,nFlagsInProgress( SfxLoadedFlags::NONE )
244     ,bModalMode( false )
245     ,bRunningMacro( false )
246     ,bReadOnlyUI( false )
247     ,nStyleFilter( 0 )
248     ,m_bEnableSetModified( true )
249     ,m_bIsModified( false )
250     ,m_nMapUnit( MapUnit::Map100thMM )
251     ,m_bCreateTempStor( false )
252     ,m_bIsInit( false )
253     ,m_bIncomplEncrWarnShown( false )
254     ,m_nModifyPasswordHash( 0 )
255     ,m_bModifyPasswordEntered( false )
256     ,m_bSavingForSigning( false )
257     ,m_bAllowModifiedBackAfterSigning( false )
258 {
259     SfxObjectShell* pDoc = &_rDocShell;
260     SfxObjectShellArr_Impl &rArr = SfxGetpApp()->GetObjectShells_Impl();
261     rArr.push_back( pDoc );
262 }
263 
264 
~SfxObjectShell_Impl()265 SfxObjectShell_Impl::~SfxObjectShell_Impl()
266 {
267 }
268 
269 
SfxObjectShell(const SfxModelFlags i_nCreationFlags)270 SfxObjectShell::SfxObjectShell( const SfxModelFlags i_nCreationFlags )
271     : pImpl(new SfxObjectShell_Impl(*this))
272     , pMedium(nullptr)
273     , eCreateMode(SfxObjectCreateMode::STANDARD)
274     , bHasName(false)
275     , bIsInGenerateThumbnail (false)
276     , mbAvoidRecentDocs(false)
277 {
278     if (i_nCreationFlags & SfxModelFlags::EMBEDDED_OBJECT)
279         eCreateMode = SfxObjectCreateMode::EMBEDDED;
280     else if (i_nCreationFlags & SfxModelFlags::EXTERNAL_LINK)
281         eCreateMode = SfxObjectCreateMode::INTERNAL;
282 
283     const bool bScriptSupport = ( i_nCreationFlags & SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS ) == SfxModelFlags::NONE;
284     if ( !bScriptSupport )
285         pImpl->m_bNoBasicCapabilities = true;
286 
287     const bool bDocRecovery = ( i_nCreationFlags & SfxModelFlags::DISABLE_DOCUMENT_RECOVERY ) == SfxModelFlags::NONE;
288     if ( !bDocRecovery )
289         pImpl->m_bDocRecoverySupport = false;
290 }
291 
292 /** Constructor of the class SfxObjectShell.
293 
294     @param eMode Purpose, to which the SfxObjectShell is created:
295                  SfxObjectCreateMode::EMBEDDED (default) as SO-Server from within another Document
296                  SfxObjectCreateMode::STANDARD, as a normal Document open stand-alone
297                  SfxObjectCreateMode::ORGANIZER to be displayed in the Organizer, here nothing of the contents is used
298 */
SfxObjectShell(SfxObjectCreateMode eMode)299 SfxObjectShell::SfxObjectShell(SfxObjectCreateMode eMode)
300     : pImpl(new SfxObjectShell_Impl(*this))
301     , pMedium(nullptr)
302     , eCreateMode(eMode)
303     , bHasName(false)
304     , bIsInGenerateThumbnail(false)
305     , mbAvoidRecentDocs(false)
306 {
307 }
308 
~SfxObjectShell()309 SfxObjectShell::~SfxObjectShell()
310 {
311 
312     if ( IsEnableSetModified() )
313         EnableSetModified( false );
314 
315     SfxObjectShell::CloseInternal();
316     pImpl->pBaseModel.set( nullptr );
317 
318     pImpl->pReloadTimer.reset();
319 
320     SfxApplication *pSfxApp = SfxGetpApp();
321     if ( USHRT_MAX != pImpl->nVisualDocumentNumber && pSfxApp )
322         pSfxApp->ReleaseIndex(pImpl->nVisualDocumentNumber);
323 
324     // Destroy Basic-Manager
325     pImpl->aBasicManager.reset(nullptr);
326 
327     if ( pSfxApp && pSfxApp->GetDdeService() )
328         pSfxApp->RemoveDdeTopic( this );
329 
330     pImpl->pBaseModel.set( nullptr );
331 
332     // don't call GetStorage() here, in case of Load Failure it's possible that a storage was never assigned!
333     if ( pMedium && pMedium->HasStorage_Impl() && pMedium->GetStorage( false ) == pImpl->m_xDocStorage )
334         pMedium->CanDisposeStorage_Impl( false );
335 
336     if ( pImpl->mpObjectContainer )
337     {
338         pImpl->mpObjectContainer->CloseEmbeddedObjects();
339         delete pImpl->mpObjectContainer;
340     }
341 
342     if ( pImpl->bOwnsStorage && pImpl->m_xDocStorage.is() )
343         pImpl->m_xDocStorage->dispose();
344 
345     if ( pMedium )
346     {
347         pMedium->CloseAndReleaseStreams_Impl();
348 
349 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
350         if (IsDocShared())
351             FreeSharedFile( pMedium->GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
352 #endif
353         DELETEZ( pMedium );
354     }
355 
356     // The removing of the temporary file must be done as the latest step in the document destruction
357     if ( !pImpl->aTempName.isEmpty() )
358     {
359         OUString aTmp;
360         osl::FileBase::getFileURLFromSystemPath( pImpl->aTempName, aTmp );
361         ::utl::UCBContentHelper::Kill( aTmp );
362     }
363 }
364 
365 
Stamp_SetPrintCancelState(bool bState)366 void SfxObjectShell::Stamp_SetPrintCancelState(bool bState)
367 {
368     pImpl->bIsPrintJobCancelable = bState;
369 }
370 
371 
Stamp_GetPrintCancelState() const372 bool SfxObjectShell::Stamp_GetPrintCancelState() const
373 {
374     return pImpl->bIsPrintJobCancelable;
375 }
376 
377 
378 // closes the Object and all its views
379 
Close()380 bool SfxObjectShell::Close()
381 {
382     SfxObjectShellRef aRef(this);
383     return CloseInternal();
384 }
385 
386 // variant that does not take a reference to itself, so we can call it during object destruction
CloseInternal()387 bool SfxObjectShell::CloseInternal()
388 {
389     if ( !pImpl->bClosing )
390     {
391         // Do not close if a progress is still running
392         if ( GetProgress() )
393             return false;
394 
395         pImpl->bClosing = true;
396         Reference< util::XCloseable > xCloseable( GetBaseModel(), UNO_QUERY );
397 
398         if ( xCloseable.is() )
399         {
400             try
401             {
402                 xCloseable->close( true );
403             }
404             catch (const Exception&)
405             {
406                 pImpl->bClosing = false;
407             }
408         }
409 
410         if ( pImpl->bClosing )
411         {
412             // remove from Document list
413             // If there is no App, there is no document to remove
414             // no need to call GetOrCreate here
415             SfxApplication *pSfxApp = SfxApplication::Get();
416             if(pSfxApp)
417             {
418                 SfxObjectShellArr_Impl &rDocs = pSfxApp->GetObjectShells_Impl();
419                 SfxObjectShellArr_Impl::iterator it = std::find( rDocs.begin(), rDocs.end(), this );
420                 if ( it != rDocs.end() )
421                     rDocs.erase( it );
422             }
423         }
424     }
425 
426     return true;
427 }
428 
CreateShellID(const SfxObjectShell * pShell)429 OUString SfxObjectShell::CreateShellID( const SfxObjectShell* pShell )
430 {
431     if (!pShell)
432         return OUString();
433 
434     OUString aShellID;
435 
436     SfxMedium* pMedium = pShell->GetMedium();
437     if (pMedium)
438         aShellID = pMedium->GetBaseURL();
439 
440     if (!aShellID.isEmpty())
441         return aShellID;
442 
443     sal_Int64 nShellID = reinterpret_cast<sal_Int64>(pShell);
444     aShellID = "0x" + OUString::number(nShellID, 16);
445     return aShellID;
446 }
447 
448 // returns a pointer the first SfxDocument of specified type
449 
GetFirst(const std::function<bool (const SfxObjectShell *)> & isObjectShell,bool bOnlyVisible)450 SfxObjectShell* SfxObjectShell::GetFirst
451 (
452     const std::function<bool ( const SfxObjectShell* )>& isObjectShell,
453     bool          bOnlyVisible
454 )
455 {
456     SfxObjectShellArr_Impl &rDocs = SfxGetpApp()->GetObjectShells_Impl();
457 
458     // search for a SfxDocument of the specified type
459     for (SfxObjectShell* pSh : rDocs)
460     {
461         if ( bOnlyVisible && pSh->IsPreview() && pSh->IsReadOnly() )
462             continue;
463 
464         if ( (!isObjectShell || isObjectShell( pSh)) &&
465              ( !bOnlyVisible || SfxViewFrame::GetFirst( pSh  )))
466             return pSh;
467     }
468 
469     return nullptr;
470 }
471 
472 
473 // returns a pointer to the next SfxDocument of specified type behind *pDoc
474 
GetNext(const SfxObjectShell & rPrev,const std::function<bool (const SfxObjectShell *)> & isObjectShell,bool bOnlyVisible)475 SfxObjectShell* SfxObjectShell::GetNext
476 (
477     const SfxObjectShell&   rPrev,
478     const std::function<bool ( const SfxObjectShell* )>& isObjectShell,
479     bool                    bOnlyVisible
480 )
481 {
482     SfxObjectShellArr_Impl &rDocs = SfxGetpApp()->GetObjectShells_Impl();
483 
484     // refind the specified predecessor
485     size_t nPos;
486     for ( nPos = 0; nPos < rDocs.size(); ++nPos )
487         if ( rDocs[nPos] == &rPrev )
488             break;
489 
490     // search for the next SfxDocument of the specified type
491     for ( ++nPos; nPos < rDocs.size(); ++nPos )
492     {
493         SfxObjectShell* pSh = rDocs[ nPos ];
494         if ( bOnlyVisible && pSh->IsPreview() && pSh->IsReadOnly() )
495             continue;
496 
497         if ( (!isObjectShell || isObjectShell( pSh)) &&
498              ( !bOnlyVisible || SfxViewFrame::GetFirst( pSh )))
499             return pSh;
500     }
501     return nullptr;
502 }
503 
504 
Current()505 SfxObjectShell* SfxObjectShell::Current()
506 {
507     SfxViewFrame *pFrame = SfxViewFrame::Current();
508     return pFrame ? pFrame->GetObjectShell() : nullptr;
509 }
510 
511 
IsInPrepareClose() const512 bool SfxObjectShell::IsInPrepareClose() const
513 {
514     return pImpl->bInPrepareClose;
515 }
516 
517 
518 struct BoolEnv_Impl
519 {
520     SfxObjectShell_Impl& rImpl;
BoolEnv_ImplBoolEnv_Impl521     explicit BoolEnv_Impl( SfxObjectShell_Impl& rImplP) : rImpl( rImplP )
522     { rImplP.bInPrepareClose = true; }
~BoolEnv_ImplBoolEnv_Impl523     ~BoolEnv_Impl() { rImpl.bInPrepareClose = false; }
524 };
525 
526 
PrepareClose(bool bUI)527 bool SfxObjectShell::PrepareClose
528 (
529     bool bUI   // true: Dialog and so on is allowed
530                // false: silent-mode
531 )
532 {
533     if( pImpl->bInPrepareClose || pImpl->bPreparedForClose )
534         return true;
535     BoolEnv_Impl aBoolEnv( *pImpl );
536 
537     // DocModalDialog?
538     if ( IsInModalMode() )
539         return false;
540 
541     SfxViewFrame* pFirst = SfxViewFrame::GetFirst( this );
542     if( pFirst && !pFirst->GetFrame().PrepareClose_Impl( bUI ) )
543         return false;
544 
545     // prepare views for closing
546     for ( SfxViewFrame* pFrm = SfxViewFrame::GetFirst( this );
547           pFrm; pFrm = SfxViewFrame::GetNext( *pFrm, this ) )
548     {
549         DBG_ASSERT(pFrm->GetViewShell(),"No Shell");
550         if ( pFrm->GetViewShell() )
551         {
552             bool bRet = pFrm->GetViewShell()->PrepareClose( bUI );
553             if ( !bRet )
554                 return bRet;
555         }
556     }
557 
558     SfxApplication *pSfxApp = SfxGetpApp();
559     pSfxApp->NotifyEvent( SfxEventHint(SfxEventHintId::PrepareCloseDoc, GlobalEventConfig::GetEventName(GlobalEventId::PREPARECLOSEDOC), this) );
560 
561     if( GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
562     {
563         pImpl->bPreparedForClose = true;
564         return true;
565     }
566 
567     // Ask if possible if it should be saved
568     // only ask for the Document in the visible window
569     SfxViewFrame *pFrame = SfxObjectShell::Current() == this
570         ? SfxViewFrame::Current() : SfxViewFrame::GetFirst( this );
571 
572     if ( bUI && IsModified() && pFrame )
573     {
574         // restore minimized
575         SfxFrame& rTop = pFrame->GetFrame();
576         SfxViewFrame::SetViewFrame( rTop.GetCurrentViewFrame() );
577         pFrame->GetFrame().Appear();
578 
579         // Ask if to save
580         short nRet = RET_YES;
581         {
582             const Reference<XTitle> xTitle(*pImpl->pBaseModel, UNO_QUERY_THROW);
583             const OUString     sTitle = xTitle->getTitle ();
584             nRet = ExecuteQuerySaveDocument(pFrame->GetWindow().GetFrameWeld(), sTitle);
585         }
586         /*HACK for plugin::destroy()*/
587 
588         if ( RET_YES == nRet )
589         {
590             // Save by each Dispatcher
591             const SfxPoolItem *pPoolItem;
592             if ( IsSaveVersionOnClose() )
593             {
594                 SfxStringItem aItem( SID_DOCINFO_COMMENTS, SfxResId(STR_AUTOMATICVERSION) );
595                 SfxBoolItem aWarnItem( SID_FAIL_ON_WARNING, bUI );
596                 const SfxPoolItem* ppArgs[] = { &aItem, &aWarnItem, nullptr };
597                 pPoolItem = pFrame->GetBindings().ExecuteSynchron( SID_SAVEDOC, ppArgs );
598             }
599             else
600             {
601                 SfxBoolItem aWarnItem( SID_FAIL_ON_WARNING, bUI );
602                 const SfxPoolItem* ppArgs[] = { &aWarnItem, nullptr };
603                 pPoolItem = pFrame->GetBindings().ExecuteSynchron( SID_SAVEDOC, ppArgs );
604             }
605 
606             if ( !pPoolItem || pPoolItem->IsVoidItem() || ( dynamic_cast< const SfxBoolItem *>( pPoolItem ) != nullptr && !static_cast<const SfxBoolItem*>( pPoolItem )->GetValue() ) )
607                 return false;
608         }
609         else if ( RET_CANCEL == nRet )
610             // Cancelled
611             return false;
612     }
613 
614     if ( pFrame )
615         sfx2::SfxNotebookBar::CloseMethod(pFrame->GetBindings());
616     pImpl->bPreparedForClose = true;
617     return true;
618 }
619 
620 
621 #if HAVE_FEATURE_SCRIPTING
622 namespace
623 {
lcl_getBasicManagerForDocument(const SfxObjectShell & _rDocument)624     BasicManager* lcl_getBasicManagerForDocument( const SfxObjectShell& _rDocument )
625     {
626         if ( !_rDocument.Get_Impl()->m_bNoBasicCapabilities )
627         {
628             if ( !_rDocument.Get_Impl()->bBasicInitialized )
629                 const_cast< SfxObjectShell& >( _rDocument ).InitBasicManager_Impl();
630             return _rDocument.Get_Impl()->aBasicManager.get();
631         }
632 
633         // assume we do not have Basic ourself, but we can refer to another
634         // document which does (by our model's XScriptInvocationContext::getScriptContainer).
635         // In this case, we return the BasicManager of this other document.
636 
637         OSL_ENSURE( !Reference< XEmbeddedScripts >( _rDocument.GetModel(), UNO_QUERY ).is(),
638             "lcl_getBasicManagerForDocument: inconsistency: no Basic, but an XEmbeddedScripts?" );
639         Reference< XModel > xForeignDocument;
640         Reference< XScriptInvocationContext > xContext( _rDocument.GetModel(), UNO_QUERY );
641         if ( xContext.is() )
642         {
643             xForeignDocument.set( xContext->getScriptContainer(), UNO_QUERY );
644             OSL_ENSURE( xForeignDocument.is() && xForeignDocument != _rDocument.GetModel(),
645                 "lcl_getBasicManagerForDocument: no Basic, but providing ourself as script container?" );
646         }
647 
648         BasicManager* pBasMgr = nullptr;
649         if ( xForeignDocument.is() )
650             pBasMgr = ::basic::BasicManagerRepository::getDocumentBasicManager( xForeignDocument );
651 
652         return pBasMgr;
653     }
654 }
655 #endif
656 
GetBasicManager() const657 BasicManager* SfxObjectShell::GetBasicManager() const
658 {
659     BasicManager* pBasMgr = nullptr;
660 #if HAVE_FEATURE_SCRIPTING
661     try
662     {
663         pBasMgr = lcl_getBasicManagerForDocument( *this );
664         if ( !pBasMgr )
665             pBasMgr = SfxApplication::GetBasicManager();
666     }
667     catch (const css::ucb::ContentCreationException&)
668     {
669         TOOLS_WARN_EXCEPTION("sfx.doc", "");
670     }
671 #endif
672     return pBasMgr;
673 }
674 
HasBasic() const675 bool SfxObjectShell::HasBasic() const
676 {
677 #if !HAVE_FEATURE_SCRIPTING
678     return false;
679 #else
680     if ( pImpl->m_bNoBasicCapabilities )
681         return false;
682 
683     if ( !pImpl->bBasicInitialized )
684         const_cast< SfxObjectShell* >( this )->InitBasicManager_Impl();
685 
686     return pImpl->aBasicManager.isValid();
687 #endif
688 }
689 
690 
691 #if HAVE_FEATURE_SCRIPTING
692 namespace
693 {
694     const Reference< XLibraryContainer >&
lcl_getOrCreateLibraryContainer(bool _bScript,Reference<XLibraryContainer> & _rxContainer,const Reference<XModel> & _rxDocument)695     lcl_getOrCreateLibraryContainer( bool _bScript, Reference< XLibraryContainer >& _rxContainer,
696         const Reference< XModel >& _rxDocument )
697     {
698         if ( !_rxContainer.is() )
699         {
700             try
701             {
702                 Reference< XStorageBasedDocument > xStorageDoc( _rxDocument, UNO_QUERY );
703                 const Reference< XComponentContext > xContext(
704                     ::comphelper::getProcessComponentContext() );
705                 _rxContainer.set (   _bScript
706                                 ?   DocumentScriptLibraryContainer::create(
707                                         xContext, xStorageDoc )
708                                 :   DocumentDialogLibraryContainer::create(
709                                         xContext, xStorageDoc )
710                                 ,   UNO_QUERY_THROW );
711             }
712             catch (const Exception&)
713             {
714                 DBG_UNHANDLED_EXCEPTION("sfx.doc");
715             }
716         }
717         return _rxContainer;
718     }
719 }
720 #endif
721 
GetDialogContainer()722 Reference< XLibraryContainer > SfxObjectShell::GetDialogContainer()
723 {
724 #if HAVE_FEATURE_SCRIPTING
725     try
726     {
727         if ( !pImpl->m_bNoBasicCapabilities )
728             return lcl_getOrCreateLibraryContainer( false, pImpl->xDialogLibraries, GetModel() );
729 
730         BasicManager* pBasMgr = lcl_getBasicManagerForDocument( *this );
731         if ( pBasMgr )
732             return pBasMgr->GetDialogLibraryContainer().get();
733     }
734     catch (const css::ucb::ContentCreationException&)
735     {
736         TOOLS_WARN_EXCEPTION("sfx.doc", "");
737     }
738 
739     SAL_WARN("sfx.doc", "SfxObjectShell::GetDialogContainer: falling back to the application - is this really expected here?");
740 #endif
741     return SfxGetpApp()->GetDialogContainer();
742 }
743 
GetBasicContainer()744 Reference< XLibraryContainer > SfxObjectShell::GetBasicContainer()
745 {
746 #if HAVE_FEATURE_SCRIPTING
747     if (!utl::ConfigManager::IsFuzzing())
748     {
749         try
750         {
751             if ( !pImpl->m_bNoBasicCapabilities )
752                 return lcl_getOrCreateLibraryContainer( true, pImpl->xBasicLibraries, GetModel() );
753 
754             BasicManager* pBasMgr = lcl_getBasicManagerForDocument( *this );
755             if ( pBasMgr )
756                 return pBasMgr->GetScriptLibraryContainer().get();
757         }
758         catch (const css::ucb::ContentCreationException&)
759         {
760             TOOLS_WARN_EXCEPTION("sfx.doc", "");
761         }
762     }
763     SAL_WARN("sfx.doc", "SfxObjectShell::GetBasicContainer: falling back to the application - is this really expected here?");
764 #endif
765     return SfxGetpApp()->GetBasicContainer();
766 }
767 
GetBasic() const768 StarBASIC* SfxObjectShell::GetBasic() const
769 {
770 #if !HAVE_FEATURE_SCRIPTING
771     return NULL;
772 #else
773     BasicManager * pMan = GetBasicManager();
774     return pMan ? pMan->GetLib(0) : nullptr;
775 #endif
776 }
777 
InitBasicManager_Impl()778 void SfxObjectShell::InitBasicManager_Impl()
779 /*  [Description]
780 
781     Creates a document's BasicManager and loads it, if we are already based on
782     a storage.
783 
784     [Note]
785 
786     This method has to be called by implementations of <SvPersist::Load()>
787     (with its pStor parameter) and by implementations of <SvPersist::InitNew()>
788     (with pStor = 0).
789 */
790 
791 {
792     /*  #163556# (DR) - Handling of recursive calls while creating the Basic
793         manager.
794 
795         It is possible that (while creating the Basic manager) the code that
796         imports the Basic storage wants to access the Basic manager again.
797         Especially in VBA compatibility mode, there is code that wants to
798         access the "VBA Globals" object which is stored as global UNO constant
799         in the Basic manager.
800 
801         To achieve correct handling of the recursive calls of this function
802         from lcl_getBasicManagerForDocument(), the implementation of the
803         function BasicManagerRepository::getDocumentBasicManager() has been
804         changed to return the Basic manager currently under construction, when
805         called repeatedly.
806 
807         The variable pImpl->bBasicInitialized will be set to sal_True after
808         construction now, to ensure that the recursive call of the function
809         lcl_getBasicManagerForDocument() will be routed into this function too.
810 
811         Calling BasicManagerHolder::reset() twice is not a big problem, as it
812         does not take ownership but stores only the raw pointer. Owner of all
813         Basic managers is the global BasicManagerRepository instance.
814      */
815 #if HAVE_FEATURE_SCRIPTING
816     DBG_ASSERT( !pImpl->bBasicInitialized && !pImpl->aBasicManager.isValid(), "Local BasicManager already exists");
817     try
818     {
819         pImpl->aBasicManager.reset( BasicManagerRepository::getDocumentBasicManager( GetModel() ) );
820     }
821     catch (const css::ucb::ContentCreationException&)
822     {
823         TOOLS_WARN_EXCEPTION("sfx.doc", "");
824     }
825     DBG_ASSERT( pImpl->aBasicManager.isValid(), "SfxObjectShell::InitBasicManager_Impl: did not get a BasicManager!" );
826     pImpl->bBasicInitialized = true;
827 #endif
828 }
829 
830 
DoClose()831 bool SfxObjectShell::DoClose()
832 {
833     return Close();
834 }
835 
836 
GetObjectShell()837 SfxObjectShell* SfxObjectShell::GetObjectShell()
838 {
839     return this;
840 }
841 
842 
GetEventNames()843 uno::Sequence< OUString > SfxObjectShell::GetEventNames()
844 {
845     static uno::Sequence< OUString > s_EventNameContainer(rtl::Reference<GlobalEventConfig>(new GlobalEventConfig)->getElementNames());
846 
847     return s_EventNameContainer;
848 }
849 
850 
GetModel() const851 css::uno::Reference< css::frame::XModel > SfxObjectShell::GetModel() const
852 {
853     return GetBaseModel();
854 }
855 
SetBaseModel(SfxBaseModel * pModel)856 void SfxObjectShell::SetBaseModel( SfxBaseModel* pModel )
857 {
858     OSL_ENSURE( !pImpl->pBaseModel.is() || pModel == nullptr, "Model already set!" );
859     pImpl->pBaseModel.set( pModel );
860     if ( pImpl->pBaseModel.is() )
861     {
862         pImpl->pBaseModel->addCloseListener( new SfxModelListener_Impl(this) );
863     }
864 }
865 
866 
GetBaseModel() const867 css::uno::Reference< css::frame::XModel > SfxObjectShell::GetBaseModel() const
868 {
869     return pImpl->pBaseModel.get();
870 }
871 
SetAutoStyleFilterIndex(sal_uInt16 nSet)872 void SfxObjectShell::SetAutoStyleFilterIndex(sal_uInt16 nSet)
873 {
874     pImpl->nStyleFilter = nSet;
875 }
876 
GetAutoStyleFilterIndex() const877 sal_uInt16 SfxObjectShell::GetAutoStyleFilterIndex() const
878 {
879     return pImpl->nStyleFilter;
880 }
881 
882 
SetCurrentComponent(const Reference<XInterface> & _rxComponent)883 void SfxObjectShell::SetCurrentComponent( const Reference< XInterface >& _rxComponent )
884 {
885     WeakReference< XInterface >& rTheCurrentComponent = theCurrentComponent::get();
886 
887     Reference< XInterface > xOldCurrentComp(rTheCurrentComponent);
888     if ( _rxComponent == xOldCurrentComp )
889         // nothing to do
890         return;
891     // note that "_rxComponent.get() == s_xCurrentComponent.get().get()" is /sufficient/, but not
892     // /required/ for "_rxComponent == s_xCurrentComponent.get()".
893     // In other words, it's still possible that we here do something which is not necessary,
894     // but we should have filtered quite some unnecessary calls already.
895 
896 #if HAVE_FEATURE_SCRIPTING
897     BasicManager* pAppMgr = SfxApplication::GetBasicManager();
898     rTheCurrentComponent = _rxComponent;
899     if ( !pAppMgr )
900         return;
901 
902     // set "ThisComponent" for Basic
903     pAppMgr->SetGlobalUNOConstant( "ThisComponent", Any( _rxComponent ) );
904 
905     // set new current component for VBA compatibility
906     if ( _rxComponent.is() )
907     {
908         OUString aVBAConstName = lclGetVBAGlobalConstName( _rxComponent );
909         if ( !aVBAConstName.isEmpty() )
910         {
911             pAppMgr->SetGlobalUNOConstant( aVBAConstName, Any( _rxComponent ) );
912             s_aRegisteredVBAConstants[ _rxComponent.get() ] = aVBAConstName;
913         }
914     }
915     // no new component passed -> remove last registered VBA component
916     else if ( xOldCurrentComp.is() )
917     {
918         OUString aVBAConstName = lclGetVBAGlobalConstName( xOldCurrentComp );
919         if ( !aVBAConstName.isEmpty() )
920         {
921             pAppMgr->SetGlobalUNOConstant( aVBAConstName, Any( Reference< XInterface >() ) );
922             s_aRegisteredVBAConstants.erase( xOldCurrentComp.get() );
923         }
924     }
925 #endif
926 }
927 
GetCurrentComponent()928 Reference< XInterface > SfxObjectShell::GetCurrentComponent()
929 {
930     return theCurrentComponent::get();
931 }
932 
933 
GetServiceNameFromFactory(const OUString & rFact)934 OUString SfxObjectShell::GetServiceNameFromFactory( const OUString& rFact )
935 {
936     //! Remove everything behind name!
937     OUString aFact( rFact );
938     OUString aPrefix("private:factory/");
939     if ( aFact.startsWith( aPrefix ) )
940         aFact = aFact.copy( aPrefix.getLength() );
941     sal_Int32 nPos = aFact.indexOf( '?' );
942     OUString aParam;
943     if ( nPos != -1 )
944     {
945         aParam = aFact.copy( nPos );
946         aFact = aFact.copy( 0, nPos );
947         aParam = aParam.copy(1);
948     }
949     aFact = aFact.replaceAll("4", "");
950     aFact = aFact.toAsciiLowerCase();
951 
952     // HACK: sometimes a real document service name is given here instead of
953     // a factory short name. Set return value directly to this service name as fallback
954     // in case next lines of code does nothing ...
955     // use rFact instead of normed aFact value !
956     OUString aServiceName = rFact;
957 
958     if ( aFact == "swriter" )
959     {
960         aServiceName = "com.sun.star.text.TextDocument";
961     }
962     else if ( aFact == "sweb" || aFact == "swriter/web" )
963     {
964         aServiceName = "com.sun.star.text.WebDocument";
965     }
966     else if ( aFact == "sglobal" || aFact == "swriter/globaldocument" )
967     {
968         aServiceName = "com.sun.star.text.GlobalDocument";
969     }
970     else if ( aFact == "scalc" )
971     {
972         aServiceName = "com.sun.star.sheet.SpreadsheetDocument";
973     }
974     else if ( aFact == "sdraw" )
975     {
976         aServiceName = "com.sun.star.drawing.DrawingDocument";
977     }
978     else if ( aFact == "simpress" )
979     {
980         aServiceName = "com.sun.star.presentation.PresentationDocument";
981     }
982     else if ( aFact == "schart" )
983     {
984         aServiceName = "com.sun.star.chart.ChartDocument";
985     }
986     else if ( aFact == "smath" )
987     {
988         aServiceName = "com.sun.star.formula.FormulaProperties";
989     }
990 #if HAVE_FEATURE_SCRIPTING
991     else if ( aFact == "sbasic" )
992     {
993         aServiceName = "com.sun.star.script.BasicIDE";
994     }
995 #endif
996 #if HAVE_FEATURE_DBCONNECTIVITY
997     else if ( aFact == "sdatabase" )
998     {
999         aServiceName = "com.sun.star.sdb.OfficeDatabaseDocument";
1000     }
1001 #endif
1002 
1003     return aServiceName;
1004 }
1005 
CreateObjectByFactoryName(const OUString & rFact,SfxObjectCreateMode eMode)1006 SfxObjectShell* SfxObjectShell::CreateObjectByFactoryName( const OUString& rFact, SfxObjectCreateMode eMode )
1007 {
1008     return CreateObject( GetServiceNameFromFactory( rFact ), eMode );
1009 }
1010 
1011 
CreateObject(const OUString & rServiceName,SfxObjectCreateMode eCreateMode)1012 SfxObjectShell* SfxObjectShell::CreateObject( const OUString& rServiceName, SfxObjectCreateMode eCreateMode )
1013 {
1014     if ( !rServiceName.isEmpty() )
1015     {
1016         uno::Reference < frame::XModel > xDoc( ::comphelper::getProcessServiceFactory()->createInstance( rServiceName ), UNO_QUERY );
1017         if ( xDoc.is() )
1018         {
1019             uno::Reference < lang::XUnoTunnel > xObj( xDoc, UNO_QUERY );
1020             uno::Sequence < sal_Int8 > aSeq( SvGlobalName( SFX_GLOBAL_CLASSID ).GetByteSequence() );
1021             sal_Int64 nHandle = xObj->getSomething( aSeq );
1022             if ( nHandle )
1023             {
1024                 SfxObjectShell* pRet = reinterpret_cast< SfxObjectShell* >( sal::static_int_cast< sal_IntPtr >( nHandle ));
1025                 pRet->SetCreateMode_Impl( eCreateMode );
1026                 return pRet;
1027             }
1028         }
1029     }
1030 
1031     return nullptr;
1032 }
1033 
CreateAndLoadComponent(const SfxItemSet & rSet)1034 Reference<lang::XComponent> SfxObjectShell::CreateAndLoadComponent( const SfxItemSet& rSet )
1035 {
1036     uno::Sequence < beans::PropertyValue > aProps;
1037     TransformItems( SID_OPENDOC, rSet, aProps );
1038     const SfxStringItem* pFileNameItem = rSet.GetItem<SfxStringItem>(SID_FILE_NAME, false);
1039     const SfxStringItem* pTargetItem = rSet.GetItem<SfxStringItem>(SID_TARGETNAME, false);
1040     OUString aURL;
1041     OUString aTarget("_blank");
1042     if ( pFileNameItem )
1043         aURL = pFileNameItem->GetValue();
1044     if ( pTargetItem )
1045         aTarget = pTargetItem->GetValue();
1046 
1047     uno::Reference < frame::XComponentLoader > xLoader =
1048             frame::Desktop::create(comphelper::getProcessComponentContext());
1049 
1050     Reference <lang::XComponent> xComp;
1051     try
1052     {
1053         xComp = xLoader->loadComponentFromURL(aURL, aTarget, 0, aProps);
1054     }
1055     catch (const uno::Exception&)
1056     {
1057     }
1058 
1059     return xComp;
1060 }
1061 
GetShellFromComponent(const Reference<lang::XComponent> & xComp)1062 SfxObjectShell* SfxObjectShell::GetShellFromComponent( const Reference<lang::XComponent>& xComp )
1063 {
1064     try
1065     {
1066         Reference<lang::XUnoTunnel> xTunnel(xComp, UNO_QUERY_THROW);
1067         Sequence <sal_Int8> aSeq( SvGlobalName( SFX_GLOBAL_CLASSID ).GetByteSequence() );
1068         sal_Int64 nHandle = xTunnel->getSomething( aSeq );
1069         if (!nHandle)
1070             return nullptr;
1071 
1072         return reinterpret_cast< SfxObjectShell* >(sal::static_int_cast< sal_IntPtr >(  nHandle ));
1073     }
1074     catch (const Exception&)
1075     {
1076     }
1077 
1078     return nullptr;
1079 }
1080 
SetInitialized_Impl(const bool i_fromInitNew)1081 void SfxObjectShell::SetInitialized_Impl( const bool i_fromInitNew )
1082 {
1083     pImpl->bInitialized = true;
1084     if (utl::ConfigManager::IsFuzzing())
1085         return;
1086     if ( i_fromInitNew )
1087     {
1088         SetActivateEvent_Impl( SfxEventHintId::CreateDoc );
1089         SfxGetpApp()->NotifyEvent( SfxEventHint( SfxEventHintId::DocCreated, GlobalEventConfig::GetEventName(GlobalEventId::DOCCREATED), this ) );
1090     }
1091     else
1092     {
1093         SfxGetpApp()->NotifyEvent( SfxEventHint( SfxEventHintId::LoadFinished, GlobalEventConfig::GetEventName(GlobalEventId::LOADFINISHED), this ) );
1094     }
1095 }
1096 
1097 
IsChangeRecording() const1098 bool SfxObjectShell::IsChangeRecording() const
1099 {
1100     // currently this function needs to be overwritten by Writer and Calc only
1101     SAL_WARN( "sfx.doc", "function not implemented" );
1102     return false;
1103 }
1104 
1105 
HasChangeRecordProtection() const1106 bool SfxObjectShell::HasChangeRecordProtection() const
1107 {
1108     // currently this function needs to be overwritten by Writer and Calc only
1109     SAL_WARN( "sfx.doc", "function not implemented" );
1110     return false;
1111 }
1112 
1113 
SetChangeRecording(bool)1114 void SfxObjectShell::SetChangeRecording( bool /*bActivate*/ )
1115 {
1116     // currently this function needs to be overwritten by Writer and Calc only
1117     SAL_WARN( "sfx.doc", "function not implemented" );
1118 }
1119 
1120 
SetProtectionPassword(const OUString &)1121 void SfxObjectShell::SetProtectionPassword( const OUString & /*rPassword*/ )
1122 {
1123     // currently this function needs to be overwritten by Writer and Calc only
1124     SAL_WARN( "sfx.doc", "function not implemented" );
1125 }
1126 
1127 
GetProtectionHash(css::uno::Sequence<sal_Int8> &)1128 bool SfxObjectShell::GetProtectionHash( /*out*/ css::uno::Sequence< sal_Int8 > & /*rPasswordHash*/ )
1129 {
1130     // currently this function needs to be overwritten by Writer and Calc only
1131     SAL_WARN( "sfx.doc", "function not implemented" );
1132     return false;
1133 }
1134 
1135 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1136