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

source code of qtbase/src/gui/kernel/qaction.cpp