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, as long as
542 QAction::iconVisibleInMenu returns \c true.
543
544 There is no default icon.
545
546 If a null icon (QIcon::isNull()) is passed into this function,
547 the icon of the action is cleared.
548*/
549void QAction::setIcon(const QIcon &icon)
550{
551 Q_D(QAction);
552 d->icon = icon;
553 d->sendDataChanged();
554}
555
556QIcon QAction::icon() const
557{
558 Q_D(const QAction);
559 return d->icon;
560}
561
562/*!
563 If \a b is true then this action will be considered a separator.
564
565 How a separator is represented depends on the widget it is inserted
566 into. Under most circumstances the text, submenu, and icon will be
567 ignored for separator actions.
568
569 \sa isSeparator()
570*/
571void QAction::setSeparator(bool b)
572{
573 Q_D(QAction);
574 if (d->separator == b)
575 return;
576
577 d->separator = b;
578 d->sendDataChanged();
579}
580
581/*!
582 Returns \c true if this action is a separator action; otherwise it
583 returns \c false.
584
585 \sa setSeparator()
586*/
587bool QAction::isSeparator() const
588{
589 Q_D(const QAction);
590 return d->separator;
591}
592
593/*!
594 \property QAction::text
595 \brief the action's descriptive text
596
597 If the action is added to a menu, the menu option will consist of
598 the icon (if there is one), the text, and the shortcut (if there
599 is one). If the text is not explicitly set in the constructor, or
600 by using setText(), the action's description icon text will be
601 used as text. There is no default text.
602
603 Certain UI elements, such as menus or buttons, can use '&' in front of a
604 character to automatically create a mnemonic (a shortcut) for that
605 character. For example, "&File" for a menu will create the shortcut
606 \uicontrol Alt+F, which will open the File menu. "E&xit" will create the
607 shortcut \uicontrol Alt+X for a button, or in a menu allow navigating to
608 the menu item by pressing "x". (use '&&' to display an actual ampersand).
609 The widget might consume and perform an action on a given shortcut.
610
611 \sa iconText
612*/
613void QAction::setText(const QString &text)
614{
615 Q_D(QAction);
616 if (d->text == text)
617 return;
618
619 d->text = text;
620 d->sendDataChanged();
621}
622
623QString QAction::text() const
624{
625 Q_D(const QAction);
626 QString s = d->text;
627 if (s.isEmpty()) {
628 s = d->iconText;
629 s.replace(c: u'&', after: "&&"_L1);
630 }
631 return s;
632}
633
634/*!
635 \property QAction::iconText
636 \brief the action's descriptive icon text
637
638 If QToolBar::toolButtonStyle is set to a value that permits text to
639 be displayed, the text defined held in this property appears as a
640 label in the relevant tool button.
641
642 It also serves as the default text in menus and tooltips if the action
643 has not been defined with setText() or setToolTip(), and will
644 also be used in toolbar buttons if no icon has been defined using setIcon().
645
646 If the icon text is not explicitly set, the action's normal text will be
647 used for the icon text.
648
649 By default, this property contains an empty string.
650
651 \sa setToolTip(), setStatusTip()
652*/
653void QAction::setIconText(const QString &text)
654{
655 Q_D(QAction);
656 if (d->iconText == text)
657 return;
658
659 d->iconText = text;
660 d->sendDataChanged();
661}
662
663QString QAction::iconText() const
664{
665 Q_D(const QAction);
666 if (d->iconText.isEmpty())
667 return qt_strippedText(s: d->text);
668 return d->iconText;
669}
670
671/*!
672 \property QAction::toolTip
673 \brief the action's tooltip
674
675 This text is used for the tooltip. If no tooltip is specified,
676 the action's text is used.
677
678 By default, this property contains the action's text.
679
680 \sa setStatusTip(), setShortcut()
681*/
682void QAction::setToolTip(const QString &tooltip)
683{
684 Q_D(QAction);
685 if (d->tooltip == tooltip)
686 return;
687
688 d->tooltip = tooltip;
689 d->sendDataChanged();
690}
691
692QString QAction::toolTip() const
693{
694 Q_D(const QAction);
695 if (d->tooltip.isEmpty()) {
696 if (!d->text.isEmpty())
697 return qt_strippedText(s: d->text);
698 return qt_strippedText(s: d->iconText);
699 }
700 return d->tooltip;
701}
702
703/*!
704 \property QAction::statusTip
705 \brief the action's status tip
706
707 The status tip is displayed on all status bars provided by the
708 action's top-level parent widget.
709
710 By default, this property contains an empty string.
711
712 \sa setToolTip(), showStatusText()
713*/
714void QAction::setStatusTip(const QString &statustip)
715{
716 Q_D(QAction);
717 if (d->statustip == statustip)
718 return;
719
720 d->statustip = statustip;
721 d->sendDataChanged();
722}
723
724QString QAction::statusTip() const
725{
726 Q_D(const QAction);
727 return d->statustip;
728}
729
730/*!
731 Updates the relevant status bar for the UI represented by \a object by sending a
732 QStatusTipEvent. Returns \c true if an event was sent, otherwise returns \c false.
733
734 If a null widget is specified, the event is sent to the action's parent.
735
736 \sa statusTip
737*/
738bool QAction::showStatusText(QObject *object)
739{
740 Q_D(QAction);
741 return d->showStatusText(object, str: statusTip());
742}
743
744/*!
745 \property QAction::whatsThis
746 \brief the action's "What's This?" help text
747
748 The "What's This?" text is used to provide a brief description of
749 the action. The text may contain rich text. There is no default
750 "What's This?" text.
751
752 \sa QWhatsThis
753*/
754void QAction::setWhatsThis(const QString &whatsthis)
755{
756 Q_D(QAction);
757 if (d->whatsthis == whatsthis)
758 return;
759
760 d->whatsthis = whatsthis;
761 d->sendDataChanged();
762}
763
764QString QAction::whatsThis() const
765{
766 Q_D(const QAction);
767 return d->whatsthis;
768}
769
770/*!
771 \enum QAction::Priority
772
773 This enum defines priorities for actions in user interface.
774
775 \value LowPriority The action should not be prioritized in
776 the user interface.
777
778 \value NormalPriority
779
780 \value HighPriority The action should be prioritized in
781 the user interface.
782
783 \sa priority
784*/
785
786
787/*!
788 \property QAction::priority
789
790 \brief the actions's priority in the user interface.
791
792 This property can be set to indicate how the action should be prioritized
793 in the user interface.
794
795 For instance, when toolbars have the Qt::ToolButtonTextBesideIcon
796 mode set, then actions with LowPriority will not show the text
797 labels.
798*/
799void QAction::setPriority(Priority priority)
800{
801 Q_D(QAction);
802 if (d->priority == priority)
803 return;
804
805 d->priority = priority;
806 d->sendDataChanged();
807}
808
809QAction::Priority QAction::priority() const
810{
811 Q_D(const QAction);
812 return d->priority;
813}
814
815/*!
816 \property QAction::checkable
817 \brief whether the action is a checkable action
818
819 A checkable action is one which has an on/off state. For example,
820 in a word processor, a Bold toolbar button may be either on or
821 off. An action which is not a toggle action is a command action;
822 a command action is simply executed, e.g. file save.
823 By default, this property is \c false.
824
825 In some situations, the state of one toggle action should depend
826 on the state of others. For example, "Left Align", "Center" and
827 "Right Align" toggle actions are mutually exclusive. To achieve
828 exclusive toggling, add the relevant toggle actions to a
829 QActionGroup with the QActionGroup::exclusive property set to
830 true.
831
832 \sa setChecked()
833*/
834void QAction::setCheckable(bool b)
835{
836 Q_D(QAction);
837 if (d->checkable == b)
838 return;
839
840 d->checkable = b;
841 QPointer<QAction> guard(this);
842 d->sendDataChanged();
843 if (guard)
844 emit checkableChanged(checkable: b);
845 if (guard && d->checked)
846 emit toggled(b);
847}
848
849bool QAction::isCheckable() const
850{
851 Q_D(const QAction);
852 return d->checkable;
853}
854
855/*!
856 \fn void QAction::toggle()
857
858 This is a convenience function for the \l checked property.
859 Connect to it to change the checked state to its opposite state.
860*/
861void QAction::toggle()
862{
863 Q_D(QAction);
864 setChecked(!d->checked);
865}
866
867/*!
868 \property QAction::checked
869 \brief whether the action is checked.
870
871 Only checkable actions can be checked. By default, this is false
872 (the action is unchecked).
873
874 \note The notifier signal for this property is toggled(). As toggling
875 a QAction changes its state, it will also emit a changed() signal.
876
877 \sa checkable, toggled()
878*/
879void QAction::setChecked(bool b)
880{
881 Q_D(QAction);
882 if (d->checked == b)
883 return;
884
885 d->checked = b;
886 if (!d->checkable)
887 return;
888 QPointer<QAction> guard(this);
889 d->sendDataChanged();
890 if (guard)
891 emit toggled(b);
892}
893
894bool QAction::isChecked() const
895{
896 Q_D(const QAction);
897 return d->checked && d->checkable;
898}
899
900/*!
901 \fn void QAction::setDisabled(bool b)
902
903 This is a convenience function for the \l enabled property, that
904 is useful for signals--slots connections. If \a b is true the
905 action is disabled; otherwise it is enabled.
906*/
907
908/*!
909 \property QAction::enabled
910 \brief whether the action is enabled
911
912 Disabled actions cannot be chosen by the user. They do not
913 disappear from menus or toolbars, but they are displayed in a way
914 which indicates that they are unavailable. For example, they might
915 be displayed using only shades of gray.
916
917 \uicontrol{What's This?} help on disabled actions is still available, provided
918 that the QAction::whatsThis property is set.
919
920 An action will be disabled when all widgets to which it is added
921 (with QWidget::addAction()) are disabled or not visible. When an
922 action is disabled, it is not possible to trigger it through its
923 shortcut.
924
925 By default, this property is \c true (actions are enabled).
926
927 \sa text
928*/
929void QAction::setEnabled(bool b)
930{
931 Q_D(QAction);
932 if (d->explicitEnabledValue == b && d->explicitEnabled)
933 return;
934 d->explicitEnabledValue = b;
935 d->explicitEnabled = true;
936 QAPP_CHECK("setEnabled");
937 d->setEnabled(enable: b, byGroup: false);
938}
939
940bool QActionPrivate::setEnabled(bool b, bool byGroup)
941{
942 Q_Q(QAction);
943 if (b && !visible)
944 b = false;
945 if (b && !byGroup && (group && !group->isEnabled()))
946 b = false;
947 if (b && byGroup && explicitEnabled)
948 b = explicitEnabledValue;
949
950 if (b == enabled)
951 return false;
952
953 enabled = b;
954#if QT_CONFIG(shortcut)
955 setShortcutEnabled(enable: b, map&: QGuiApplicationPrivate::instance()->shortcutMap);
956#endif
957 QPointer guard(q);
958 sendDataChanged();
959 if (guard)
960 emit q->enabledChanged(enabled: b);
961 return true;
962}
963
964void QAction::resetEnabled()
965{
966 Q_D(QAction);
967 if (!d->explicitEnabled)
968 return;
969 d->explicitEnabled = false;
970 d->setEnabled(b: true, byGroup: false);
971}
972
973bool QAction::isEnabled() const
974{
975 Q_D(const QAction);
976 return d->enabled;
977}
978
979/*!
980 \property QAction::visible
981 \brief whether the action can be seen (e.g. in menus and toolbars)
982
983 If \e visible is true the action can be seen (e.g. in menus and
984 toolbars) and chosen by the user; if \e visible is false the
985 action cannot be seen or chosen by the user.
986
987 Actions which are not visible are \e not grayed out; they do not
988 appear at all.
989
990 By default, this property is \c true (actions are visible).
991*/
992void QAction::setVisible(bool b)
993{
994 Q_D(QAction);
995 if (b != d->forceInvisible)
996 return;
997 d->forceInvisible = !b;
998 if (b && d->group && !d->group->isVisible())
999 return;
1000 d->setVisible(b);
1001}
1002
1003void QActionPrivate::setVisible(bool b)
1004{
1005 Q_Q(QAction);
1006 if (b == visible)
1007 return;
1008 QAPP_CHECK("setVisible");
1009 visible = b;
1010 bool enable = visible;
1011 if (enable && explicitEnabled)
1012 enable = explicitEnabledValue;
1013 QPointer guard(q);
1014 if (!setEnabled(b: enable, byGroup: false))
1015 sendDataChanged();
1016 if (guard)
1017 emit q->visibleChanged();
1018}
1019
1020bool QAction::isVisible() const
1021{
1022 Q_D(const QAction);
1023 return d->visible;
1024}
1025
1026/*!
1027 \reimp
1028*/
1029bool QAction::event(QEvent *e)
1030{
1031 Q_D(QAction);
1032 if (e->type() == QEvent::ActionChanged) {
1033 for (auto object : std::as_const(t&: d->associatedObjects))
1034 QCoreApplication::sendEvent(receiver: object, event: e);
1035 }
1036
1037#if QT_CONFIG(shortcut)
1038 if (e->type() == QEvent::Shortcut) {
1039 QShortcutEvent *se = static_cast<QShortcutEvent *>(e);
1040 Q_ASSERT_X(d_func()->shortcutIds.contains(se->shortcutId()),
1041 "QAction::event",
1042 "Received shortcut event from incorrect shortcut");
1043 if (se->isAmbiguous())
1044 qWarning(msg: "QAction::event: Ambiguous shortcut overload: %s", se->key().toString(format: QKeySequence::NativeText).toLatin1().constData());
1045 else
1046 activate(event: Trigger);
1047 return true;
1048 }
1049#endif // QT_CONFIG(shortcut)
1050 return QObject::event(event: e);
1051}
1052
1053/*!
1054 Returns the user data as set in QAction::setData.
1055
1056 \sa setData()
1057*/
1058QVariant QAction::data() const
1059{
1060 Q_D(const QAction);
1061 return d->userData;
1062}
1063
1064/*!
1065 Sets the action's internal data to the given \a data.
1066
1067 \sa data()
1068*/
1069void QAction::setData(const QVariant &data)
1070{
1071 Q_D(QAction);
1072 if (d->userData == data)
1073 return;
1074 d->userData = data;
1075 d->sendDataChanged();
1076}
1077
1078/*!
1079 Sends the relevant signals for ActionEvent \a event.
1080
1081 Action-based widgets use this API to cause the QAction
1082 to emit signals as well as emitting their own.
1083*/
1084void QAction::activate(ActionEvent event)
1085{
1086 Q_D(QAction);
1087 if (event == Trigger) {
1088 // Ignore even explicit triggers when explicitly disabled
1089 if ((d->explicitEnabled && !d->explicitEnabledValue) || (d->group && !d->group->isEnabled()))
1090 return;
1091 QPointer<QObject> guard = this;
1092 if (d->checkable) {
1093 // the checked action of an exclusive group may not be unchecked
1094 if (d->checked && (d->group
1095 && d->group->exclusionPolicy() == QActionGroup::ExclusionPolicy::Exclusive
1096 && d->group->checkedAction() == this)) {
1097 if (!guard.isNull())
1098 emit triggered(checked: true);
1099 return;
1100 }
1101 setChecked(!d->checked);
1102 }
1103 if (!guard.isNull())
1104 emit triggered(checked: d->checked);
1105 } else if (event == Hover) {
1106 emit hovered();
1107 }
1108}
1109
1110/*!
1111 \fn void QAction::triggered(bool checked)
1112
1113 This signal is emitted when an action is activated by the user;
1114 for example, when the user clicks a menu option, toolbar button,
1115 or presses an action's shortcut key combination, or when trigger()
1116 was called. Notably, it is \e not emitted when setChecked() or
1117 toggle() is called.
1118
1119 If the action is checkable, \a checked is true if the action is
1120 checked, or false if the action is unchecked.
1121
1122 \sa activate(), toggled(), checked
1123*/
1124
1125/*!
1126 \fn void QAction::toggled(bool checked)
1127
1128 This signal is emitted whenever a checkable action changes its
1129 isChecked() status. This can be the result of a user interaction,
1130 or because setChecked() was called. As setChecked() changes the
1131 QAction, it emits changed() in addition to toggled().
1132
1133 \a checked is true if the action is checked, or false if the
1134 action is unchecked.
1135
1136 \sa activate(), triggered(), checked
1137*/
1138
1139/*!
1140 \fn void QAction::hovered()
1141
1142 This signal is emitted when an action is highlighted by the user;
1143 for example, when the user pauses with the cursor over a menu option,
1144 toolbar button, or presses an action's shortcut key combination.
1145
1146 \sa activate()
1147*/
1148
1149/*!
1150 \fn void QAction::changed()
1151
1152 This signal is emitted when an action has changed. If you
1153 are only interested in actions in a given widget, you can
1154 watch for QWidget::actionEvent() sent with an
1155 QEvent::ActionChanged.
1156
1157 \sa QWidget::actionEvent()
1158*/
1159
1160/*!
1161 \enum QAction::ActionEvent
1162
1163 This enum type is used when calling QAction::activate()
1164
1165 \value Trigger this will cause the QAction::triggered() signal to be emitted.
1166
1167 \value Hover this will cause the QAction::hovered() signal to be emitted.
1168*/
1169
1170/*!
1171 \property QAction::menuRole
1172 \brief the action's menu role
1173
1174 This indicates what role the action serves in the application menu on
1175 \macos. By default all actions have the TextHeuristicRole, which means that
1176 the action is added based on its text (see QMenuBar for more information).
1177
1178 The menu role can only be changed before the actions are put into the menu
1179 bar in \macos (usually just before the first application window is
1180 shown).
1181*/
1182void QAction::setMenuRole(MenuRole menuRole)
1183{
1184 Q_D(QAction);
1185 if (d->menuRole == menuRole)
1186 return;
1187
1188 d->menuRole = menuRole;
1189 d->sendDataChanged();
1190}
1191
1192QAction::MenuRole QAction::menuRole() const
1193{
1194 Q_D(const QAction);
1195 return d->menuRole;
1196}
1197
1198/*!
1199 \fn QMenu *QAction::menu() const
1200
1201 Returns the menu contained by this action.
1202
1203 In widget applications, actions that contain menus can be used to create menu
1204 items with submenus, or inserted into toolbars to create buttons with popup menus.
1205
1206 \sa QMenu::addAction(), QMenu::menuInAction()
1207*/
1208QObject* QAction::menuObject() const
1209{
1210 Q_D(const QAction);
1211 return d->menu();
1212}
1213
1214/*!
1215 \fn void QAction::setMenu(QMenu *menu)
1216
1217 Sets the menu contained by this action to the specified \a menu.
1218*/
1219void QAction::setMenuObject(QObject *object)
1220{
1221 Q_D(QAction);
1222 d->setMenu(object);
1223}
1224
1225/*!
1226 \property QAction::iconVisibleInMenu
1227 \brief Whether or not an action should show an icon in a menu
1228
1229 In some applications, it may make sense to have actions with icons in the
1230 toolbar, but not in menus. If true, the icon (if valid) is shown in the menu, when it
1231 is false, it is not shown.
1232
1233 The default is to follow whether the Qt::AA_DontShowIconsInMenus attribute
1234 is set for the application. Explicitly settings this property overrides
1235 the presence (or absence) of the attribute.
1236
1237 For example:
1238 \snippet code/src_gui_kernel_qaction.cpp 0
1239
1240 \sa icon, QCoreApplication::setAttribute()
1241*/
1242void QAction::setIconVisibleInMenu(bool visible)
1243{
1244 Q_D(QAction);
1245 if (d->iconVisibleInMenu == -1 || visible != bool(d->iconVisibleInMenu)) {
1246 int oldValue = d->iconVisibleInMenu;
1247 d->iconVisibleInMenu = visible;
1248 // Only send data changed if we really need to.
1249 if (oldValue != -1
1250 || visible == !QCoreApplication::testAttribute(attribute: Qt::AA_DontShowIconsInMenus)) {
1251 d->sendDataChanged();
1252 }
1253 }
1254}
1255
1256bool QAction::isIconVisibleInMenu() const
1257{
1258 Q_D(const QAction);
1259 if (d->iconVisibleInMenu == -1) {
1260 return !QCoreApplication::testAttribute(attribute: Qt::AA_DontShowIconsInMenus);
1261 }
1262 return d->iconVisibleInMenu;
1263}
1264
1265/*!
1266 \property QAction::shortcutVisibleInContextMenu
1267 \brief Whether or not an action should show a shortcut in a context menu
1268
1269 In some applications, it may make sense to have actions with shortcuts in
1270 context menus. If true, the shortcut (if valid) is shown when the action is
1271 shown via a context menu, when it is false, it is not shown.
1272
1273 The default is to follow whether the Qt::AA_DontShowShortcutsInContextMenus attribute
1274 is set for the application. Explicitly setting this property overrides the attribute.
1275
1276 \sa shortcut, QCoreApplication::setAttribute()
1277*/
1278void QAction::setShortcutVisibleInContextMenu(bool visible)
1279{
1280 Q_D(QAction);
1281 if (d->shortcutVisibleInContextMenu == -1 || visible != bool(d->shortcutVisibleInContextMenu)) {
1282 int oldValue = d->shortcutVisibleInContextMenu;
1283 d->shortcutVisibleInContextMenu = visible;
1284 // Only send data changed if we really need to.
1285 if (oldValue != -1
1286 || visible == !QCoreApplication::testAttribute(attribute: Qt::AA_DontShowShortcutsInContextMenus)) {
1287 d->sendDataChanged();
1288 }
1289 }
1290}
1291
1292bool QAction::isShortcutVisibleInContextMenu() const
1293{
1294 Q_D(const QAction);
1295 if (d->shortcutVisibleInContextMenu == -1)
1296 return !QCoreApplication::testAttribute(attribute: Qt::AA_DontShowShortcutsInContextMenus);
1297 return d->shortcutVisibleInContextMenu;
1298}
1299
1300#ifndef QT_NO_DEBUG_STREAM
1301Q_GUI_EXPORT QDebug operator<<(QDebug d, const QAction *action)
1302{
1303 QDebugStateSaver saver(d);
1304 d.nospace();
1305 d << "QAction(" << static_cast<const void *>(action);
1306 if (action) {
1307 d << " text=" << action->text();
1308 if (!action->toolTip().isEmpty())
1309 d << " toolTip=" << action->toolTip();
1310 if (action->isCheckable())
1311 d << " checked=" << action->isChecked();
1312#if QT_CONFIG(shortcut)
1313 if (!action->shortcuts().isEmpty())
1314 d << " shortcuts=" << action->shortcuts();
1315#endif
1316 d << " menuRole=";
1317 QtDebugUtils::formatQEnum(debug&: d, value: action->menuRole());
1318 d << " enabled=" << action->isEnabled();
1319 d << " visible=" << action->isVisible();
1320 }
1321 d << ')';
1322 return d;
1323}
1324#endif // QT_NO_DEBUG_STREAM
1325
1326QT_END_NAMESPACE
1327
1328#include "moc_qaction.cpp"
1329

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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