1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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/menubtn.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>
35 void collectUIInformation( const OUString
& aID
, const OUString
& aevent
, const OUString
& akey
, const OUString
& avalue
)
37 EventDescription aDescription
;
38 aDescription
.aID
= aID
;
39 aDescription
.aParameters
= {{ akey
, avalue
}};
40 aDescription
.aAction
= aevent
;
41 aDescription
.aParent
= "MainWindow";
42 aDescription
.aKeyWord
= "MenuButton";
43 UITestLogger::getInstance().logEvent(aDescription
);
47 void MenuButton::ImplInit( vcl::Window
* pParent
, WinBits nStyle
)
49 if ( !(nStyle
& WB_NOTABSTOP
) )
52 PushButton::ImplInit( pParent
, nStyle
);
53 EnableRTL( AllSettings::GetLayoutRTL() );
56 void MenuButton::ExecuteMenu()
58 mbStartingMenu
= true;
62 if (!mpMenu
&& !mpFloatingWindow
)
64 mbStartingMenu
= false;
68 Size aSize
= GetSizePixel();
74 tools::Rectangle
aRect(aPos
, aSize
);
75 mpMenu
->Execute(this, aRect
, PopupMenuFlags::ExecuteDown
);
80 mnCurItemId
= mpMenu
->GetCurItemId();
81 msCurItemIdent
= mpMenu
->GetCurItemIdent();
85 Point
aPos(GetParent()->OutputToScreenPixel(GetPosPixel()));
86 tools::Rectangle
aRect(aPos
, aSize
);
87 FloatWinPopupFlags nFlags
= FloatWinPopupFlags::Down
| FloatWinPopupFlags::GrabFocus
;
88 if (mpFloatingWindow
->GetType() == WindowType::FLOATINGWINDOW
)
89 static_cast<FloatingWindow
*>(mpFloatingWindow
.get())->StartPopupMode(aRect
, nFlags
);
92 mpFloatingWindow
->EnableDocking();
93 vcl::Window::GetDockingManager()->StartPopupMode(mpFloatingWindow
, aRect
, nFlags
);
99 mbStartingMenu
= false;
102 OUString aID
= get_id(); // tdf#136678 take a copy if we are destroyed by Select callback
107 msCurItemIdent
.clear();
109 collectUIInformation(aID
,u
"OPENLIST"_ustr
,u
""_ustr
,u
""_ustr
);
112 void MenuButton::CancelMenu()
114 if (!mpMenu
&& !mpFloatingWindow
)
119 mpMenu
->EndExecute();
123 if (mpFloatingWindow
->GetType() == WindowType::FLOATINGWINDOW
)
124 static_cast<FloatingWindow
*>(mpFloatingWindow
.get())->EndPopupMode();
126 vcl::Window::GetDockingManager()->EndPopupMode(mpFloatingWindow
);
128 collectUIInformation(get_id(),u
"CLOSELIST"_ustr
,u
""_ustr
,u
""_ustr
);
131 bool MenuButton::InPopupMode() const
136 if (!mpMenu
&& !mpFloatingWindow
)
140 return PopupMenu::GetActivePopupMenu() == mpMenu
;
143 if (mpFloatingWindow
->GetType() == WindowType::FLOATINGWINDOW
)
144 return static_cast<const FloatingWindow
*>(mpFloatingWindow
.get())->IsInPopupMode();
146 return vcl::Window::GetDockingManager()->IsInPopupMode(mpFloatingWindow
);
150 MenuButton::MenuButton( vcl::Window
* pParent
, WinBits nWinBits
)
151 : PushButton(WindowType::MENUBUTTON
)
154 , mbStartingMenu(false)
156 mnDDStyle
= PushButtonDropdownStyle::MenuButton
;
157 ImplInit(pParent
, nWinBits
);
160 MenuButton::~MenuButton()
165 void MenuButton::dispose()
168 mpFloatingWindow
.clear();
169 if (mpMenu
&& mbOwnPopupMenu
)
172 PushButton::dispose();
175 IMPL_LINK_NOARG(MenuButton
, ImplMenuTimeoutHdl
, Timer
*, void)
177 // See if Button Tracking is still active, as it could've been cancelled earlier
180 if ( !(GetStyle() & WB_NOPOINTERFOCUS
) )
186 void MenuButton::MouseButtonDown( const MouseEvent
& rMEvt
)
188 bool bExecute
= true;
191 // If the separated dropdown symbol is not hit, delay the popup execution
192 if( rMEvt
.GetPosPixel().X() <= ImplGetSeparatorX() )
196 mpMenuTimer
.reset(new Timer("MenuTimer"));
197 mpMenuTimer
->SetInvokeHandler( LINK( this, MenuButton
, ImplMenuTimeoutHdl
) );
200 mpMenuTimer
->SetTimeout( MouseSettings::GetActionDelay() );
201 mpMenuTimer
->Start();
203 PushButton::MouseButtonDown( rMEvt
);
209 if ( PushButton::ImplHitTestPushButton( this, rMEvt
.GetPosPixel() ) )
211 if ( !(GetStyle() & WB_NOPOINTERFOCUS
) )
218 void MenuButton::KeyInput( const KeyEvent
& rKEvt
)
220 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
221 sal_uInt16 nCode
= aKeyCode
.GetCode();
222 if ( (nCode
== KEY_DOWN
) && aKeyCode
.IsMod2() )
224 else if ( !mbDelayMenu
&&
225 !aKeyCode
.GetModifier() &&
226 ((nCode
== KEY_RETURN
) || (nCode
== KEY_SPACE
)) )
229 PushButton::KeyInput( rKEvt
);
232 void MenuButton::Activate()
234 maActivateHdl
.Call( this );
237 void MenuButton::Select()
240 collectUIInformation(get_id(),u
"OPENFROMLIST"_ustr
,u
"POS"_ustr
,OUString::number(mnCurItemId
));
242 maSelectHdl
.Call( this );
245 void MenuButton::SetPopupMenu(PopupMenu
* pNewMenu
, bool bTakeOwnership
)
247 if (pNewMenu
== mpMenu
)
250 if (mpMenu
&& mbOwnPopupMenu
)
254 mbOwnPopupMenu
= bTakeOwnership
;
257 void MenuButton::SetPopover(Window
* pWindow
)
259 if (pWindow
== mpFloatingWindow
)
262 mpFloatingWindow
= pWindow
;
266 FactoryFunction
MenuButton::GetUITestFactory() const
268 return MenuButtonUIObject::create
;
271 void MenuButton::SetCurItemId(){
272 mnCurItemId
= mpMenu
->GetCurItemId();
273 msCurItemIdent
= mpMenu
->GetCurItemIdent();
276 void MenuButton::DumpAsPropertyTree(tools::JsonWriter
& rJsonWriter
)
278 PushButton::DumpAsPropertyTree(rJsonWriter
);
282 auto aMenuNode
= rJsonWriter
.startArray("menu");
283 for (int i
= 0; i
< mpMenu
->GetItemCount(); i
++)
285 auto aEntryNode
= rJsonWriter
.startStruct();
286 auto sId
= mpMenu
->GetItemId(i
);
287 rJsonWriter
.put("id", mpMenu
->GetItemIdent(sId
));
288 rJsonWriter
.put("text", mpMenu
->GetItemText(sId
));
293 //class MenuToggleButton ----------------------------------------------------
295 MenuToggleButton::MenuToggleButton( vcl::Window
* pParent
, WinBits nWinBits
)
296 : MenuButton( pParent
, nWinBits
)
300 MenuToggleButton::~MenuToggleButton()
305 void MenuToggleButton::SetActive( bool bSel
)
310 bool MenuToggleButton::GetActive() const
315 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */