Coverage Report

Created: 2026-11-06 11:29

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/MessageDialog.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
62.0M
{
73
62.0M
    return g_pSfxApplication;
74
62.0M
}
75
76
void SfxApplication::SetModule(SfxToolsModule nSharedLib, std::unique_ptr<SfxModule> pModule)
77
23
{
78
23
    assert(g_pSfxApplication != nullptr);
79
80
23
    g_pSfxApplication->pImpl->aModules[nSharedLib] = std::move(pModule);
81
23
}
82
83
SfxModule* SfxApplication::GetModule(SfxToolsModule nSharedLib)
84
50.5M
{
85
50.5M
    if (!g_pSfxApplication) // It is possible GetModule is called before SfxApplication is initialised via GetOrCreate()
86
23
        return nullptr;
87
50.5M
    return g_pSfxApplication->pImpl->aModules[nSharedLib].get();
88
50.5M
}
89
90
SfxApplication* SfxApplication::GetOrCreate()
91
26
{
92
26
    static std::mutex theApplicationMutex;
93
94
    // SFX on demand
95
26
    std::unique_lock aGuard(theApplicationMutex);
96
26
    if (!g_pSfxApplication)
97
23
    {
98
23
        SAL_INFO( "sfx.appl", "SfxApplication::SetApp" );
99
100
23
        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
23
        g_pSfxApplication->Initialize_Impl();
106
107
23
        ::framework::SetRefreshToolbars( RefreshToolbars );
108
23
        ::framework::SetToolBoxControllerCreator( SfxToolBoxControllerFactory );
109
23
        ::framework::SetStatusBarControllerCreator( SfxStatusBarControllerFactory );
110
23
        ::framework::SetDockingWindowCreator( SfxDockingWindowFactory );
111
23
        ::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
23
    }
128
26
    return g_pSfxApplication;
129
26
}
130
131
SfxApplication::SfxApplication()
132
23
    : pImpl( new SfxAppData_Impl )
133
23
{
134
23
    SetName( u"StarOffice"_ustr );
135
136
23
    SAL_INFO( "sfx.appl", "{ initialize DDE" );
137
138
23
    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
23
    (void)bOk;
152
23
#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
23
    SAL_INFO( "sfx.appl", "} initialize DDE" );
163
23
}
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
12.4k
{
194
12.4k
    if ( pFrame != pImpl->pViewFrame )
195
12.4k
    {
196
12.4k
        SfxViewFrame *pOldFrame = pImpl->pViewFrame;
197
198
        // DocWinActivate : both frames belong to the same TopWindow
199
        // TopWinActivate : both frames belong to different TopWindows
200
201
12.4k
        bool bTaskActivate = pOldFrame != pFrame;
202
203
12.4k
        if ( pOldFrame )
204
6.21k
        {
205
6.21k
            if ( bTaskActivate )
206
6.21k
                NotifyEvent( SfxViewEventHint( SfxEventHintId::DeactivateDoc, GlobalEventConfig::GetEventName(GlobalEventId::DEACTIVATEDOC), pOldFrame->GetObjectShell(), pOldFrame->GetFrame().GetController() ) );
207
208
6.21k
            pOldFrame->DoDeactivate( bTaskActivate, pFrame );
209
210
6.21k
            if( pOldFrame->GetProgress() )
211
0
                pOldFrame->GetProgress()->Suspend();
212
6.21k
        }
213
214
12.4k
        pImpl->pViewFrame = pFrame;
215
216
12.4k
        if( pFrame )
217
6.21k
        {
218
            // Keep SfxViewFrame::Current() consistent with SfxViewFrame::First
219
6.21k
            pImpl->MoveFrameToFirstFrame(*pFrame);
220
6.21k
            SfxViewShell* pViewShell = pFrame->GetViewShell();
221
6.21k
            if (pViewShell)
222
6.21k
            {
223
                // Keep SfxViewShell::Current() consistent with SfxViewShell::First
224
6.21k
                pImpl->MoveShellToFirstShell(*pViewShell);
225
6.21k
            }
226
227
6.21k
            pFrame->DoActivate( bTaskActivate );
228
6.21k
            if ( bTaskActivate && pFrame->GetObjectShell() )
229
6.21k
            {
230
6.21k
                pFrame->GetObjectShell()->PostActivateEvent_Impl( pFrame );
231
6.21k
                NotifyEvent(SfxViewEventHint(SfxEventHintId::ActivateDoc, GlobalEventConfig::GetEventName(GlobalEventId::ACTIVATEDOC), pFrame->GetObjectShell(), pFrame->GetFrame().GetController() ) );
232
6.21k
            }
233
234
6.21k
            SfxProgress *pProgress = pFrame->GetProgress();
235
6.21k
            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
6.21k
            if (pViewShell)
244
6.21k
            {
245
6.21k
                SfxDispatcher* pDisp = pImpl->pViewFrame->GetDispatcher();
246
6.21k
                pDisp->Flush();
247
6.21k
                pDisp->Update_Impl(true);
248
6.21k
            }
249
6.21k
        }
250
12.4k
    }
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
12.4k
    if ( pFrame && pFrame->GetViewShell() )
257
6.21k
        pFrame->GetViewShell()->SetCurrentDocument();
258
12.4k
}
259
260
void SfxApplication::SetProgress_Impl
261
(
262
    SfxProgress *pProgress
263
)
264
154k
{
265
154k
    DBG_ASSERT( ( !pImpl->pProgress && pProgress ) ||
266
154k
                ( pImpl->pProgress && !pProgress ),
267
154k
                "Progress activation/deactivation mismatch" );
268
269
154k
    if ( pImpl->pProgress && pProgress )
270
0
    {
271
0
        pImpl->pProgress->Suspend();
272
0
        delete pImpl->pProgress;
273
0
    }
274
275
154k
    pImpl->pProgress = pProgress;
276
154k
}
277
278
279
sal_uInt16 SfxApplication::GetFreeIndex()
280
6.21k
{
281
6.21k
    return pImpl->aIndexBitSet.GetFreeIndex()+1;
282
6.21k
}
283
284
285
void SfxApplication::ReleaseIndex(sal_uInt16 i)
286
6.21k
{
287
6.21k
    pImpl->aIndexBitSet.ReleaseIndex(i-1);
288
6.21k
}
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
19.6M
{
329
19.6M
    return pImpl->maViewFrames;
330
19.6M
}
331
332
std::vector<SfxViewShell*>& SfxApplication::GetViewShells_Impl() const
333
16.5M
{
334
16.5M
    return pImpl->maViewShells;
335
16.5M
}
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
695k
{
344
695k
    return pImpl->maObjShells;
345
695k
}
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 = Application::CreateMessageDialog(
384
                pViewFrame ? pViewFrame->GetFrameWeld() : nullptr, VclMessageType::Error,
385
                VclButtonsType::Ok, aError);
386
387
            xBox->runAsync(xBox, [](sal_Int32 /*nResult*/) {});
388
        }
389
        return true;
390
    }
391
392
#ifndef DISABLE_DYNLOADING
393
    basicide_handle_basic_error pSymbol = reinterpret_cast<basicide_handle_basic_error>(sfx2::getBasctlFunction("basicide_handle_basic_error"));
394
395
    // call basicide_handle_basic_error in basctl
396
    bool bRet = pSymbol( pStarBasic );
397
398
#else
399
400
    bool bRet = basicide_handle_basic_error( pStarBasic );
401
402
#endif
403
404
    return bRet;
405
406
#endif
407
0
}
408
409
bool SfxApplication::IsXScriptURL( const OUString& rScriptURL )
410
0
{
411
0
    bool result = false;
412
413
0
#if !HAVE_FEATURE_SCRIPTING
414
0
    (void) rScriptURL;
415
#else
416
    const css::uno::Reference< css::uno::XComponentContext >& xContext =
417
            ::comphelper::getProcessComponentContext();
418
419
    css::uno::Reference< css::uri::XUriReferenceFactory >
420
            xFactory = css::uri::UriReferenceFactory::create( xContext );
421
422
    try
423
    {
424
        css::uno::Reference< css::uri::XVndSunStarScriptUrl >
425
                xUrl( xFactory->parse( rScriptURL ),  css::uno::UNO_QUERY );
426
427
        if ( xUrl.is() )
428
        {
429
            result = true;
430
        }
431
    }
432
    catch (const css::uno::RuntimeException&)
433
    {
434
        // ignore, will just return FALSE
435
    }
436
#endif
437
0
    return result;
438
0
}
439
440
OUString
441
SfxApplication::ChooseScript(weld::Window *pParent)
442
0
{
443
0
    OUString aScriptURL;
444
445
#if HAVE_FEATURE_SCRIPTING
446
    SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
447
    SAL_INFO( "sfx.appl", "create selector dialog");
448
449
    const SfxViewFrame* pViewFrame = SfxViewFrame::Current();
450
    const SfxFrame* pFrame = pViewFrame ? &pViewFrame->GetFrame() : nullptr;
451
    uno::Reference< frame::XFrame > xFrame( pFrame ? pFrame->GetFrameInterface() : uno::Reference< frame::XFrame >() );
452
453
    ScopedVclPtr<AbstractScriptSelectorDialog> pDlg(pFact->CreateScriptSelectorDialog(pParent, xFrame));
454
455
    SAL_INFO( "sfx.appl", "done, now exec it");
456
457
    sal_uInt16 nRet = pDlg->Execute();
458
459
    SAL_INFO( "sfx.appl", "has returned");
460
461
    if ( nRet == RET_OK )
462
    {
463
        aScriptURL = pDlg->GetScriptURL();
464
    }
465
#else
466
0
    (void) pParent;
467
0
#endif
468
0
    return aScriptURL;
469
0
}
470
471
void SfxApplication::MacroOrganizer(weld::Window* pParent, const uno::Reference<frame::XFrame>& xDocFrame, sal_Int16 nTabId)
472
0
{
473
0
#if !HAVE_FEATURE_SCRIPTING
474
0
    (void) pParent;
475
0
    (void) nTabId;
476
0
    (void) xDocFrame;
477
#else
478
479
#ifndef DISABLE_DYNLOADING
480
    basicide_macro_organizer pSymbol = reinterpret_cast<basicide_macro_organizer>(sfx2::getBasctlFunction("basicide_macro_organizer"));
481
482
    // call basicide_macro_organizer in basctl
483
    pSymbol(pParent, xDocFrame.get(), nTabId);
484
485
#else
486
487
    basicide_macro_organizer(pParent, xDocFrame.get(), nTabId);
488
489
#endif
490
491
#endif
492
0
}
493
494
ErrCode SfxApplication::CallBasic( const OUString& rCode, BasicManager* pMgr, SbxArray* pArgs, SbxValue* pRet )
495
0
{
496
0
#if !HAVE_FEATURE_SCRIPTING
497
0
    (void) rCode;
498
0
    (void) pMgr;
499
0
    (void) pArgs;
500
0
    (void) pRet;
501
0
    return ERRCODE_BASIC_CANNOT_LOAD;
502
#else
503
    (void) ERRCODE_BASIC_CANNOT_LOAD; // So that the !HAVE_FEATURE_SCRIPTING case isn't broken again by IWYU
504
    return pMgr->ExecuteMacro( rCode, pArgs, pRet);
505
#endif
506
0
}
507
508
sfx2::sidebar::Theme & SfxApplication::GetSidebarTheme()
509
0
{
510
0
    if (!pImpl->m_pSidebarTheme.is())
511
0
    {
512
0
        pImpl->m_pSidebarTheme.set(new sfx2::sidebar::Theme);
513
0
        pImpl->m_pSidebarTheme->InitializeTheme();
514
0
    }
515
0
    return *pImpl->m_pSidebarTheme;
516
0
}
517
518
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */