Coverage Report

Created: 2026-11-06 11:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sfx2/source/notebookbar/SfxNotebookBar.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
10
#include <vcl/builder.hxx>
11
#include <sfx2/bindings.hxx>
12
#include <sfx2/viewsh.hxx>
13
#include <sfx2/dispatch.hxx>
14
#include <sfx2/notebookbar/SfxNotebookBar.hxx>
15
#include <vcl/notebookbar/notebookbar.hxx>
16
#include <vcl/syswin.hxx>
17
#include <sfx2/viewfrm.hxx>
18
#include <sfx2/sfxsids.hrc>
19
#include <sfx2/weldutils.hxx>
20
#include <comphelper/processfactory.hxx>
21
#include <com/sun/star/frame/UnknownModuleException.hpp>
22
#include <com/sun/star/frame/XLayoutManager.hpp>
23
#include <officecfg/Office/UI/ToolbarMode.hxx>
24
#include <com/sun/star/frame/XModuleManager.hpp>
25
#include <com/sun/star/frame/ModuleManager.hpp>
26
#include <com/sun/star/beans/XPropertySet.hpp>
27
#include <unotools/confignode.hxx>
28
#include <comphelper/types.hxx>
29
#include <framework/addonsoptions.hxx>
30
#include <vcl/notebookbar/NotebookBarAddonsItem.hxx>
31
#include <vector>
32
#include <unordered_map>
33
34
using namespace sfx2;
35
using namespace css::uno;
36
using namespace css::ui;
37
using namespace css;
38
39
constexpr OUString MENUBAR_STR = u"private:resource/menubar/menubar"_ustr;
40
41
const char MERGE_NOTEBOOKBAR_URL[] = "URL";
42
43
bool SfxNotebookBar::m_bLock = false;
44
bool SfxNotebookBar::m_bHide = false;
45
46
static void NotebookbarAddonValues(
47
    std::vector<Image>& aImageValues,
48
    std::vector<css::uno::Sequence<css::uno::Sequence<css::beans::PropertyValue>>>&
49
        aExtensionValues)
50
0
{
51
0
    framework::AddonsOptions aAddonsItems;
52
53
0
    for (int nIdx = 0; nIdx < aAddonsItems.GetAddonsNotebookBarCount(); nIdx++)
54
0
    {
55
0
        const css::uno::Sequence<css::uno::Sequence<css::beans::PropertyValue>>& aExtension
56
0
            = aAddonsItems.GetAddonsNotebookBarPart(nIdx);
57
0
        for (const css::uno::Sequence<css::beans::PropertyValue>& rExtensionVal : aExtension)
58
0
        {
59
0
            Image aImage;
60
0
            bool isBigImage = true;
61
0
            for (const auto& rProp : rExtensionVal)
62
0
            {
63
0
                if (rProp.Name == MERGE_NOTEBOOKBAR_URL)
64
0
                {
65
0
                    OUString sImage;
66
0
                    rProp.Value >>= sImage;
67
0
                    aImage = Image(aAddonsItems.GetImageFromURL(sImage, isBigImage));
68
0
                }
69
0
            }
70
0
            aImageValues.push_back(std::move(aImage));
71
0
        }
72
0
        aExtensionValues.push_back(aExtension);
73
0
    }
74
0
}
75
76
static Reference<frame::XLayoutManager> lcl_getLayoutManager( const Reference<frame::XFrame>& xFrame )
77
0
{
78
0
    css::uno::Reference<css::frame::XLayoutManager> xLayoutManager;
79
80
0
    if (xFrame.is())
81
0
    {
82
0
        Reference<css::beans::XPropertySet> xPropSet(xFrame, UNO_QUERY);
83
84
0
        if (xPropSet.is())
85
0
        {
86
0
            Any aValue = xPropSet->getPropertyValue(u"LayoutManager"_ustr);
87
0
            aValue >>= xLayoutManager;
88
0
        }
89
0
    }
90
91
0
    return xLayoutManager;
92
0
}
93
94
static OUString lcl_getAppName( vcl::EnumContext::Application eApp )
95
6.21k
{
96
6.21k
    switch ( eApp )
97
6.21k
    {
98
6.21k
        case vcl::EnumContext::Application::Writer:
99
6.21k
            return u"Writer"_ustr;
100
0
        case vcl::EnumContext::Application::Calc:
101
0
            return u"Calc"_ustr;
102
0
        case vcl::EnumContext::Application::Impress:
103
0
            return u"Impress"_ustr;
104
0
        case vcl::EnumContext::Application::Draw:
105
0
            return u"Draw"_ustr;
106
0
        case vcl::EnumContext::Application::Formula:
107
0
            return u"Formula"_ustr;
108
0
        default:
109
0
            return OUString();
110
6.21k
    }
111
6.21k
}
112
113
static void lcl_setNotebookbarFileName( vcl::EnumContext::Application eApp, const OUString& sFileName )
114
0
{
115
0
    std::shared_ptr<comphelper::ConfigurationChanges> aBatch(
116
0
                comphelper::ConfigurationChanges::create() );
117
0
    switch ( eApp )
118
0
    {
119
0
        case vcl::EnumContext::Application::Writer:
120
0
            officecfg::Office::UI::ToolbarMode::ActiveWriter::set( sFileName, aBatch );
121
0
            break;
122
0
        case vcl::EnumContext::Application::Calc:
123
0
            officecfg::Office::UI::ToolbarMode::ActiveCalc::set( sFileName, aBatch );
124
0
            break;
125
0
        case vcl::EnumContext::Application::Impress:
126
0
            officecfg::Office::UI::ToolbarMode::ActiveImpress::set( sFileName, aBatch );
127
0
            break;
128
0
        case vcl::EnumContext::Application::Draw:
129
0
            officecfg::Office::UI::ToolbarMode::ActiveDraw::set( sFileName, aBatch );
130
0
            break;
131
0
        default:
132
0
            break;
133
0
    }
134
0
    aBatch->commit();
135
0
}
136
137
static OUString lcl_getNotebookbarFileName( vcl::EnumContext::Application eApp )
138
0
{
139
0
    switch ( eApp )
140
0
    {
141
0
        case vcl::EnumContext::Application::Writer:
142
0
            return officecfg::Office::UI::ToolbarMode::ActiveWriter::get();
143
0
        case vcl::EnumContext::Application::Calc:
144
0
            return officecfg::Office::UI::ToolbarMode::ActiveCalc::get();
145
0
        case vcl::EnumContext::Application::Impress:
146
0
            return officecfg::Office::UI::ToolbarMode::ActiveImpress::get();
147
0
        case vcl::EnumContext::Application::Draw:
148
0
            return officecfg::Office::UI::ToolbarMode::ActiveDraw::get();
149
150
0
        default:
151
0
            break;
152
0
    }
153
0
    return OUString();
154
0
}
155
156
static utl::OConfigurationTreeRoot lcl_getCurrentImplConfigRoot()
157
0
{
158
0
    return utl::OConfigurationTreeRoot(::comphelper::getProcessComponentContext(),
159
0
                                       u"org.openoffice.Office.UI.ToolbarMode/"_ustr,
160
0
                                       true);
161
0
}
162
163
static utl::OConfigurationNode lcl_getCurrentImplConfigNode(const Reference<css::frame::XFrame>& xFrame,
164
                                                                  utl::OConfigurationTreeRoot const & rNotebookbarNode )
165
0
{
166
0
    if (!rNotebookbarNode.isValid())
167
0
        return utl::OConfigurationNode();
168
169
0
    const Reference<frame::XModuleManager> xModuleManager  = frame::ModuleManager::create( ::comphelper::getProcessComponentContext() );
170
171
0
    vcl::EnumContext::Application eApp = vcl::EnumContext::GetApplicationEnum( xModuleManager->identify( xFrame ) );
172
0
    OUString aActive = lcl_getNotebookbarFileName( eApp );
173
174
0
    const utl::OConfigurationNode aImplsNode = rNotebookbarNode.openNode("Applications/" + lcl_getAppName( eApp) + "/Modes");
175
0
    const Sequence<OUString> aModeNodeNames( aImplsNode.getNodeNames() );
176
177
0
    for ( const auto& rModeNodeName : aModeNodeNames )
178
0
    {
179
0
        utl::OConfigurationNode aImplNode( aImplsNode.openNode( rModeNodeName ) );
180
0
        if ( !aImplNode.isValid() )
181
0
            continue;
182
183
0
        OUString aCommandArg = comphelper::getString( aImplNode.getNodeValue( u"CommandArg"_ustr ) );
184
185
0
        if ( aCommandArg == aActive )
186
0
        {
187
0
            return aImplNode;
188
0
        }
189
0
    }
190
191
0
    return utl::OConfigurationNode();
192
0
}
193
194
void SfxNotebookBar::CloseMethod(SfxBindings& rBindings)
195
0
{
196
0
    SfxFrame& rFrame = rBindings.GetDispatcher_Impl()->GetFrame()->GetFrame();
197
0
    CloseMethod(rFrame.GetSystemWindow());
198
0
}
199
200
void SfxNotebookBar::CloseMethod(SystemWindow* pSysWindow)
201
0
{
202
0
    if (pSysWindow)
203
0
    {
204
0
        if(pSysWindow->GetNotebookBar())
205
0
            pSysWindow->CloseNotebookBar();
206
0
        if (SfxViewFrame* pViewFrm = SfxViewFrame::Current())
207
0
            SfxNotebookBar::ShowMenubar(pViewFrm, true);
208
0
    }
209
0
}
210
211
void SfxNotebookBar::LockNotebookBar()
212
0
{
213
0
    m_bHide = true;
214
0
    m_bLock = true;
215
0
}
216
217
void SfxNotebookBar::UnlockNotebookBar()
218
0
{
219
0
    m_bHide = false;
220
0
    m_bLock = false;
221
0
}
222
223
bool SfxNotebookBar::IsActive(bool bConsiderSingleToolbar)
224
6.21k
{
225
6.21k
    if (m_bHide)
226
0
        return false;
227
228
6.21k
    vcl::EnumContext::Application eApp = vcl::EnumContext::Application::Any;
229
230
6.21k
    if (SfxViewFrame* pViewFrm = SfxViewFrame::Current())
231
6.21k
    {
232
6.21k
        const Reference<frame::XFrame>& xFrame = pViewFrm->GetFrame().GetFrameInterface();
233
6.21k
        if (!xFrame.is())
234
0
            return false;
235
236
6.21k
        const Reference<frame::XModuleManager> xModuleManager  = frame::ModuleManager::create( ::comphelper::getProcessComponentContext() );
237
6.21k
        try
238
6.21k
        {
239
6.21k
            eApp = vcl::EnumContext::GetApplicationEnum(xModuleManager->identify(xFrame));
240
6.21k
        }
241
6.21k
        catch (css::uno::Exception& e)
242
6.21k
        {
243
0
            SAL_WARN("sfx.appl", "SfxNotebookBar::IsActive(): " + e.Message);
244
0
            return false;
245
0
        }
246
6.21k
    }
247
0
    else
248
0
        return false;
249
250
6.21k
    OUString appName(lcl_getAppName( eApp ));
251
252
6.21k
    if (appName.isEmpty())
253
0
        return false;
254
255
256
6.21k
    OUString aPath = "org.openoffice.Office.UI.ToolbarMode/Applications/" + appName;
257
258
6.21k
    const utl::OConfigurationTreeRoot aAppNode(
259
6.21k
                                        ::comphelper::getProcessComponentContext(),
260
6.21k
                                        aPath,
261
6.21k
                                        false);
262
6.21k
    if ( !aAppNode.isValid() )
263
6.21k
        return false;
264
265
0
    OUString aActive = comphelper::getString( aAppNode.getNodeValue( u"Active"_ustr ) );
266
267
0
    if (bConsiderSingleToolbar && aActive == "Single")
268
0
        return true;
269
270
0
    const utl::OConfigurationNode aModesNode = aAppNode.openNode(u"Modes"_ustr);
271
0
    const Sequence<OUString> aModeNodeNames( aModesNode.getNodeNames() );
272
273
0
    for ( const auto& rModeNodeName : aModeNodeNames )
274
0
    {
275
0
        const utl::OConfigurationNode aModeNode( aModesNode.openNode( rModeNodeName ) );
276
0
        if ( !aModeNode.isValid() )
277
0
            continue;
278
279
0
        OUString aCommandArg = comphelper::getString( aModeNode.getNodeValue( u"CommandArg"_ustr ) );
280
281
0
        if ( aCommandArg == aActive )
282
0
        {
283
0
            return comphelper::getBOOL( aModeNode.getNodeValue( u"HasNotebookbar"_ustr ) );
284
0
        }
285
0
    }
286
0
    return false;
287
0
}
288
289
void SfxNotebookBar::ExecMethod(SfxBindings& rBindings, const OUString& rUIName)
290
0
{
291
    // Save active UI file name
292
0
    if (!rUIName.isEmpty())
293
0
    {
294
0
        if (SfxViewFrame* pViewFrm = SfxViewFrame::Current())
295
0
        {
296
0
            const Reference<frame::XFrame>& xFrame = pViewFrm->GetFrame().GetFrameInterface();
297
0
            if (xFrame.is())
298
0
            {
299
0
                const Reference<frame::XModuleManager> xModuleManager  = frame::ModuleManager::create( ::comphelper::getProcessComponentContext() );
300
0
                vcl::EnumContext::Application eApp = vcl::EnumContext::GetApplicationEnum(xModuleManager->identify(xFrame));
301
0
                lcl_setNotebookbarFileName( eApp, rUIName );
302
0
            }
303
0
        }
304
0
    }
305
306
    // trigger the StateMethod
307
0
    rBindings.Invalidate(SID_NOTEBOOKBAR);
308
0
    rBindings.Update();
309
0
}
310
311
bool SfxNotebookBar::StateMethod(SfxBindings& rBindings, std::u16string_view rUIFile,
312
                                 bool bReloadNotebookbar)
313
6.21k
{
314
6.21k
    SfxFrame& rFrame = rBindings.GetDispatcher_Impl()->GetFrame()->GetFrame();
315
6.21k
    return StateMethod(rFrame.GetSystemWindow(), rFrame.GetFrameInterface(), rUIFile,
316
6.21k
                       bReloadNotebookbar);
317
6.21k
}
318
319
bool SfxNotebookBar::StateMethod(SystemWindow* pSysWindow,
320
                                 const Reference<css::frame::XFrame>& xFrame,
321
                                 std::u16string_view rUIFile, bool bReloadNotebookbar)
322
6.21k
{
323
6.21k
    if (!pSysWindow)
324
0
    {
325
0
        SfxViewFrame* pViewFrm = SfxViewFrame::Current();
326
0
        if (pViewFrm && pViewFrm->GetWindow().GetSystemWindow())
327
0
            pSysWindow = pViewFrm->GetWindow().GetSystemWindow();
328
0
        else
329
0
            return false;
330
0
    }
331
332
6.21k
    if (IsActive())
333
0
    {
334
0
        const css::uno::Reference<css::uno::XComponentContext>& xContext = comphelper::getProcessComponentContext();
335
0
        const Reference<frame::XModuleManager> xModuleManager  = frame::ModuleManager::create( xContext );
336
0
        OUString aModuleName = xModuleManager->identify( xFrame );
337
0
        vcl::EnumContext::Application eApp = vcl::EnumContext::GetApplicationEnum( aModuleName );
338
339
0
        const OUString sFile = lcl_getNotebookbarFileName(eApp);
340
341
0
        const OUString sNewFile = rUIFile + sFile;
342
0
        OUString sCurrentFile;
343
0
        VclPtr<NotebookBar> pNotebookBar = pSysWindow->GetNotebookBar();
344
0
        if ( pNotebookBar )
345
0
            sCurrentFile = pNotebookBar->GetUIFilePath();
346
347
0
        bool bChangedFile = sNewFile != sCurrentFile;
348
349
0
        if ((!sFile.isEmpty() && bChangedFile) || (!pNotebookBar || !pNotebookBar->IsVisible())
350
0
            || bReloadNotebookbar)
351
0
        {
352
            //Addons For Notebookbar
353
0
            std::vector<Image> aImageValues;
354
0
            std::vector<css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > > > aExtensionValues;
355
0
            std::unique_ptr<NotebookBarAddonsItem> pNotebookBarAddonsItem
356
0
                = std::make_unique<NotebookBarAddonsItem>();
357
0
            NotebookbarAddonValues(aImageValues, aExtensionValues);
358
0
            pNotebookBarAddonsItem->aAddonValues = std::move(aExtensionValues);
359
0
            pNotebookBarAddonsItem->aImageValues = std::move(aImageValues);
360
361
            // tdf#164899 don't call SystemWindow::SetNotebookBar recursively
362
            // if NoteBookBar is in process of getting set
363
0
            if (pSysWindow->isSettingUpNoteBookBar())
364
0
                return false;
365
366
0
            RemoveListeners(pSysWindow);
367
368
0
            pSysWindow->SetNotebookBar(sNewFile, xFrame, std::move(pNotebookBarAddonsItem),
369
0
                                       bReloadNotebookbar);
370
0
            pNotebookBar = pSysWindow->GetNotebookBar();
371
0
            pNotebookBar->Show();
372
373
0
            pNotebookBar->GetParent()->Resize();
374
375
0
            utl::OConfigurationTreeRoot aRoot(lcl_getCurrentImplConfigRoot());
376
0
            const utl::OConfigurationNode aModeNode(lcl_getCurrentImplConfigNode(xFrame, aRoot));
377
0
            SfxNotebookBar::ShowMenubar( comphelper::getBOOL( aModeNode.getNodeValue( u"HasMenubar"_ustr ) ) );
378
379
0
            SfxViewFrame* pView = SfxViewFrame::Current();
380
381
0
            if(pView)
382
0
            {
383
0
                pNotebookBar->SetupListener(true);
384
0
            }
385
0
        }
386
387
0
        return true;
388
0
    }
389
6.21k
    else if (auto pNotebookBar = pSysWindow->GetNotebookBar())
390
0
    {
391
0
        vcl::Window* pParent = pNotebookBar->GetParent();
392
0
        pSysWindow->CloseNotebookBar();
393
0
        pParent->Resize();
394
0
        SfxNotebookBar::ShowMenubar(true);
395
0
    }
396
397
6.21k
    return false;
398
6.21k
}
399
400
void SfxNotebookBar::RemoveListeners(SystemWindow const * pSysWindow)
401
0
{
402
0
    if (const auto& pNotebookBar = pSysWindow->GetNotebookBar())
403
0
    {
404
0
        pNotebookBar->SetupListener(false);
405
0
    }
406
0
}
407
408
void SfxNotebookBar::ShowMenubar(bool bShow)
409
0
{
410
0
    if (m_bLock)
411
0
        return;
412
413
0
    m_bLock = true;
414
415
0
    Reference<frame::XFrame> xFrame;
416
0
    vcl::EnumContext::Application eCurrentApp = vcl::EnumContext::Application::NONE;
417
0
    const uno::Reference< uno::XComponentContext >& xContext = comphelper::getProcessComponentContext();
418
0
    const Reference<frame::XModuleManager> xModuleManager = frame::ModuleManager::create( xContext );
419
420
0
    if (SfxViewFrame* pViewFrm = SfxViewFrame::Current())
421
0
    {
422
0
        xFrame = pViewFrm->GetFrame().GetFrameInterface();
423
0
        eCurrentApp = vcl::EnumContext::GetApplicationEnum( xModuleManager->identify( xFrame ) );
424
0
    }
425
426
0
    SfxViewFrame* pViewFrame = SfxViewFrame::GetFirst();
427
0
    while( pViewFrame )
428
0
    {
429
0
        xFrame = pViewFrame->GetFrame().GetFrameInterface();
430
0
        if ( xFrame.is() )
431
0
        {
432
0
            vcl::EnumContext::Application eApp =
433
0
                    vcl::EnumContext::GetApplicationEnum( xModuleManager->identify( xFrame ) );
434
435
0
            if ( eApp == eCurrentApp )
436
0
            {
437
0
                const Reference<frame::XLayoutManager> xLayoutManager =
438
0
                                                        lcl_getLayoutManager( xFrame );
439
440
0
                if (xLayoutManager.is())
441
0
                {
442
0
                    if (xLayoutManager->getElement(MENUBAR_STR).is())
443
0
                    {
444
0
                        if (xLayoutManager->isElementVisible(MENUBAR_STR) && !bShow)
445
0
                            xLayoutManager->hideElement(MENUBAR_STR);
446
0
                        else if(!xLayoutManager->isElementVisible(MENUBAR_STR) && bShow)
447
0
                            xLayoutManager->showElement(MENUBAR_STR);
448
0
                    }
449
0
                }
450
0
            }
451
0
        }
452
453
0
        pViewFrame = SfxViewFrame::GetNext( *pViewFrame );
454
0
    }
455
0
    m_bLock = false;
456
0
}
457
458
void SfxNotebookBar::ShowMenubar(SfxViewFrame const * pViewFrame, bool bShow)
459
0
{
460
0
    if (m_bLock)
461
0
        return;
462
463
0
    m_bLock = true;
464
465
0
    Reference<frame::XFrame> xFrame = pViewFrame->GetFrame().GetFrameInterface();
466
0
    if (xFrame.is())
467
0
    {
468
0
        const Reference<frame::XLayoutManager> xLayoutManager = lcl_getLayoutManager(xFrame);
469
0
        if (xLayoutManager.is())
470
0
        {
471
0
            if (xLayoutManager->getElement(MENUBAR_STR).is())
472
0
            {
473
0
                if (xLayoutManager->isElementVisible(MENUBAR_STR) && !bShow)
474
0
                    xLayoutManager->hideElement(MENUBAR_STR);
475
0
                else if (!xLayoutManager->isElementVisible(MENUBAR_STR) && bShow)
476
0
                    xLayoutManager->showElement(MENUBAR_STR);
477
0
            }
478
0
        }
479
0
    }
480
0
    m_bLock = false;
481
0
}
482
483
void SfxNotebookBar::ToggleMenubar()
484
0
{
485
0
    SfxViewFrame* pViewFrm = SfxViewFrame::Current();
486
0
    if (!pViewFrm)
487
0
        return;
488
489
0
    const Reference<frame::XFrame>& xFrame = pViewFrm->GetFrame().GetFrameInterface();
490
0
    if (!xFrame.is())
491
0
        return;
492
493
0
    const Reference<frame::XLayoutManager> xLayoutManager =
494
0
                                            lcl_getLayoutManager(xFrame);
495
496
0
    bool bShow = true;
497
0
    if (xLayoutManager.is() && xLayoutManager->getElement(MENUBAR_STR).is())
498
0
    {
499
0
        if (xLayoutManager->isElementVisible(MENUBAR_STR))
500
0
        {
501
0
            SfxNotebookBar::ShowMenubar(false);
502
0
            bShow = false;
503
0
        }
504
0
        else
505
0
            SfxNotebookBar::ShowMenubar(true);
506
0
    }
507
508
    // Save menubar settings
509
0
    if (IsActive())
510
0
    {
511
0
        utl::OConfigurationTreeRoot aRoot(lcl_getCurrentImplConfigRoot());
512
0
        utl::OConfigurationNode aModeNode(lcl_getCurrentImplConfigNode(xFrame, aRoot));
513
0
        aModeNode.setNodeValue( u"HasMenubar"_ustr, toAny<bool>( bShow ) );
514
0
        aRoot.commit();
515
0
    }
516
0
}
517
518
void SfxNotebookBar::ReloadNotebookBar(std::u16string_view sUIPath)
519
0
{
520
0
    if (!SfxNotebookBar::IsActive())
521
0
        return;
522
0
    SfxViewShell* pViewShell = SfxViewShell::Current();
523
0
    if (!pViewShell)
524
0
        return;
525
0
    sfx2::SfxNotebookBar::StateMethod(pViewShell->GetViewFrame().GetBindings(), sUIPath, true);
526
0
}
527
528
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */