Coverage Report

Created: 2025-11-16 09:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/vcl/source/control/MenuButton.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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 <vcl/dockwin.hxx>
21
#include <vcl/event.hxx>
22
#include <vcl/toolkit/floatwin.hxx>
23
#include <vcl/menu.hxx>
24
#include <vcl/timer.hxx>
25
#include <vcl/toolkit/MenuButton.hxx>
26
#include <vcl/settings.hxx>
27
#include <vcl/uitest/uiobject.hxx>
28
#include <vcl/uitest/logger.hxx>
29
#include <vcl/uitest/eventdescription.hxx>
30
#include <menutogglebutton.hxx>
31
#include <tools/json_writer.hxx>
32
33
namespace
34
{
35
void collectUIInformation( const OUString& aID, const OUString& aevent , const OUString& akey , const OUString& avalue)
36
0
{
37
0
    EventDescription aDescription;
38
0
    aDescription.aID = aID;
39
0
    aDescription.aParameters = {{ akey ,  avalue}};
40
0
    aDescription.aAction = aevent;
41
0
    aDescription.aParent = "MainWindow";
42
0
    aDescription.aKeyWord = "MenuButton";
43
0
    UITestLogger::getInstance().logEvent(aDescription);
44
0
}
45
}
46
47
void MenuButton::ImplInit( vcl::Window* pParent, WinBits nStyle )
48
0
{
49
0
    if ( !(nStyle & WB_NOTABSTOP) )
50
0
        nStyle |= WB_TABSTOP;
51
52
0
    PushButton::ImplInit( pParent, nStyle );
53
0
    EnableRTL( AllSettings::GetLayoutRTL() );
54
0
}
55
56
void MenuButton::ExecuteMenu()
57
0
{
58
0
    mbStartingMenu = true;
59
60
0
    PrepareExecute();
61
62
0
    if (!mpMenu && !mpFloatingWindow)
63
0
    {
64
0
        mbStartingMenu = false;
65
0
        return;
66
0
    }
67
68
0
    Size aSize = GetSizePixel();
69
0
    SetPressed( true );
70
0
    EndSelection();
71
0
    if (mpMenu)
72
0
    {
73
0
        Point aPos(0, 1);
74
0
        tools::Rectangle aRect(aPos, aSize );
75
0
        mpMenu->Execute(this, aRect, PopupMenuFlags::ExecuteDown);
76
77
0
        if (isDisposed())
78
0
            return;
79
80
0
        mnCurItemId = mpMenu->GetCurItemId();
81
0
        msCurItemIdent = mpMenu->GetCurItemIdent();
82
0
    }
83
0
    else
84
0
    {
85
0
        Point aPos(GetParent()->OutputToScreenPixel(GetPosPixel()));
86
0
        tools::Rectangle aRect(aPos, aSize );
87
0
        FloatWinPopupFlags nFlags = FloatWinPopupFlags::Down | FloatWinPopupFlags::GrabFocus;
88
0
        if (mpFloatingWindow->GetType() == WindowType::FLOATINGWINDOW)
89
0
            static_cast<FloatingWindow*>(mpFloatingWindow.get())->StartPopupMode(aRect, nFlags);
90
0
        else
91
0
        {
92
0
            mpFloatingWindow->EnableDocking();
93
0
            vcl::Window::GetDockingManager()->StartPopupMode(mpFloatingWindow, aRect, nFlags);
94
0
        }
95
0
    }
96
97
0
    Activate();
98
99
0
    mbStartingMenu = false;
100
101
0
    SetPressed(false);
102
0
    OUString aID = get_id(); // tdf#136678 take a copy if we are destroyed by Select callback
103
0
    if (mnCurItemId)
104
0
    {
105
0
        Select();
106
0
        mnCurItemId = 0;
107
0
        msCurItemIdent.clear();
108
0
    }
109
0
    collectUIInformation(aID,u"OPENLIST"_ustr,u""_ustr,u""_ustr);
110
0
}
111
112
void MenuButton::CancelMenu()
113
0
{
114
0
    if (!mpMenu && !mpFloatingWindow)
115
0
        return;
116
117
0
    if (mpMenu)
118
0
    {
119
0
        mpMenu->EndExecute();
120
0
    }
121
0
    else
122
0
    {
123
0
        if (mpFloatingWindow->GetType() == WindowType::FLOATINGWINDOW)
124
0
            static_cast<FloatingWindow*>(mpFloatingWindow.get())->EndPopupMode();
125
0
        else
126
0
            vcl::Window::GetDockingManager()->EndPopupMode(mpFloatingWindow);
127
0
    }
128
0
    collectUIInformation(get_id(),u"CLOSELIST"_ustr,u""_ustr,u""_ustr);
129
0
}
130
131
bool MenuButton::InPopupMode() const
132
0
{
133
0
    if (mbStartingMenu)
134
0
        return true;
135
136
0
    if (!mpMenu && !mpFloatingWindow)
137
0
        return false;
138
139
0
    if (mpMenu)
140
0
       return PopupMenu::GetActivePopupMenu() == mpMenu;
141
0
    else
142
0
    {
143
0
        if (mpFloatingWindow->GetType() == WindowType::FLOATINGWINDOW)
144
0
            return static_cast<const FloatingWindow*>(mpFloatingWindow.get())->IsInPopupMode();
145
0
        else
146
0
            return vcl::Window::GetDockingManager()->IsInPopupMode(mpFloatingWindow);
147
0
    }
148
0
}
149
150
MenuButton::MenuButton( vcl::Window* pParent, WinBits nWinBits )
151
0
    : PushButton(WindowType::MENUBUTTON)
152
0
    , mnCurItemId(0)
153
0
    , mbStartingMenu(false)
154
0
{
155
0
    mnDDStyle = PushButtonDropdownStyle::MenuButton;
156
0
    ImplInit(pParent, nWinBits);
157
0
}
Unexecuted instantiation: MenuButton::MenuButton(vcl::Window*, long)
Unexecuted instantiation: MenuButton::MenuButton(vcl::Window*, long)
158
159
MenuButton::~MenuButton()
160
0
{
161
0
    disposeOnce();
162
0
}
163
164
void MenuButton::dispose()
165
0
{
166
0
    mpFloatingWindow.reset();
167
0
    if (mpMenu && mbOwnPopupMenu)
168
0
        mpMenu->dispose();
169
0
    mpMenu.reset();
170
0
    PushButton::dispose();
171
0
}
172
173
void MenuButton::MouseButtonDown( const MouseEvent& rMEvt )
174
0
{
175
0
    if ( PushButton::ImplHitTestPushButton( this, rMEvt.GetPosPixel() ) )
176
0
    {
177
0
        if ( !(GetStyle() & WB_NOPOINTERFOCUS) )
178
0
            GrabFocus();
179
0
        ExecuteMenu();
180
0
    }
181
0
}
182
183
void MenuButton::KeyInput( const KeyEvent& rKEvt )
184
0
{
185
0
    vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
186
0
    sal_uInt16 nCode = aKeyCode.GetCode();
187
0
    if ( (nCode == KEY_DOWN) && aKeyCode.IsMod2() )
188
0
        ExecuteMenu();
189
0
    else if ( !aKeyCode.GetModifier() &&
190
0
              ((nCode == KEY_RETURN) || (nCode == KEY_SPACE)) )
191
0
        ExecuteMenu();
192
0
    else
193
0
        PushButton::KeyInput( rKEvt );
194
0
}
195
196
void MenuButton::Activate()
197
0
{
198
0
    maActivateHdl.Call( this );
199
0
}
200
201
void MenuButton::Select()
202
0
{
203
0
    if (mnCurItemId)
204
0
        collectUIInformation(get_id(),u"OPENFROMLIST"_ustr,u"POS"_ustr,OUString::number(mnCurItemId));
205
206
0
    maSelectHdl.Call( this );
207
0
}
208
209
void MenuButton::SetPopupMenu(PopupMenu* pNewMenu, bool bTakeOwnership)
210
0
{
211
0
    if (pNewMenu == mpMenu)
212
0
        return;
213
214
0
    if (mpMenu && mbOwnPopupMenu)
215
0
        mpMenu->dispose();
216
217
0
    mpMenu = pNewMenu;
218
0
    mbOwnPopupMenu = bTakeOwnership;
219
0
}
220
221
void MenuButton::SetPopover(Window* pWindow)
222
0
{
223
0
    if (pWindow == mpFloatingWindow)
224
0
        return;
225
226
0
    mpFloatingWindow = pWindow;
227
0
}
228
229
230
FactoryFunction MenuButton::GetUITestFactory() const
231
0
{
232
0
    return MenuButtonUIObject::create;
233
0
}
234
235
0
void MenuButton::SetCurItemId(){
236
0
    mnCurItemId = mpMenu->GetCurItemId();
237
0
    msCurItemIdent = mpMenu->GetCurItemIdent();
238
0
}
239
240
void MenuButton::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter)
241
0
{
242
0
    PushButton::DumpAsPropertyTree(rJsonWriter);
243
244
0
    if (mpMenu)
245
0
    {
246
0
        auto aMenuNode = rJsonWriter.startArray("menu");
247
0
        for (int i = 0; i < mpMenu->GetItemCount(); i++)
248
0
        {
249
0
            auto aEntryNode = rJsonWriter.startStruct();
250
0
            auto sId = mpMenu->GetItemId(i);
251
0
            rJsonWriter.put("id", mpMenu->GetItemIdent(sId));
252
0
            rJsonWriter.put("text", mpMenu->GetItemText(sId));
253
0
        }
254
0
    }
255
0
}
256
257
//class MenuToggleButton ----------------------------------------------------
258
259
MenuToggleButton::MenuToggleButton( vcl::Window* pParent, WinBits nWinBits )
260
0
    : MenuButton( pParent, nWinBits )
261
0
{
262
0
}
Unexecuted instantiation: MenuToggleButton::MenuToggleButton(vcl::Window*, long)
Unexecuted instantiation: MenuToggleButton::MenuToggleButton(vcl::Window*, long)
263
264
MenuToggleButton::~MenuToggleButton()
265
0
{
266
0
    disposeOnce();
267
0
}
268
269
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */