1/****************************************************************************
2**
3** Copyright (C) 2020 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qaction.h"
41#include "qactiongroup.h"
42
43#include "qaction_p.h"
44#include "qguiapplication.h"
45#include "qevent.h"
46#include "qlist.h"
47#include "qstylehints.h"
48#if QT_CONFIG(shortcut)
49# include <private/qshortcutmap_p.h>
50#endif
51#include <private/qguiapplication_p.h>
52#include <private/qdebug_p.h>
53
54#define QAPP_CHECK(functionName) \
55 if (Q_UNLIKELY(!QCoreApplication::instance())) { \
56 qWarning("QAction: Initialize Q(Gui)Application before calling '" functionName "'."); \
57 return; \
58 }
59
60QT_BEGIN_NAMESPACE
61
62/*
63 internal: guesses a descriptive text from a text suited for a menu entry
64 */
65static QString qt_strippedText(QString s)
66{
67 s.remove(QLatin1String("..."));
68 for (int i = 0; i < s.size(); ++i) {
69 if (s.at(i) == QLatin1Char('&'))
70 s.remove(i, 1);
71 }
72 return s.trimmed();
73}
74
75QActionPrivate *QGuiApplicationPrivate::createActionPrivate() const
76{
77 return new QActionPrivate;
78}
79
80QActionPrivate::QActionPrivate() :
81#if QT_CONFIG(shortcut)
82 autorepeat(1),
83#endif
84 enabled(1), explicitEnabled(0), explicitEnabledValue(1), visible(1), forceInvisible(0), checkable(0),
85 checked(0), separator(0), fontSet(false),
86 iconVisibleInMenu(-1), shortcutVisibleInContextMenu(-1)
87{
88}
89
90#if QT_CONFIG(shortcut)
91static bool dummy(QObject *, Qt::ShortcutContext) { return false; } // only for GUI testing.
92
93QShortcutMap::ContextMatcher QActionPrivate::contextMatcher() const
94{
95 return dummy;
96};
97#endif // QT_CONFIG(shortcut)
98
99QActionPrivate::~QActionPrivate() = default;
100
101void QActionPrivate::destroy()
102{
103}
104
105void QActionPrivate::sendDataChanged()
106{
107 Q_Q(QAction);
108 QActionEvent e(QEvent::ActionChanged, q);
109 QCoreApplication::sendEvent(q, &e);
110
111 emit q->changed();
112}
113
114#if QT_CONFIG(shortcut)
115void QActionPrivate::redoGrab(QShortcutMap &map)
116{
117 Q_Q(QAction);
118 for (int id : qAsConst(shortcutIds)) {
119 if (id)
120 map.removeShortcut(id, q);
121 }
122
123 shortcutIds.clear();
124 for (const QKeySequence &shortcut : qAsConst(shortcuts)) {
125 if (!shortcut.isEmpty())
126 shortcutIds.append(map.addShortcut(q, shortcut, shortcutContext, contextMatcher()));
127 else
128 shortcutIds.append(0);
129 }
130 if (!enabled) {
131 for (int id : qAsConst(shortcutIds)) {
132 if (id)
133 map.setShortcutEnabled(false, id, q);
134 }
135 }
136 if (!autorepeat) {
137 for (int id : qAsConst(shortcutIds)) {
138 if (id)
139 map.setShortcutAutoRepeat(false, id, q);
140 }
141 }
142}
143
144void QActionPrivate::setShortcutEnabled(bool enable, QShortcutMap &map)
145{
146 Q_Q(QAction);
147 for (int id : qAsConst(shortcutIds)) {
148 if (id)
149 map.setShortcutEnabled(enable, id, q);
150 }
151}
152#endif // QT_NO_SHORTCUT
153
154bool QActionPrivate::showStatusText(QObject *object, const QString &str)
155{
156 if (QObject *receiver = object ? object : parent) {
157 QStatusTipEvent tip(str);
158 QCoreApplication::sendEvent(receiver, &tip);
159 return true;
160 }
161 return false;
162}
163
164void QActionPrivate::setMenu(QObject *)
165{
166}
167
168QObject *QActionPrivate::menu() const
169{
170 return nullptr;
171}
172
173/*!
174 \class QAction
175 \brief The QAction class provides an abstraction for user commands
176 that can be added to different user interface components.
177 \since 6.0
178
179 \inmodule QtGui
180
181 In applications many common commands can be invoked via menus,
182 toolbar buttons, and keyboard shortcuts. Since the user expects
183 each command to be performed in the same way, regardless of the
184 user interface used, it is useful to represent each command as
185 an \e action.
186
187 Actions can be added to menus and toolbars, and will
188 automatically keep them in sync. For example, in a word processor,
189 if the user presses a Bold toolbar button, the Bold menu item
190 will automatically be checked.
191
192 A QAction may contain an icon, menu text, a shortcut, status text,
193 "What's This?" text, and a tooltip. Most of these can be set in
194 the constructor. They can also be set independently with
195 setIcon(), setText(), setIconText(), setShortcut(),
196 setStatusTip(), setWhatsThis(), and setToolTip(). For menu items,
197 it is possible to set an individual font with setFont().
198
199 We recommend that actions are created as children of the window
200 they are used in. In most cases actions will be children of
201 the application's main window.
202
203 \section1 QAction in widget applications
204
205 Once a QAction has been created, it should be added to the relevant
206 menu and toolbar, then connected to the slot which will perform
207 the action. For example:
208
209 \snippet mainwindows/application/mainwindow.cpp 19
210
211 Actions are added to widgets using QWidget::addAction() or
212 QGraphicsWidget::addAction(). Note that an action must be added to a
213 widget before it can be used. This is also true when the shortcut should
214 be global (i.e., Qt::ApplicationShortcut as Qt::ShortcutContext).
215
216 Actions can be created as independent objects. But they may
217 also be created during the construction of menus. The QMenu class
218 contains convenience functions for creating actions suitable for
219 use as menu items.
220
221
222 \sa QMenu, QToolBar, {Application Example}
223*/
224
225/*!
226 \fn void QAction::trigger()
227
228 This is a convenience slot that calls activate(Trigger).
229*/
230
231/*!
232 \fn void QAction::hover()
233
234 This is a convenience slot that calls activate(Hover).
235*/
236
237/*!
238 \enum QAction::MenuRole
239
240 This enum describes how an action should be moved into the application menu on \macos.
241
242 \value NoRole This action should not be put into the application menu
243 \value TextHeuristicRole This action should be put in the application menu based on the action's text
244 as described in the QMenuBar documentation.
245 \value ApplicationSpecificRole This action should be put in the application menu with an application specific role
246 \value AboutQtRole This action handles the "About Qt" menu item.
247 \value AboutRole This action should be placed where the "About" menu item is in the application menu. The text of
248 the menu item will be set to "About <application name>". The application name is fetched from the
249 \c{Info.plist} file in the application's bundle (See \l{Qt for macOS - Deployment}).
250 \value PreferencesRole This action should be placed where the "Preferences..." menu item is in the application menu.
251 \value QuitRole This action should be placed where the Quit menu item is in the application menu.
252
253 Setting this value only has effect on items that are in the immediate menus
254 of the menubar, not the submenus of those menus. For example, if you have
255 File menu in your menubar and the File menu has a submenu, setting the
256 MenuRole for the actions in that submenu have no effect. They will never be moved.
257*/
258
259/*!
260 Constructs an action with \a parent. If \a parent is an action
261 group the action will be automatically inserted into the group.
262
263 \note The \a parent argument is optional since Qt 5.7.
264*/
265QAction::QAction(QObject *parent)
266 : QAction(*QGuiApplicationPrivate::instance()->createActionPrivate(), parent)
267{
268}
269
270/*!
271 Constructs an action with some \a text and \a parent. If \a
272 parent is an action group the action will be automatically
273 inserted into the group.
274
275 The action uses a stripped version of \a text (e.g. "\&Menu
276 Option..." becomes "Menu Option") as descriptive text for
277 tool buttons. You can override this by setting a specific
278 description with setText(). The same text will be used for
279 tooltips unless you specify a different text using
280 setToolTip().
281
282*/
283QAction::QAction(const QString &text, QObject *parent)
284 : QAction(parent)
285{
286 Q_D(QAction);
287 d->text = text;
288}
289
290/*!
291 Constructs an action with an \a icon and some \a text and \a
292 parent. If \a parent is an action group the action will be
293 automatically inserted into the group.
294
295 The action uses a stripped version of \a text (e.g. "\&Menu
296 Option..." becomes "Menu Option") as descriptive text for
297 tool buttons. You can override this by setting a specific
298 description with setText(). The same text will be used for
299 tooltips unless you specify a different text using
300 setToolTip().
301*/
302QAction::QAction(const QIcon &icon, const QString &text, QObject *parent)
303 : QAction(text, parent)
304{
305 Q_D(QAction);
306 d->icon = icon;
307}
308
309/*!
310 \internal
311*/
312QAction::QAction(QActionPrivate &dd, QObject *parent)
313 : QObject(dd, parent)
314{
315 Q_D(QAction);
316 d->group = qobject_cast<QActionGroup *>(parent);
317 if (d->group)
318 d->group->addAction(this);
319}
320
321#if QT_CONFIG(shortcut)
322/*!
323 \property QAction::shortcut
324 \brief the action's primary shortcut key
325
326 Valid keycodes for this property can be found in \l Qt::Key and
327 \l Qt::Modifier. There is no default shortcut key.
328*/
329
330/*!
331 Sets \a shortcut as the sole shortcut that triggers the action.
332
333 \sa shortcut, setShortcuts()
334*/
335void QAction::setShortcut(const QKeySequence &shortcut)
336{
337 if (shortcut.isEmpty())
338 setShortcuts({});
339 else
340 setShortcuts({ shortcut });
341}
342
343/*!
344 Sets \a shortcuts as the list of shortcuts that trigger the
345 action. The first element of the list is the primary shortcut.
346
347 \sa shortcut, setShortcut()
348*/
349void QAction::setShortcuts(const QList<QKeySequence> &shortcuts)
350{
351 QAPP_CHECK("setShortcuts");
352 Q_D(QAction);
353
354 if (d->shortcuts == shortcuts)
355 return;
356
357 d->shortcuts = shortcuts;
358 d->redoGrab(QGuiApplicationPrivate::instance()->shortcutMap);
359 d->sendDataChanged();
360}
361
362/*!
363 Sets a platform dependent list of shortcuts based on the \a key.
364 The result of calling this function will depend on the currently running platform.
365 Note that more than one shortcut can assigned by this action.
366 If only the primary shortcut is required, use setShortcut instead.
367
368 \sa QKeySequence::keyBindings()
369*/
370void QAction::setShortcuts(QKeySequence::StandardKey key)
371{
372 QList <QKeySequence> list = QKeySequence::keyBindings(key);
373 setShortcuts(list);
374}
375
376/*!
377 Returns the primary shortcut.
378
379 \sa setShortcuts()
380*/
381QKeySequence QAction::shortcut() const
382{
383 Q_D(const QAction);
384 if (d->shortcuts.isEmpty())
385 return QKeySequence();
386 return d->shortcuts.first();
387}
388
389/*!
390 Returns the list of shortcuts, with the primary shortcut as
391 the first element of the list.
392
393 \sa setShortcuts()
394*/
395QList<QKeySequence> QAction::shortcuts() const
396{
397 Q_D(const QAction);
398 return d->shortcuts;
399}
400
401/*!
402 \property QAction::shortcutContext
403 \brief the context for the action's shortcut
404
405 Valid values for this property can be found in \l Qt::ShortcutContext.
406 The default value is Qt::WindowShortcut.
407*/
408void QAction::setShortcutContext(Qt::ShortcutContext context)
409{
410 Q_D(QAction);
411 if (d->shortcutContext == context)
412 return;
413 QAPP_CHECK("setShortcutContext");
414 d->shortcutContext = context;
415 d->redoGrab(QGuiApplicationPrivate::instance()->shortcutMap);
416 d->sendDataChanged();
417}
418
419Qt::ShortcutContext QAction::shortcutContext() const
420{
421 Q_D(const QAction);
422 return d->shortcutContext;
423}
424
425/*!
426 \property QAction::autoRepeat
427 \brief whether the action can auto repeat
428
429 If true, the action will auto repeat when the keyboard shortcut
430 combination is held down, provided that keyboard auto repeat is
431 enabled on the system.
432 The default value is true.
433*/
434void QAction::setAutoRepeat(bool on)
435{
436 Q_D(QAction);
437 if (d->autorepeat == on)
438 return;
439 QAPP_CHECK("setAutoRepeat");
440 d->autorepeat = on;
441 d->redoGrab(QGuiApplicationPrivate::instance()->shortcutMap);
442 d->sendDataChanged();
443}
444
445bool QAction::autoRepeat() const
446{
447 Q_D(const QAction);
448 return d->autorepeat;
449}
450#endif // QT_CONFIG(shortcut)
451
452/*!
453 \property QAction::font
454 \brief the action's font
455
456 The font property is used to render the text set on the
457 QAction. The font can be considered a hint as it will not be
458 consulted in all cases based upon application and style.
459
460 By default, this property contains the application's default font.
461
462 \sa setText()
463*/
464void QAction::setFont(const QFont &font)
465{
466 Q_D(QAction);
467 if (d->font == font)
468 return;
469
470 d->fontSet = true;
471 d->font = font;
472 d->sendDataChanged();
473}
474
475QFont QAction::font() const
476{
477 Q_D(const QAction);
478 return d->font;
479}
480
481
482/*!
483 Destroys the object and frees allocated resources.
484*/
485QAction::~QAction()
486{
487 Q_D(QAction);
488
489 d->destroy();
490
491 if (d->group)
492 d->group->removeAction(this);
493#if QT_CONFIG(shortcut)
494 if (qApp) {
495 for (int id : qAsConst(d->shortcutIds)) {
496 if (id)
497 QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(id, this);
498 }
499 }
500#endif
501}
502
503/*!
504 Sets this action group to \a group. The action will be automatically
505 added to the group's list of actions.
506
507 Actions within the group will be mutually exclusive.
508
509 \sa QActionGroup, actionGroup()
510*/
511void QAction::setActionGroup(QActionGroup *group)
512{
513 Q_D(QAction);
514 if(group == d->group)
515 return;
516
517 if(d->group)
518 d->group->removeAction(this);
519 d->group = group;
520 if(group)
521 group->addAction(this);
522 d->sendDataChanged();
523}
524
525/*!
526 Returns the action group for this action. If no action group manages
527 this action, then \nullptr will be returned.
528
529 \sa QActionGroup, setActionGroup()
530*/
531QActionGroup *QAction::actionGroup() const
532{
533 Q_D(const QAction);
534 return d->group;
535}
536
537/*!
538 \since 6.0
539 Returns a list of objects this action has been added to.
540
541 \sa QWidget::addAction(), QGraphicsWidget::addAction()
542*/
543QList<QObject*> QAction::associatedObjects() const
544{
545 Q_D(const QAction);
546 return d->associatedObjects;
547}
548
549/*!
550 \fn QWidget *QAction::parentWidget() const
551 \obsolete Use parent() with qobject_cast() instead.
552
553 Returns the parent widget.
554*/
555
556/*!
557 \fn QList<QWidget*> QAction::associatedWidgets() const
558 \obsolete Use associatedObjects() with qobject_cast() instead.
559
560 Returns a list of widgets this action has been added to.
561
562 \sa QWidget::addAction(), associatedObjects(), associatedGraphicsWidgets()
563*/
564
565/*!
566 \fn QList<QWidget*> QAction::associatedGraphicsWidgets() const
567 \obsolete Use associatedObjects() with qobject_cast() instead.
568
569 Returns a list of graphics widgets this action has been added to.
570
571 \sa QGraphicsWidget::addAction(), associatedObjects(), associatedWidgets()
572*/
573
574/*!
575 \property QAction::icon
576 \brief the action's icon
577
578 In toolbars, the icon is used as the tool button icon; in menus,
579 it is displayed to the left of the menu text. There is no default
580 icon.
581
582 If a null icon (QIcon::isNull()) is passed into this function,
583 the icon of the action is cleared.
584*/
585void QAction::setIcon(const QIcon &icon)
586{
587 Q_D(QAction);
588 d->icon = icon;
589 d->sendDataChanged();
590}
591
592QIcon QAction::icon() const
593{
594 Q_D(const QAction);
595 return d->icon;
596}
597
598/*!
599 If \a b is true then this action will be considered a separator.
600
601 How a separator is represented depends on the widget it is inserted
602 into. Under most circumstances the text, submenu, and icon will be
603 ignored for separator actions.
604
605 \sa isSeparator()
606*/
607void QAction::setSeparator(bool b)
608{
609 Q_D(QAction);
610 if (d->separator == b)
611 return;
612
613 d->separator = b;
614 d->sendDataChanged();
615}
616
617/*!
618 Returns \c true if this action is a separator action; otherwise it
619 returns \c false.
620
621 \sa setSeparator()
622*/
623bool QAction::isSeparator() const
624{
625 Q_D(const QAction);
626 return d->separator;
627}
628
629/*!
630 \property QAction::text
631 \brief the action's descriptive text
632
633 If the action is added to a menu, the menu option will consist of
634 the icon (if there is one), the text, and the shortcut (if there
635 is one). If the text is not explicitly set in the constructor, or
636 by using setText(), the action's description icon text will be
637 used as text. There is no default text.
638
639 \sa iconText
640*/
641void QAction::setText(const QString &text)
642{
643 Q_D(QAction);
644 if (d->text == text)
645 return;
646
647 d->text = text;
648 d->sendDataChanged();
649}
650
651QString QAction::text() const
652{
653 Q_D(const QAction);
654 QString s = d->text;
655 if(s.isEmpty()) {
656 s = d->iconText;
657 s.replace(QLatin1Char('&'), QLatin1String("&&"));
658 }
659 return s;
660}
661
662/*!
663 \property QAction::iconText
664 \brief the action's descriptive icon text
665
666 If QToolBar::toolButtonStyle is set to a value that permits text to
667 be displayed, the text defined held in this property appears as a
668 label in the relevant tool button.
669
670 It also serves as the default text in menus and tooltips if the action
671 has not been defined with setText() or setToolTip(), and will
672 also be used in toolbar buttons if no icon has been defined using setIcon().
673
674 If the icon text is not explicitly set, the action's normal text will be
675 used for the icon text.
676
677 By default, this property contains an empty string.
678
679 \sa setToolTip(), setStatusTip()
680*/
681void QAction::setIconText(const QString &text)
682{
683 Q_D(QAction);
684 if (d->iconText == text)
685 return;
686
687 d->iconText = text;
688 d->sendDataChanged();
689}
690
691QString QAction::iconText() const
692{
693 Q_D(const QAction);
694 if (d->iconText.isEmpty())
695 return qt_strippedText(d->text);
696 return d->iconText;
697}
698
699/*!
700 \property QAction::toolTip
701 \brief the action's tooltip
702
703 This text is used for the tooltip. If no tooltip is specified,
704 the action's text is used.
705
706 By default, this property contains the action's text.
707
708 \sa setStatusTip(), setShortcut()
709*/
710void QAction::setToolTip(const QString &tooltip)
711{
712 Q_D(QAction);
713 if (d->tooltip == tooltip)
714 return;
715
716 d->tooltip = tooltip;
717 d->sendDataChanged();
718}
719
720QString QAction::toolTip() const
721{
722 Q_D(const QAction);
723 if (d->tooltip.isEmpty()) {
724 if (!d->text.isEmpty())
725 return qt_strippedText(d->text);
726 return qt_strippedText(d->iconText);
727 }
728 return d->tooltip;
729}
730
731/*!
732 \property QAction::statusTip
733 \brief the action's status tip
734
735 The status tip is displayed on all status bars provided by the
736 action's top-level parent widget.
737
738 By default, this property contains an empty string.
739
740 \sa setToolTip(), showStatusText()
741*/
742void QAction::setStatusTip(const QString &statustip)
743{
744 Q_D(QAction);
745 if (d->statustip == statustip)
746 return;
747
748 d->statustip = statustip;
749 d->sendDataChanged();
750}
751
752QString QAction::statusTip() const
753{
754 Q_D(const QAction);
755 return d->statustip;
756}
757
758/*!
759 Updates the relevant status bar for the UI represented by \a object by sending a
760 QStatusTipEvent. Returns \c true if an event was sent, otherwise returns \c false.
761
762 If a null widget is specified, the event is sent to the action's parent.
763
764 \sa statusTip
765*/
766bool QAction::showStatusText(QObject *object)
767{
768 Q_D(QAction);
769 return d->showStatusText(object, statusTip());
770}
771
772/*!
773 \property QAction::whatsThis
774 \brief the action's "What's This?" help text
775
776 The "What's This?" text is used to provide a brief description of
777 the action. The text may contain rich text. There is no default
778 "What's This?" text.
779
780 \sa QWhatsThis
781*/
782void QAction::setWhatsThis(const QString &whatsthis)
783{
784 Q_D(QAction);
785 if (d->whatsthis == whatsthis)
786 return;
787
788 d->whatsthis = whatsthis;
789 d->sendDataChanged();
790}
791
792QString QAction::whatsThis() const
793{
794 Q_D(const QAction);
795 return d->whatsthis;
796}
797
798/*!
799 \enum QAction::Priority
800
801 This enum defines priorities for actions in user interface.
802
803 \value LowPriority The action should not be prioritized in
804 the user interface.
805
806 \value NormalPriority
807
808 \value HighPriority The action should be prioritized in
809 the user interface.
810
811 \sa priority
812*/
813
814
815/*!
816 \property QAction::priority
817
818 \brief the actions's priority in the user interface.
819
820 This property can be set to indicate how the action should be prioritized
821 in the user interface.
822
823 For instance, when toolbars have the Qt::ToolButtonTextBesideIcon
824 mode set, then actions with LowPriority will not show the text
825 labels.
826*/
827void QAction::setPriority(Priority priority)
828{
829 Q_D(QAction);
830 if (d->priority == priority)
831 return;
832
833 d->priority = priority;
834 d->sendDataChanged();
835}
836
837QAction::Priority QAction::priority() const
838{
839 Q_D(const QAction);
840 return d->priority;
841}
842
843/*!
844 \property QAction::checkable
845 \brief whether the action is a checkable action
846
847 A checkable action is one which has an on/off state. For example,
848 in a word processor, a Bold toolbar button may be either on or
849 off. An action which is not a toggle action is a command action;
850 a command action is simply executed, e.g. file save.
851 By default, this property is \c false.
852
853 In some situations, the state of one toggle action should depend
854 on the state of others. For example, "Left Align", "Center" and
855 "Right Align" toggle actions are mutually exclusive. To achieve
856 exclusive toggling, add the relevant toggle actions to a
857 QActionGroup with the QActionGroup::exclusive property set to
858 true.
859
860 \sa setChecked()
861*/
862void QAction::setCheckable(bool b)
863{
864 Q_D(QAction);
865 if (d->checkable == b)
866 return;
867
868 d->checkable = b;
869 QPointer<QAction> guard(this);
870 d->sendDataChanged();
871 if (guard)
872 emit checkableChanged(b);
873 if (guard && d->checked)
874 emit toggled(b);
875}
876
877bool QAction::isCheckable() const
878{
879 Q_D(const QAction);
880 return d->checkable;
881}
882
883/*!
884 \fn void QAction::toggle()
885
886 This is a convenience function for the \l checked property.
887 Connect to it to change the checked state to its opposite state.
888*/
889void QAction::toggle()
890{
891 Q_D(QAction);
892 setChecked(!d->checked);
893}
894
895/*!
896 \property QAction::checked
897 \brief whether the action is checked.
898
899 Only checkable actions can be checked. By default, this is false
900 (the action is unchecked).
901
902 \note The notifier signal for this property is toggled(). As toggling
903 a QAction changes its state, it will also emit a changed() signal.
904
905 \sa checkable, toggled()
906*/
907void QAction::setChecked(bool b)
908{
909 Q_D(QAction);
910 if (d->checked == b)
911 return;
912
913 d->checked = b;
914 if (!d->checkable)
915 return;
916 QPointer<QAction> guard(this);
917 d->sendDataChanged();
918 if (guard)
919 emit toggled(b);
920}
921
922bool QAction::isChecked() const
923{
924 Q_D(const QAction);
925 return d->checked && d->checkable;
926}
927
928/*!
929 \fn void QAction::setDisabled(bool b)
930
931 This is a convenience function for the \l enabled property, that
932 is useful for signals--slots connections. If \a b is true the
933 action is disabled; otherwise it is enabled.
934*/
935
936/*!
937 \property QAction::enabled
938 \brief whether the action is enabled
939
940 Disabled actions cannot be chosen by the user. They do not
941 disappear from menus or toolbars, but they are displayed in a way
942 which indicates that they are unavailable. For example, they might
943 be displayed using only shades of gray.
944
945 \uicontrol{What's This?} help on disabled actions is still available, provided
946 that the QAction::whatsThis property is set.
947
948 An action will be disabled when all widgets to which it is added
949 (with QWidget::addAction()) are disabled or not visible. When an
950 action is disabled, it is not possible to trigger it through its
951 shortcut.
952
953 By default, this property is \c true (actions are enabled).
954
955 \sa text
956*/
957void QAction::setEnabled(bool b)
958{
959 Q_D(QAction);
960 if (d->explicitEnabledValue == b && d->explicitEnabled)
961 return;
962 d->explicitEnabledValue = b;
963 d->explicitEnabled = true;
964 QAPP_CHECK("setEnabled");
965 d->setEnabled(b, false);
966}
967
968bool QActionPrivate::setEnabled(bool b, bool byGroup)
969{
970 Q_Q(QAction);
971 if (b && !visible)
972 b = false;
973 if (b && !byGroup && (group && !group->isEnabled()))
974 b = false;
975 if (b && byGroup && explicitEnabled)
976 b = explicitEnabledValue;
977
978 if (b == enabled)
979 return false;
980
981 enabled = b;
982#if QT_CONFIG(shortcut)
983 setShortcutEnabled(b, QGuiApplicationPrivate::instance()->shortcutMap);
984#endif
985 QPointer guard(q);
986 sendDataChanged();
987 if (guard)
988 emit q->enabledChanged(b);
989 return true;
990}
991
992void QAction::resetEnabled()
993{
994 Q_D(QAction);
995 if (!d->explicitEnabled)
996 return;
997 d->explicitEnabled = false;
998 d->setEnabled(true, false);
999}
1000
1001bool QAction::isEnabled() const
1002{
1003 Q_D(const QAction);
1004 return d->enabled;
1005}
1006
1007/*!
1008 \property QAction::visible
1009 \brief whether the action can be seen (e.g. in menus and toolbars)
1010
1011 If \e visible is true the action can be seen (e.g. in menus and
1012 toolbars) and chosen by the user; if \e visible is false the
1013 action cannot be seen or chosen by the user.
1014
1015 Actions which are not visible are \e not grayed out; they do not
1016 appear at all.
1017
1018 By default, this property is \c true (actions are visible).
1019*/
1020void QAction::setVisible(bool b)
1021{
1022 Q_D(QAction);
1023 if (b != d->forceInvisible)
1024 return;
1025 d->forceInvisible = !b;
1026 if (b && d->group && !d->group->isVisible())
1027 return;
1028 d->setVisible(b);
1029}
1030
1031void QActionPrivate::setVisible(bool b)
1032{
1033 Q_Q(QAction);
1034 if (b == visible)
1035 return;
1036 QAPP_CHECK("setVisible");
1037 visible = b;
1038 bool enable = visible;
1039 if (enable && explicitEnabled)
1040 enable = explicitEnabledValue;
1041 QPointer guard(q);
1042 if (!setEnabled(enable, false))
1043 sendDataChanged();
1044 if (guard)
1045 emit q->visibleChanged();
1046}
1047
1048bool QAction::isVisible() const
1049{
1050 Q_D(const QAction);
1051 return d->visible;
1052}
1053
1054/*!
1055 \reimp
1056*/
1057bool QAction::event(QEvent *e)
1058{
1059 Q_D(QAction);
1060 if (e->type() == QEvent::ActionChanged) {
1061 for (auto object : qAsConst(d->associatedObjects))
1062 QCoreApplication::sendEvent(object, e);
1063 }
1064
1065#if QT_CONFIG(shortcut)
1066 if (e->type() == QEvent::Shortcut) {
1067 QShortcutEvent *se = static_cast<QShortcutEvent *>(e);
1068 Q_ASSERT_X(d_func()->shortcutIds.contains(se->shortcutId()),
1069 "QAction::event",
1070 "Received shortcut event from incorrect shortcut");
1071 if (se->isAmbiguous())
1072 qWarning("QAction::event: Ambiguous shortcut overload: %s", se->key().toString(QKeySequence::NativeText).toLatin1().constData());
1073 else
1074 activate(Trigger);
1075 return true;
1076 }
1077#endif // QT_CONFIG(shortcut)
1078 return QObject::event(e);
1079}
1080
1081/*!
1082 Returns the user data as set in QAction::setData.
1083
1084 \sa setData()
1085*/
1086QVariant QAction::data() const
1087{
1088 Q_D(const QAction);
1089 return d->userData;
1090}
1091
1092/*!
1093 Sets the action's internal data to the given \a data.
1094
1095 \sa data()
1096*/
1097void QAction::setData(const QVariant &data)
1098{
1099 Q_D(QAction);
1100 if (d->userData == data)
1101 return;
1102 d->userData = data;
1103 d->sendDataChanged();
1104}
1105
1106/*!
1107 Sends the relevant signals for ActionEvent \a event.
1108
1109 Action-based widgets use this API to cause the QAction
1110 to emit signals as well as emitting their own.
1111*/
1112void QAction::activate(ActionEvent event)
1113{
1114 Q_D(QAction);
1115 if (event == Trigger) {
1116 // Ignore even explicit triggers when explicitly disabled
1117 if ((d->explicitEnabled && !d->explicitEnabledValue) || (d->group && !d->group->isEnabled()))
1118 return;
1119 QPointer<QObject> guard = this;
1120 if (d->checkable) {
1121 // the checked action of an exclusive group may not be unchecked
1122 if (d->checked && (d->group
1123 && d->group->exclusionPolicy() == QActionGroup::ExclusionPolicy::Exclusive
1124 && d->group->checkedAction() == this)) {
1125 if (!guard.isNull())
1126 emit triggered(true);
1127 return;
1128 }
1129 setChecked(!d->checked);
1130 }
1131 if (!guard.isNull())
1132 emit triggered(d->checked);
1133 } else if(event == Hover) {
1134 emit hovered();
1135 }
1136}
1137
1138/*!
1139 \fn void QAction::triggered(bool checked)
1140
1141 This signal is emitted when an action is activated by the user;
1142 for example, when the user clicks a menu option, toolbar button,
1143 or presses an action's shortcut key combination, or when trigger()
1144 was called. Notably, it is \e not emitted when setChecked() or
1145 toggle() is called.
1146
1147 If the action is checkable, \a checked is true if the action is
1148 checked, or false if the action is unchecked.
1149
1150 \sa activate(), toggled(), checked
1151*/
1152
1153/*!
1154 \fn void QAction::toggled(bool checked)
1155
1156 This signal is emitted whenever a checkable action changes its
1157 isChecked() status. This can be the result of a user interaction,
1158 or because setChecked() was called. As setChecked() changes the
1159 QAction, it emits changed() in addition to toggled().
1160
1161 \a checked is true if the action is checked, or false if the
1162 action is unchecked.
1163
1164 \sa activate(), triggered(), checked
1165*/
1166
1167/*!
1168 \fn void QAction::hovered()
1169
1170 This signal is emitted when an action is highlighted by the user;
1171 for example, when the user pauses with the cursor over a menu option,
1172 toolbar button, or presses an action's shortcut key combination.
1173
1174 \sa activate()
1175*/
1176
1177/*!
1178 \fn void QAction::changed()
1179
1180 This signal is emitted when an action has changed. If you
1181 are only interested in actions in a given widget, you can
1182 watch for QWidget::actionEvent() sent with an
1183 QEvent::ActionChanged.
1184
1185 \sa QWidget::actionEvent()
1186*/
1187
1188/*!
1189 \enum QAction::ActionEvent
1190
1191 This enum type is used when calling QAction::activate()
1192
1193 \value Trigger this will cause the QAction::triggered() signal to be emitted.
1194
1195 \value Hover this will cause the QAction::hovered() signal to be emitted.
1196*/
1197
1198/*!
1199 \property QAction::menuRole
1200 \brief the action's menu role
1201
1202 This indicates what role the action serves in the application menu on
1203 \macos. By default all actions have the TextHeuristicRole, which means that
1204 the action is added based on its text (see QMenuBar for more information).
1205
1206 The menu role can only be changed before the actions are put into the menu
1207 bar in \macos (usually just before the first application window is
1208 shown).
1209*/
1210void QAction::setMenuRole(MenuRole menuRole)
1211{
1212 Q_D(QAction);
1213 if (d->menuRole == menuRole)
1214 return;
1215
1216 d->menuRole = menuRole;
1217 d->sendDataChanged();
1218}
1219
1220QAction::MenuRole QAction::menuRole() const
1221{
1222 Q_D(const QAction);
1223 return d->menuRole;
1224}
1225
1226/*!
1227 \fn QMenu *QAction::menu() const
1228 \obsolete
1229
1230 Returns the menu contained by this action.
1231
1232 In widget applications, actions that contain menus can be used to create menu
1233 items with submenus, or inserted into toolbars to create buttons with popup menus.
1234
1235 \sa QMenu::addAction()
1236*/
1237QObject* QAction::menuObject() const
1238{
1239 Q_D(const QAction);
1240 return d->menu();
1241}
1242
1243/*!
1244 \fn void QAction::setMenu(QMenu *menu)
1245 \obsolete
1246
1247 Sets the menu contained by this action to the specified \a menu.
1248*/
1249void QAction::setMenuObject(QObject *object)
1250{
1251 Q_D(QAction);
1252 d->setMenu(object);
1253}
1254
1255/*!
1256 \property QAction::iconVisibleInMenu
1257 \brief Whether or not an action should show an icon in a menu
1258
1259 In some applications, it may make sense to have actions with icons in the
1260 toolbar, but not in menus. If true, the icon (if valid) is shown in the menu, when it
1261 is false, it is not shown.
1262
1263 The default is to follow whether the Qt::AA_DontShowIconsInMenus attribute
1264 is set for the application. Explicitly settings this property overrides
1265 the presence (or abscence) of the attribute.
1266
1267 For example:
1268 \snippet code/src_gui_kernel_qaction.cpp 0
1269
1270 \sa icon, QCoreApplication::setAttribute()
1271*/
1272void QAction::setIconVisibleInMenu(bool visible)
1273{
1274 Q_D(QAction);
1275 if (d->iconVisibleInMenu == -1 || visible != bool(d->iconVisibleInMenu)) {
1276 int oldValue = d->iconVisibleInMenu;
1277 d->iconVisibleInMenu = visible;
1278 // Only send data changed if we really need to.
1279 if (oldValue != -1
1280 || visible == !QCoreApplication::testAttribute(Qt::AA_DontShowIconsInMenus)) {
1281 d->sendDataChanged();
1282 }
1283 }
1284}
1285
1286bool QAction::isIconVisibleInMenu() const
1287{
1288 Q_D(const QAction);
1289 if (d->iconVisibleInMenu == -1) {
1290 return !QCoreApplication::testAttribute(Qt::AA_DontShowIconsInMenus);
1291 }
1292 return d->iconVisibleInMenu;
1293}
1294
1295/*!
1296 \property QAction::shortcutVisibleInContextMenu
1297 \brief Whether or not an action should show a shortcut in a context menu
1298
1299 In some applications, it may make sense to have actions with shortcuts in
1300 context menus. If true, the shortcut (if valid) is shown when the action is
1301 shown via a context menu, when it is false, it is not shown.
1302
1303 The default is to follow whether the Qt::AA_DontShowShortcutsInContextMenus attribute
1304 is set for the application, falling back to the widget style hint.
1305 Explicitly setting this property overrides the presence (or abscence) of the attribute.
1306
1307 \sa shortcut, QCoreApplication::setAttribute()
1308*/
1309void QAction::setShortcutVisibleInContextMenu(bool visible)
1310{
1311 Q_D(QAction);
1312 if (d->shortcutVisibleInContextMenu == -1 || visible != bool(d->shortcutVisibleInContextMenu)) {
1313 int oldValue = d->shortcutVisibleInContextMenu;
1314 d->shortcutVisibleInContextMenu = visible;
1315 // Only send data changed if we really need to.
1316 if (oldValue != -1
1317 || visible == !QCoreApplication::testAttribute(Qt::AA_DontShowShortcutsInContextMenus)) {
1318 d->sendDataChanged();
1319 }
1320 }
1321}
1322
1323bool QAction::isShortcutVisibleInContextMenu() const
1324{
1325 Q_D(const QAction);
1326 if (d->shortcutVisibleInContextMenu == -1) {
1327 return !QCoreApplication::testAttribute(Qt::AA_DontShowShortcutsInContextMenus)
1328 && QGuiApplication::styleHints()->showShortcutsInContextMenus();
1329 }
1330 return d->shortcutVisibleInContextMenu;
1331}
1332
1333#ifndef QT_NO_DEBUG_STREAM
1334Q_GUI_EXPORT QDebug operator<<(QDebug d, const QAction *action)
1335{
1336 QDebugStateSaver saver(d);
1337 d.nospace();
1338 d << "QAction(" << static_cast<const void *>(action);
1339 if (action) {
1340 d << " text=" << action->text();
1341 if (!action->toolTip().isEmpty())
1342 d << " toolTip=" << action->toolTip();
1343 if (action->isCheckable())
1344 d << " checked=" << action->isChecked();
1345#if QT_CONFIG(shortcut)
1346 if (!action->shortcuts().isEmpty())
1347 d << " shortcuts=" << action->shortcuts();
1348#endif
1349 d << " menuRole=";
1350 QtDebugUtils::formatQEnum(d, action->menuRole());
1351 d << " enabled=" << action->isEnabled();
1352 d << " visible=" << action->isVisible();
1353 } else {
1354 d << '0';
1355 }
1356 d << ')';
1357 return d;
1358}
1359#endif // QT_NO_DEBUG_STREAM
1360
1361QT_END_NAMESPACE
1362
1363#include "moc_qaction.cpp"
1364