Coverage Report

Created: 2025-11-16 09:57

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