1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qquickmenuitem_p.h"
5#include "qquickmenuitem_p_p.h"
6#include "qquickmenu_p.h"
7#include "qquickdeferredexecute_p_p.h"
8
9#include <QtGui/qpa/qplatformtheme.h>
10#include <QtQuick/private/qquickevents_p_p.h>
11
12QT_BEGIN_NAMESPACE
13
14/*!
15 \qmltype MenuItem
16 \inherits AbstractButton
17//! \instantiates QQuickMenuItem
18 \inqmlmodule QtQuick.Controls
19 \since 5.7
20 \ingroup qtquickcontrols-menus
21 \brief Presents an item within a Menu.
22
23 MenuItem is a convenience type that implements the AbstractButton API,
24 providing a familiar way to respond to menu items being \l triggered, for
25 example.
26
27 MenuItem inherits its API from AbstractButton. For instance, you can set
28 \l {AbstractButton::text}{text} and \l {Icons in Qt Quick Controls}{icon}
29 using the AbstractButton API.
30
31 \code
32 Button {
33 id: fileButton
34 text: "File"
35 onClicked: menu.open()
36
37 Menu {
38 id: menu
39
40 MenuItem {
41 text: "New..."
42 onTriggered: document.reset()
43 }
44 MenuItem {
45 text: "Open..."
46 onTriggered: openDialog.open()
47 }
48 MenuItem {
49 text: "Save"
50 onTriggered: saveDialog.open()
51 }
52 }
53 }
54 \endcode
55
56 \sa {Customizing Menu}, Menu, {Menu Controls}
57*/
58
59void QQuickMenuItemPrivate::setMenu(QQuickMenu *newMenu)
60{
61 Q_Q(QQuickMenuItem);
62 if (menu == newMenu)
63 return;
64
65 menu = newMenu;
66 emit q->menuChanged();
67}
68
69void QQuickMenuItemPrivate::setSubMenu(QQuickMenu *newSubMenu)
70{
71 Q_Q(QQuickMenuItem);
72 if (subMenu == newSubMenu)
73 return;
74
75 if (subMenu) {
76 QObject::disconnect(sender: subMenu, signal: &QQuickMenu::titleChanged, receiver: q, slot: &QQuickAbstractButton::setText);
77 QObject::disconnect(sender: subMenu, signal: &QQuickMenu::iconChanged, receiver: q, slot: &QQuickAbstractButton::setIcon);
78 QObjectPrivate::disconnect(sender: subMenu, signal: &QQuickPopup::enabledChanged, receiverPrivate: this, slot: &QQuickMenuItemPrivate::updateEnabled);
79 }
80
81 if (newSubMenu) {
82 QObject::connect(sender: newSubMenu, signal: &QQuickMenu::titleChanged, context: q, slot: &QQuickAbstractButton::setText);
83 QObject::connect(sender: newSubMenu, signal: &QQuickMenu::iconChanged, context: q, slot: &QQuickAbstractButton::setIcon);
84 QObjectPrivate::connect(sender: newSubMenu, signal: &QQuickPopup::enabledChanged, receiverPrivate: this, slot: &QQuickMenuItemPrivate::updateEnabled);
85 q->setText(newSubMenu->title());
86 q->setIcon(newSubMenu->icon());
87 }
88
89 subMenu = newSubMenu;
90 updateEnabled();
91 emit q->subMenuChanged();
92}
93
94void QQuickMenuItemPrivate::updateEnabled()
95{
96 Q_Q(QQuickMenuItem);
97 q->setEnabled(subMenu && subMenu->isEnabled());
98}
99
100static inline QString arrowName() { return QStringLiteral("arrow"); }
101
102void QQuickMenuItemPrivate::cancelArrow()
103{
104 Q_Q(QQuickAbstractButton);
105 quickCancelDeferred(object: q, property: arrowName());
106}
107
108void QQuickMenuItemPrivate::executeArrow(bool complete)
109{
110 Q_Q(QQuickMenuItem);
111 if (arrow.wasExecuted())
112 return;
113
114 if (!arrow || complete)
115 quickBeginDeferred(object: q, property: arrowName(), delegate&: arrow);
116 if (complete)
117 quickCompleteDeferred(object: q, property: arrowName(), delegate&: arrow);
118}
119
120bool QQuickMenuItemPrivate::acceptKeyClick(Qt::Key key) const
121{
122 return key == Qt::Key_Return || key == Qt::Key_Enter
123 || QQuickAbstractButtonPrivate::acceptKeyClick(key);
124}
125
126QPalette QQuickMenuItemPrivate::defaultPalette() const
127{
128 return QQuickTheme::palette(scope: QQuickTheme::Menu);
129}
130
131/*!
132 \qmlsignal void QtQuick.Controls::MenuItem::triggered()
133
134 This signal is emitted when the menu item is triggered by the user.
135*/
136
137QQuickMenuItem::QQuickMenuItem(QQuickItem *parent)
138 : QQuickAbstractButton(*(new QQuickMenuItemPrivate), parent)
139{
140 connect(sender: this, signal: &QQuickAbstractButton::clicked, context: this, slot: &QQuickMenuItem::triggered);
141}
142
143/*!
144 \qmlproperty bool QtQuick.Controls::MenuItem::highlighted
145
146 This property holds whether the menu item is highlighted by the user.
147
148 A menu item can be highlighted by mouse hover or keyboard navigation.
149
150 The default value is \c false.
151
152 \sa Menu::currentIndex
153*/
154bool QQuickMenuItem::isHighlighted() const
155{
156 Q_D(const QQuickMenuItem);
157 return d->highlighted;
158}
159
160void QQuickMenuItem::setHighlighted(bool highlighted)
161{
162 Q_D(QQuickMenuItem);
163 if (highlighted == d->highlighted)
164 return;
165
166 d->highlighted = highlighted;
167 emit highlightedChanged();
168}
169
170/*!
171 \since QtQuick.Controls 2.3 (Qt 5.10)
172 \qmlproperty Item QtQuick.Controls::MenuItem::arrow
173
174 This property holds the sub-menu arrow item.
175
176 \sa {Customizing Menu}
177*/
178QQuickItem *QQuickMenuItem::arrow() const
179{
180 QQuickMenuItemPrivate *d = const_cast<QQuickMenuItemPrivate *>(d_func());
181 if (!d->arrow)
182 d->executeArrow();
183 return d->arrow;
184}
185
186void QQuickMenuItem::setArrow(QQuickItem *arrow)
187{
188 Q_D(QQuickMenuItem);
189 if (d->arrow == arrow)
190 return;
191
192 if (!d->arrow.isExecuting())
193 d->cancelArrow();
194
195 QQuickControlPrivate::hideOldItem(item: d->arrow);
196 d->arrow = arrow;
197 if (arrow && !arrow->parentItem())
198 arrow->setParentItem(this);
199 if (!d->arrow.isExecuting())
200 emit arrowChanged();
201}
202
203/*!
204 \since QtQuick.Controls 2.3 (Qt 5.10)
205 \qmlproperty Menu QtQuick.Controls::MenuItem::menu
206 \readonly
207
208 This property holds the menu that contains this menu item,
209 or \c null if the item is not in a menu.
210*/
211QQuickMenu *QQuickMenuItem::menu() const
212{
213 Q_D(const QQuickMenuItem);
214 return d->menu;
215}
216
217/*!
218 \since QtQuick.Controls 2.3 (Qt 5.10)
219 \qmlproperty Menu QtQuick.Controls::MenuItem::subMenu
220 \readonly
221
222 This property holds the sub-menu that this item presents in
223 the parent menu, or \c null if this item is not a sub-menu item.
224*/
225QQuickMenu *QQuickMenuItem::subMenu() const
226{
227 Q_D(const QQuickMenuItem);
228 return d->subMenu;
229}
230
231void QQuickMenuItem::componentComplete()
232{
233 Q_D(QQuickMenuItem);
234 d->executeArrow(complete: true);
235 QQuickAbstractButton::componentComplete();
236}
237
238QFont QQuickMenuItem::defaultFont() const
239{
240 return QQuickTheme::font(scope: QQuickTheme::Menu);
241}
242
243#if QT_CONFIG(accessibility)
244QAccessible::Role QQuickMenuItem::accessibleRole() const
245{
246 return QAccessible::MenuItem;
247}
248#endif
249
250QT_END_NAMESPACE
251
252#include "moc_qquickmenuitem_p.cpp"
253

source code of qtdeclarative/src/quicktemplates/qquickmenuitem.cpp