xref: /core/sfx2/source/appl/app.cxx (revision 8cce131d)
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_feature_desktop.h>
21 #include <sal/log.hxx>
22 #include <osl/module.hxx>
23 #include <tools/debug.hxx>
24 
25 #include <sfx2/app.hxx>
26 #include <sfx2/frame.hxx>
27 #include <basic/sberrors.hxx>
28 #include <tools/svlibrary.h>
29 
30 #include <svl/svdde.hxx>
31 #include <unotools/configmgr.hxx>
32 #include <com/sun/star/frame/XFrame.hpp>
33 #include <comphelper/processfactory.hxx>
34 #include <com/sun/star/uri/UriReferenceFactory.hpp>
35 #include <com/sun/star/uri/XVndSunStarScriptUrl.hpp>
36 #include <basic/basmgr.hxx>
37 #include <vcl/svapp.hxx>
38 #include <sfx2/sfxhelp.hxx>
39 #include <sfx2/progress.hxx>
40 #include <sfx2/objsh.hxx>
41 #include <sfx2/dispatch.hxx>
42 #include <sfx2/viewsh.hxx>
43 #include <sfx2/viewfrm.hxx>
44 #include <appdata.hxx>
45 #include <sfx2/module.hxx>
46 #include <sfx2/event.hxx>
47 #include <workwin.hxx>
48 #include <sfx2/sidebar/Theme.hxx>
49 #include <sfx2/tbxctrl.hxx>
50 #include <sfx2/sfxdlg.hxx>
51 #include <sfx2/stbitem.hxx>
52 #include <sfx2/dockwin.hxx>
53 #include <shellimpl.hxx>
54 
55 #include <svtools/helpopt.hxx>
56 #include <unotools/viewoptions.hxx>
57 #include <rtl/instance.hxx>
58 #include <rtl/strbuf.hxx>
59 #include <memory>
60 #include <framework/sfxhelperfunctions.hxx>
61 #include <fwkhelper.hxx>
62 
63 using namespace ::com::sun::star;
64 
65 static SfxApplication* g_pSfxApplication = nullptr;
66 
67 #if HAVE_FEATURE_DESKTOP
68 static SfxHelp*        pSfxHelp = nullptr;
69 #endif
70 
71 namespace
72 {
73     class theApplicationMutex
74         : public rtl::Static<osl::Mutex, theApplicationMutex> {};
75 }
76 
77 SfxApplication* SfxApplication::Get()
78 {
79     return g_pSfxApplication;
80 }
81 
82 void SfxApplication::SetModule(SfxToolsModule nSharedLib, std::unique_ptr<SfxModule> pModule)
83 {
84     assert(g_pSfxApplication != nullptr);
85 
86     g_pSfxApplication->pImpl->aModules[nSharedLib] = std::move(pModule);
87 }
88 
89 SfxModule* SfxApplication::GetModule(SfxToolsModule nSharedLib)
90 {
91     if (!g_pSfxApplication) // It is possible GetModule is called before SfxApplication is initialised via GetOrCreate()
92         return nullptr;
93     return g_pSfxApplication->pImpl->aModules[nSharedLib].get();
94 }
95 
96 SfxApplication* SfxApplication::GetOrCreate()
97 {
98     // SFX on demand
99     ::osl::MutexGuard aGuard(theApplicationMutex::get());
100     if (!g_pSfxApplication)
101     {
102         SAL_INFO( "sfx.appl", "SfxApplication::SetApp" );
103 
104         g_pSfxApplication = new SfxApplication;
105 
106         // at the moment a bug may occur when Initialize_Impl returns FALSE,
107         // but this is only temporary because all code that may cause such
108         // a fault will be moved outside the SFX
109         g_pSfxApplication->Initialize_Impl();
110 
111         ::framework::SetRefreshToolbars( RefreshToolbars );
112         ::framework::SetToolBoxControllerCreator( SfxToolBoxControllerFactory );
113         ::framework::SetStatusBarControllerCreator( SfxStatusBarControllerFactory );
114         ::framework::SetDockingWindowCreator( SfxDockingWindowFactory );
115         ::framework::SetIsDockingWindowVisible( IsDockingWindowVisible );
116 #if HAVE_FEATURE_DESKTOP
117         Application::SetHelp( pSfxHelp );
118         if (!utl::ConfigManager::IsFuzzing() && SvtHelpOptions().IsHelpTips())
119             Help::EnableQuickHelp();
120         else
121             Help::DisableQuickHelp();
122         if (!utl::ConfigManager::IsFuzzing() && SvtHelpOptions().IsHelpTips() && SvtHelpOptions().IsExtendedHelp())
123             Help::EnableBalloonHelp();
124         else
125             Help::DisableBalloonHelp();
126 #endif
127     }
128     return g_pSfxApplication;
129 }
130 
131 SfxApplication::SfxApplication()
132     : pImpl( new SfxAppData_Impl )
133 {
134     SetName( "StarOffice" );
135     if (!utl::ConfigManager::IsFuzzing())
136         SvtViewOptions::AcquireOptions();
137 
138     SAL_INFO( "sfx.appl", "{ initialize DDE" );
139 
140     bool bOk = InitializeDde();
141 
142 #ifdef DBG_UTIL
143     if( !bOk )
144     {
145         OStringBuffer aStr("No DDE-Service possible. Error: ");
146         if( GetDdeService() )
147             aStr.append(static_cast<sal_Int32>(GetDdeService()->GetError()));
148         else
149             aStr.append('?');
150         SAL_WARN( "sfx.appl", aStr.getStr() );
151     }
152 #else
153     (void)bOk;
154 #endif
155 
156 #if HAVE_FEATURE_DESKTOP
157     pSfxHelp = new SfxHelp;
158 #endif
159 
160 #if HAVE_FEATURE_SCRIPTING
161     StarBASIC::SetGlobalErrorHdl( LINK( this, SfxApplication, GlobalBasicErrorHdl_Impl ) );
162 #endif
163 
164     SAL_INFO( "sfx.appl", "} initialize DDE" );
165 }
166 
167 SfxApplication::~SfxApplication()
168 {
169     SAL_WARN_IF(GetObjectShells_Impl().size() != 0, "sfx.appl", "Memory leak: some object shells were not removed!");
170 
171     Broadcast( SfxHint(SfxHintId::Dying) );
172 
173     for (auto &module : pImpl->aModules)    // Clear modules
174         module.reset();
175 
176 #if HAVE_FEATURE_DESKTOP
177     delete pSfxHelp;
178     Application::SetHelp();
179 #endif
180 
181     // delete global options
182     if (!utl::ConfigManager::IsFuzzing())
183         SvtViewOptions::ReleaseOptions();
184 
185     if ( !pImpl->bDowning )
186         Deinitialize();
187 
188     g_pSfxApplication = nullptr;
189 }
190 
191 
192 const OUString& SfxApplication::GetLastDir_Impl() const
193 
194 /*  [Description]
195 
196     Internal method by which the last set directory with the method
197     <SfxApplication::SetLastDir_Impl()> in SFX is returned.
198 
199     This is usually the most recently addressed by the
200     SfxFileDialog directory.
201 
202     [Cross-reference]
203     <SfxApplication::SetLastDir_Impl()>
204 */
205 
206 {
207     return pImpl->aLastDir;
208 }
209 
210 void SfxApplication::SetLastDir_Impl
211 (
212     const OUString&   rNewDir     /* Complete directory path as a string */
213 )
214 
215 /*  [Description]
216 
217     Internal Method, by which a directory path is set that was last addressed
218     (eg by the SfxFileDialog).
219 
220     [Cross-reference]
221     <SfxApplication::GetLastDir_Impl()>
222 */
223 
224 {
225     pImpl->aLastDir = rNewDir;
226 }
227 
228 
229 void SfxApplication::ResetLastDir()
230 {
231     pImpl->aLastDir.clear();
232 }
233 
234 
235 SfxDispatcher* SfxApplication::GetDispatcher_Impl()
236 {
237     return pImpl->pViewFrame? pImpl->pViewFrame->GetDispatcher(): pImpl->pAppDispat;
238 }
239 
240 
241 void SfxApplication::SetViewFrame_Impl( SfxViewFrame *pFrame )
242 {
243     if ( pFrame != pImpl->pViewFrame )
244     {
245         SfxViewFrame *pOldFrame = pImpl->pViewFrame;
246 
247         // DocWinActivate : both frames belong to the same TopWindow
248         // TopWinActivate : both frames belong to different TopWindows
249 
250         bool bTaskActivate = pOldFrame != pFrame;
251 
252         if ( pOldFrame )
253         {
254             if ( bTaskActivate )
255                 NotifyEvent( SfxViewEventHint( SfxEventHintId::DeactivateDoc, GlobalEventConfig::GetEventName(GlobalEventId::DEACTIVATEDOC), pOldFrame->GetObjectShell(), pOldFrame->GetFrame().GetController() ) );
256             pOldFrame->DoDeactivate( bTaskActivate, pFrame );
257 
258             if( pOldFrame->GetProgress() )
259                 pOldFrame->GetProgress()->Suspend();
260         }
261 
262         pImpl->pViewFrame = pFrame;
263 
264         if( pFrame )
265         {
266             pFrame->DoActivate( bTaskActivate );
267             if ( bTaskActivate && pFrame->GetObjectShell() )
268             {
269                 pFrame->GetObjectShell()->PostActivateEvent_Impl( pFrame );
270                 NotifyEvent(SfxViewEventHint(SfxEventHintId::ActivateDoc, GlobalEventConfig::GetEventName(GlobalEventId::ACTIVATEDOC), pFrame->GetObjectShell(), pFrame->GetFrame().GetController() ) );
271             }
272 
273             SfxProgress *pProgress = pFrame->GetProgress();
274             if ( pProgress )
275             {
276                 if( pProgress->IsSuspended() )
277                     pProgress->Resume();
278                 else
279                     pProgress->SetState( pProgress->GetState() );
280             }
281 
282             if ( pImpl->pViewFrame->GetViewShell() )
283             {
284                 SfxDispatcher* pDisp = pImpl->pViewFrame->GetDispatcher();
285                 pDisp->Flush();
286                 pDisp->Update_Impl(true);
287             }
288         }
289     }
290 
291     // even if the frame actually didn't change, ensure its document is forwarded
292     // to SfxObjectShell::SetCurrentComponent.
293     // Otherwise, the CurrentComponent might not be correct, in case it has meanwhile
294     // been reset to some other document, by some non-SFX component. #i49133#
295     if ( pFrame && pFrame->GetViewShell() )
296         pFrame->GetViewShell()->SetCurrentDocument();
297 }
298 
299 void SfxApplication::SetProgress_Impl
300 (
301     SfxProgress *pProgress
302 )
303 {
304     DBG_ASSERT( ( !pImpl->pProgress && pProgress ) ||
305                 ( pImpl->pProgress && !pProgress ),
306                 "Progress activation/deactivation mismatch" );
307 
308     if ( pImpl->pProgress && pProgress )
309     {
310         pImpl->pProgress->Suspend();
311         delete pImpl->pProgress;
312     }
313 
314     pImpl->pProgress = pProgress;
315 }
316 
317 
318 sal_uInt16 SfxApplication::GetFreeIndex()
319 {
320     return pImpl->aIndexBitSet.GetFreeIndex()+1;
321 }
322 
323 
324 void SfxApplication::ReleaseIndex(sal_uInt16 i)
325 {
326     pImpl->aIndexBitSet.ReleaseIndex(i-1);
327 }
328 
329 
330 vcl::Window* SfxApplication::GetTopWindow() const
331 {
332     SfxWorkWindow* pWork = GetWorkWindow_Impl( SfxViewFrame::Current() );
333     return pWork ? pWork->GetWindow() : nullptr;
334 }
335 
336 SfxTbxCtrlFactArr_Impl&     SfxApplication::GetTbxCtrlFactories_Impl() const
337 {
338     return *pImpl->pTbxCtrlFac;
339 }
340 
341 SfxStbCtrlFactArr_Impl&     SfxApplication::GetStbCtrlFactories_Impl() const
342 {
343     return *pImpl->pStbCtrlFac;
344 }
345 
346 SfxViewFrameArr_Impl&       SfxApplication::GetViewFrames_Impl() const
347 {
348     return *pImpl->pViewFrames;
349 }
350 
351 SfxViewShellArr_Impl&       SfxApplication::GetViewShells_Impl() const
352 {
353     return *pImpl->pViewShells;
354 }
355 
356 SfxObjectShellArr_Impl&     SfxApplication::GetObjectShells_Impl() const
357 {
358     return *pImpl->pObjShells;
359 }
360 
361 void SfxApplication::Invalidate( sal_uInt16 nId )
362 {
363     for( SfxViewFrame* pFrame = SfxViewFrame::GetFirst(); pFrame; pFrame = SfxViewFrame::GetNext( *pFrame ) )
364         Invalidate_Impl( pFrame->GetBindings(), nId );
365 }
366 
367 #if HAVE_FEATURE_SCRIPTING
368 
369 #ifndef DISABLE_DYNLOADING
370 
371 typedef long (*basicide_handle_basic_error)(void const *);
372 typedef void (*basicide_macro_organizer)(void *, sal_Int16);
373 
374 extern "C" { static void thisModule() {} }
375 
376 #else
377 
378 extern "C" long basicide_handle_basic_error(void const*);
379 extern "C" void basicide_macro_organizer(void*, sal_Int16);
380 
381 #endif
382 
383 #endif
384 
385 IMPL_STATIC_LINK( SfxApplication, GlobalBasicErrorHdl_Impl, StarBASIC*, pStarBasic, bool )
386 {
387 #if !HAVE_FEATURE_SCRIPTING
388     (void) pStarBasic;
389     return false;
390 #else
391 
392 #ifndef DISABLE_DYNLOADING
393     // load basctl module
394     osl::Module aMod;
395     aMod.loadRelative(&thisModule, SVLIBRARY("basctl"));
396 
397     // get symbol
398     basicide_handle_basic_error pSymbol = reinterpret_cast<basicide_handle_basic_error>(aMod.getFunctionSymbol("basicide_handle_basic_error"));
399 
400     aMod.release();
401 
402     // call basicide_handle_basic_error in basctl
403     bool bRet = pSymbol && pSymbol( pStarBasic );
404 
405 #else
406 
407     bool bRet = basicide_handle_basic_error( pStarBasic );
408 
409 #endif
410 
411     return bRet;
412 
413 #endif
414 }
415 
416 bool SfxApplication::IsXScriptURL( const OUString& rScriptURL )
417 {
418     bool result = false;
419 
420 #if !HAVE_FEATURE_SCRIPTING
421     (void) rScriptURL;
422 #else
423     css::uno::Reference< css::uno::XComponentContext > xContext =
424             ::comphelper::getProcessComponentContext();
425 
426     css::uno::Reference< css::uri::XUriReferenceFactory >
427             xFactory = css::uri::UriReferenceFactory::create( xContext );
428 
429     try
430     {
431         css::uno::Reference< css::uri::XVndSunStarScriptUrl >
432                 xUrl( xFactory->parse( rScriptURL ),  css::uno::UNO_QUERY );
433 
434         if ( xUrl.is() )
435         {
436             result = true;
437         }
438     }
439     catch (const css::uno::RuntimeException&)
440     {
441         // ignore, will just return FALSE
442     }
443 #endif
444     return result;
445 }
446 
447 OUString
448 SfxApplication::ChooseScript(weld::Window *pParent)
449 {
450     OUString aScriptURL;
451 
452 #if HAVE_FEATURE_SCRIPTING
453     SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
454     SAL_INFO( "sfx.appl", "create selector dialog");
455 
456     const SfxViewFrame* pViewFrame = SfxViewFrame::Current();
457     const SfxFrame* pFrame = pViewFrame ? &pViewFrame->GetFrame() : nullptr;
458     uno::Reference< frame::XFrame > xFrame( pFrame ? pFrame->GetFrameInterface() : uno::Reference< frame::XFrame >() );
459 
460     ScopedVclPtr<AbstractScriptSelectorDialog> pDlg(pFact->CreateScriptSelectorDialog(pParent, xFrame));
461 
462     SAL_INFO( "sfx.appl", "done, now exec it");
463 
464     sal_uInt16 nRet = pDlg->Execute();
465 
466     SAL_INFO( "sfx.appl", "has returned");
467 
468     if ( nRet == RET_OK )
469     {
470         aScriptURL = pDlg->GetScriptURL();
471     }
472 #else
473     (void) pParent;
474 #endif
475     return aScriptURL;
476 }
477 
478 void SfxApplication::MacroOrganizer(weld::Window* pParent, sal_Int16 nTabId)
479 {
480 #if !HAVE_FEATURE_SCRIPTING
481     (void) pParent;
482     (void) nTabId;
483 #else
484 
485 #ifndef DISABLE_DYNLOADING
486     // load basctl module
487     osl::Module aMod;
488     aMod.loadRelative(&thisModule, SVLIBRARY("basctl"));
489 
490     // get symbol
491     basicide_macro_organizer pSymbol = reinterpret_cast<basicide_macro_organizer>(aMod.getFunctionSymbol("basicide_macro_organizer"));
492 
493     aMod.release();
494 
495     SAL_WARN_IF(!pSymbol, "sfx.appl", "SfxApplication::MacroOrganizer, no symbol!");
496     if (!pSymbol)
497         return;
498 
499     // call basicide_macro_organizer in basctl
500     pSymbol(pParent, nTabId);
501 
502 #else
503 
504     basicide_macro_organizer(pParent, nTabId);
505 
506 #endif
507 
508 #endif
509 }
510 
511 ErrCode SfxApplication::CallBasic( const OUString& rCode, BasicManager* pMgr, SbxArray* pArgs, SbxValue* pRet )
512 {
513 #if !HAVE_FEATURE_SCRIPTING
514     (void) rCode;
515     (void) pMgr;
516     (void) pArgs;
517     (void) pRet;
518     return ERRCODE_BASIC_CANNOT_LOAD;
519 #else
520     (void) ERRCODE_BASIC_CANNOT_LOAD; // So that the !HAVE_FEATURE_SCRIPTING case isn't broken again by IWYU
521     return pMgr->ExecuteMacro( rCode, pArgs, pRet);
522 #endif
523 }
524 
525 sfx2::sidebar::Theme & SfxApplication::GetSidebarTheme()
526 {
527     if (!pImpl->m_pSidebarTheme.is())
528     {
529         pImpl->m_pSidebarTheme.set(new sfx2::sidebar::Theme);
530         pImpl->m_pSidebarTheme->InitializeTheme();
531     }
532     return *pImpl->m_pSidebarTheme;
533 }
534 
535 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
536