Coverage Report

Created: 2025-07-07 10:01

/src/libreoffice/svtools/source/control/toolbarmenu.cxx
Line
Count
Source (jump to first uncovered line)
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 <memory>
21
#include <comphelper/lok.hxx>
22
#include <comphelper/processfactory.hxx>
23
24
#include <utility>
25
#include <vcl/taskpanelist.hxx>
26
#include <vcl/svapp.hxx>
27
28
#include <framestatuslistener.hxx>
29
#include <svtools/toolbarmenu.hxx>
30
31
using namespace ::com::sun::star::uno;
32
using namespace ::com::sun::star::lang;
33
using namespace ::com::sun::star::frame;
34
35
namespace {
36
37
SystemWindow* GetTopMostParentSystemWindow(const vcl::Window& rWindow)
38
0
{
39
    // ->manually search topmost system window
40
    // required because their might be another system window between this and the top window
41
0
    vcl::Window* pWindow = rWindow.GetParent();
42
0
    SystemWindow* pTopMostSysWin = nullptr;
43
0
    while ( pWindow )
44
0
    {
45
0
        if ( pWindow->IsSystemWindow() )
46
0
            pTopMostSysWin = static_cast<SystemWindow*>(pWindow);
47
0
        pWindow = pWindow->GetParent();
48
0
    }
49
0
    return pTopMostSysWin;
50
0
}
51
52
class ToolbarPopupStatusListener : public svt::FrameStatusListener
53
{
54
public:
55
    ToolbarPopupStatusListener( const css::uno::Reference< css::frame::XFrame >& xFrame,
56
                                WeldToolbarPopup& rToolbarPopup );
57
58
    virtual void SAL_CALL dispose() override;
59
    virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& Event ) override;
60
61
    WeldToolbarPopup* mpPopup;
62
};
63
64
65
ToolbarPopupStatusListener::ToolbarPopupStatusListener(
66
    const css::uno::Reference< css::frame::XFrame >& xFrame,
67
    WeldToolbarPopup& rToolbarPopup )
68
0
: svt::FrameStatusListener( ::comphelper::getProcessComponentContext(), xFrame )
69
0
, mpPopup( &rToolbarPopup )
70
0
{
71
0
}
72
73
74
void SAL_CALL ToolbarPopupStatusListener::dispose()
75
0
{
76
0
    mpPopup = nullptr;
77
0
    svt::FrameStatusListener::dispose();
78
0
}
79
80
81
void SAL_CALL ToolbarPopupStatusListener::statusChanged( const css::frame::FeatureStateEvent& Event )
82
0
{
83
0
    if( mpPopup )
84
0
        mpPopup->statusChanged( Event );
85
0
}
86
87
}
88
89
void WeldToolbarPopup::AddStatusListener(const OUString& rCommandURL)
90
0
{
91
0
    if (!m_xStatusListener.is())
92
0
        m_xStatusListener.set(new ToolbarPopupStatusListener(m_xFrame, *this));
93
94
0
    m_xStatusListener->addStatusListener(rCommandURL);
95
0
}
96
97
void WeldToolbarPopup::statusChanged(const css::frame::FeatureStateEvent& /*Event*/)
98
0
{
99
0
}
100
101
void InterimToolbarPopup::EndPopupMode()
102
0
{
103
0
    GetDockingManager()->EndPopupMode(this);
104
0
}
105
106
WeldToolbarPopup::WeldToolbarPopup(css::uno::Reference<css::frame::XFrame> xFrame,
107
                                   weld::Widget* pParent, const OUString& rUIFile,
108
                                   const OUString& rId)
109
0
    : m_xBuilder(Application::CreateBuilder(pParent, rUIFile))
110
0
    , m_xTopLevel(m_xBuilder->weld_popover(rId))
111
0
    , m_xContainer(m_xBuilder->weld_container(u"container"_ustr))
112
0
    , m_xFrame(std::move(xFrame))
113
0
{
114
0
    m_xTopLevel->connect_focus_in(LINK(this, WeldToolbarPopup, FocusHdl));
115
0
}
116
117
WeldToolbarPopup::~WeldToolbarPopup()
118
0
{
119
0
    if (m_xStatusListener.is())
120
0
        m_xStatusListener->dispose();
121
0
}
122
123
IMPL_LINK_NOARG(WeldToolbarPopup, FocusHdl, weld::Widget&, void)
124
0
{
125
0
    GrabFocus();
126
0
}
127
128
ToolbarPopupContainer::ToolbarPopupContainer(weld::Widget* pParent)
129
0
    : m_xBuilder(Application::CreateBuilder(pParent, u"svx/ui/toolbarpopover.ui"_ustr))
130
0
    , m_xTopLevel(m_xBuilder->weld_container(u"ToolbarPopover"_ustr))
131
0
    , m_xContainer(m_xBuilder->weld_container(u"container"_ustr))
132
0
{
133
0
    m_xTopLevel->connect_focus_in(LINK(this, ToolbarPopupContainer, FocusHdl));
134
0
}
135
136
void ToolbarPopupContainer::setPopover(std::unique_ptr<WeldToolbarPopup> xPopup)
137
0
{
138
0
    m_xPopup = std::move(xPopup);
139
    // move the WeldToolbarPopup contents into this toolbar so on-demand contents can appear inside a preexisting gtk popover
140
    // because the arrow for the popover is only enabled if there's a popover set
141
0
    m_xPopup->getTopLevel()->move(m_xPopup->getContainer(), m_xContainer.get());
142
143
    // in online LoseFocus event is fired due to this line and popup is closed
144
    // when first time opened any popup from not focused sidebar
145
0
    if (!comphelper::LibreOfficeKit::isActive())
146
0
        m_xPopup->GrabFocus();
147
0
}
148
149
void ToolbarPopupContainer::unsetPopover()
150
0
{
151
0
    if (!m_xPopup)
152
0
        return;
153
0
    m_xContainer->move(m_xPopup->getContainer(), m_xPopup->getTopLevel());
154
0
    m_xPopup.reset();
155
0
}
156
157
ToolbarPopupContainer::~ToolbarPopupContainer()
158
0
{
159
0
    unsetPopover();
160
0
}
161
162
IMPL_LINK_NOARG(ToolbarPopupContainer, FocusHdl, weld::Widget&, void)
163
0
{
164
0
    if (m_xPopup)
165
0
        m_xPopup->GrabFocus();
166
0
}
167
168
InterimToolbarPopup::InterimToolbarPopup(const css::uno::Reference<css::frame::XFrame>& rFrame, vcl::Window* pParent,
169
                                         std::unique_ptr<WeldToolbarPopup> xPopup, bool bTearable)
170
0
    : DropdownDockingWindow(pParent, rFrame, bTearable)
171
0
    , m_xFrame(rFrame)
172
0
    , m_xBuilder(Application::CreateInterimBuilder(m_xBox.get(), u"svt/ui/interimparent.ui"_ustr, false))
173
0
    , m_xContainer(m_xBuilder->weld_container(u"container"_ustr))
174
0
    , m_xPopup(std::move(xPopup))
175
0
{
176
0
    if (SystemWindow* pWindow = GetTopMostParentSystemWindow(*this))
177
0
        pWindow->GetTaskPaneList()->AddWindow(this);
178
179
    // move the WeldToolbarPopup contents into this interim toolbar so welded contents can appear as a dropdown in an unwelded toolbar
180
0
    m_xPopup->getTopLevel()->move(m_xPopup->getContainer(), m_xContainer.get());
181
0
}
Unexecuted instantiation: InterimToolbarPopup::InterimToolbarPopup(com::sun::star::uno::Reference<com::sun::star::frame::XFrame> const&, vcl::Window*, std::__1::unique_ptr<WeldToolbarPopup, std::__1::default_delete<WeldToolbarPopup> >, bool)
Unexecuted instantiation: InterimToolbarPopup::InterimToolbarPopup(com::sun::star::uno::Reference<com::sun::star::frame::XFrame> const&, vcl::Window*, std::__1::unique_ptr<WeldToolbarPopup, std::__1::default_delete<WeldToolbarPopup> >, bool)
182
183
void InterimToolbarPopup::GetFocus()
184
0
{
185
0
    DropdownDockingWindow::GetFocus();
186
0
    if (!m_xPopup)
187
0
        return;
188
0
    m_xPopup->GrabFocus();
189
0
}
190
191
void InterimToolbarPopup::dispose()
192
0
{
193
0
    if (SystemWindow* pWindow = GetTopMostParentSystemWindow(*this))
194
0
        pWindow->GetTaskPaneList()->RemoveWindow(this);
195
196
    // if we have focus when disposed, pick the document window as destination
197
    // for focus rather than let it go to an arbitrary windows
198
0
    if (HasFocus())
199
0
    {
200
0
        if (auto xWindow = m_xFrame->getContainerWindow())
201
0
            xWindow->setFocus();
202
0
    }
203
    // move the contents back where it belongs
204
0
    m_xContainer->move(m_xPopup->getContainer(), m_xPopup->getTopLevel());
205
0
    m_xPopup.reset();
206
0
    m_xContainer.reset();
207
0
    m_xBuilder.reset();
208
0
    m_xFrame.clear();
209
0
    DropdownDockingWindow::dispose();
210
0
}
211
212
InterimToolbarPopup::~InterimToolbarPopup()
213
0
{
214
0
    disposeOnce();
215
0
}
216
217
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */