Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qwidgetaction.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 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// Qt-Security score:significant reason:default
4
6#include "qwidget.h"
7#include "qdebug.h"
8
9#include <QtWidgets/private/qwidget_p.h>
10
12
14
15/*!
16 \class QWidgetAction
17 \since 4.2
18 \brief The QWidgetAction class extends QAction by an interface
19 for inserting custom widgets into action based containers, such
20 as toolbars.
21
22 \ingroup mainwindow-classes
23 \inmodule QtWidgets
24
25 Most actions in an application are represented as items in menus or
26 buttons in toolbars. However sometimes more complex widgets are
27 necessary. For example a zoom action in a word processor may be
28 realized using a QComboBox in a QToolBar, presenting a range
29 of different zoom levels. QToolBar provides QToolBar::insertWidget()
30 as convenience function for inserting a single widget.
31 However if you want to implement an action that uses custom
32 widgets for visualization in multiple containers then you have to
33 subclass QWidgetAction.
34
35 If a QWidgetAction is added for example to a QToolBar then
36 QWidgetAction::createWidget() is called. Reimplementations of that
37 function should create a new custom widget with the specified parent.
38
39 If the action is removed from a container widget then
40 QWidgetAction::deleteWidget() is called with the previously created custom
41 widget as argument. The default implementation hides the widget and deletes
42 it using QObject::deleteLater().
43
44 If you have only one single custom widget then you can set it as default
45 widget using setDefaultWidget(). That widget will then be used if the
46 action is added to a QToolBar, or in general to an action container that
47 supports QWidgetAction. If a QWidgetAction with only a default widget is
48 added to two toolbars at the same time then the default widget is shown
49 only in the first toolbar the action was added to. QWidgetAction takes
50 over ownership of the default widget.
51
52 Note that it is up to the widget to activate the action, for example by
53 reimplementing mouse event handlers and calling QAction::trigger().
54
55 \b {\macos}: If you add a widget to a menu in the application's menu
56 bar on \macos, the widget will be added and it will function but with some
57 limitations:
58 \list 1
59 \li The widget is reparented away from the QMenu to the native menu
60 view. If you show the menu in some other place (e.g. as a popup menu),
61 the widget will not be there.
62 \li Focus/Keyboard handling of the widget is not possible.
63 \li Due to Apple's design, mouse tracking on the widget currently does
64 not work.
65 \li Connecting the triggered() signal to a slot that opens a modal
66 dialog will cause a crash in \macos 10.4 (known bug acknowledged
67 by Apple), a workaround is to use a QueuedConnection instead of a
68 DirectConnection.
69 \endlist
70
71 \sa QAction, QActionGroup, QWidget
72*/
73
74/*!
75 Constructs an action with \a parent.
76*/
77QWidgetAction::QWidgetAction(QObject *parent)
78 : QAction(*(new QWidgetActionPrivate), parent)
79{
80}
81
82/*!
83 Destroys the object and frees allocated resources.
84*/
85QWidgetAction::~QWidgetAction()
86{
87 Q_D(QWidgetAction);
88 for (QWidget *w : std::as_const(d->createdWidgets))
89 QObjectPrivate::disconnect(w, &QWidget::destroyed,
90 d, &QWidgetActionPrivate::widgetDestroyed);
91 QList<QWidget *> widgetsToDelete = d->createdWidgets;
92 d->createdWidgets.clear();
93 qDeleteAll(widgetsToDelete);
94 delete d->defaultWidget;
95}
96
97/*!
98 Sets \a widget to be the default widget. The ownership is
99 transferred to QWidgetAction. Unless createWidget() is
100 reimplemented by a subclass to return a new widget the default
101 widget is used when a container widget requests a widget through
102 requestWidget().
103*/
104void QWidgetAction::setDefaultWidget(QWidget *widget)
105{
106 Q_D(QWidgetAction);
107 if (widget == d->defaultWidget || d->defaultWidgetInUse)
108 return;
109 delete d->defaultWidget;
110 d->defaultWidget = widget;
111 if (!widget)
112 return;
113
114 setVisible(!QWidgetPrivate::get(widget)->isExplicitlyHidden());
115 d->defaultWidget->hide();
116 d->defaultWidget->setParent(nullptr);
117 d->defaultWidgetInUse = false;
118 if (!isEnabled())
119 d->defaultWidget->setEnabled(false);
120}
121
122/*!
123 Returns the default widget.
124*/
125QWidget *QWidgetAction::defaultWidget() const
126{
127 Q_D(const QWidgetAction);
128 return d->defaultWidget;
129}
130
131/*!
132 Returns a widget that represents the action, with the given \a
133 parent.
134
135 Container widgets that support actions can call this function to
136 request a widget as visual representation of the action.
137
138 \sa releaseWidget(), createWidget(), defaultWidget()
139*/
140QWidget *QWidgetAction::requestWidget(QWidget *parent)
141{
142 Q_D(QWidgetAction);
143
144 QWidget *w = createWidget(parent);
145 if (!w) {
146 if (d->defaultWidgetInUse || !d->defaultWidget)
147 return nullptr;
148 d->defaultWidget->setParent(parent);
149 d->defaultWidgetInUse = true;
150 return d->defaultWidget;
151 }
152
153 QObjectPrivate::connect(w, &QWidget::destroyed,
154 d, &QWidgetActionPrivate::widgetDestroyed);
155 d->createdWidgets.append(w);
156 return w;
157}
158
159/*!
160 Releases the specified \a widget.
161
162 Container widgets that support actions call this function when a widget
163 action is removed.
164
165 \sa requestWidget(), deleteWidget(), defaultWidget()
166*/
167void QWidgetAction::releaseWidget(QWidget *widget)
168{
169 Q_D(QWidgetAction);
170
171 if (widget == d->defaultWidget) {
172 d->defaultWidget->hide();
173 d->defaultWidget->setParent(nullptr);
174 d->defaultWidgetInUse = false;
175 return;
176 }
177
178 if (!d->createdWidgets.contains(widget))
179 return;
180
181 QObjectPrivate::disconnect(widget, &QWidget::destroyed,
182 d, &QWidgetActionPrivate::widgetDestroyed);
183 d->createdWidgets.removeAll(widget);
184 deleteWidget(widget);
185}
186
187/*!
188 \reimp
189*/
190bool QWidgetAction::event(QEvent *event)
191{
192 Q_D(QWidgetAction);
193 if (event->type() == QEvent::ActionChanged) {
194 if (d->defaultWidget)
195 d->defaultWidget->setEnabled(isEnabled());
196 for (int i = 0; i < d->createdWidgets.size(); ++i)
197 d->createdWidgets.at(i)->setEnabled(isEnabled());
198 }
199 return QAction::event(event);
200}
201
202/*!
203 \reimp
204 */
205bool QWidgetAction::eventFilter(QObject *obj, QEvent *event)
206{
207 return QAction::eventFilter(obj,event);
208}
209
210/*!
211 This function is called whenever the action is added to a container widget
212 that supports custom widgets. If you don't want a custom widget to be
213 used as representation of the action in the specified \a parent widget then
214 0 should be returned.
215
216 \sa deleteWidget()
217*/
218QWidget *QWidgetAction::createWidget(QWidget *parent)
219{
220 Q_UNUSED(parent);
221 return nullptr;
222}
223
224/*!
225 This function is called whenever the action is removed from a
226 container widget that displays the action using a custom \a
227 widget previously created using createWidget(). The default
228 implementation hides the \a widget and schedules it for deletion
229 using QObject::deleteLater().
230
231 \sa createWidget()
232*/
233void QWidgetAction::deleteWidget(QWidget *widget)
234{
235 widget->hide();
236 widget->deleteLater();
237}
238
239/*!
240 Returns the list of widgets that have been using createWidget() and
241 are currently in use by widgets the action has been added to.
242*/
243QList<QWidget *> QWidgetAction::createdWidgets() const
244{
245 Q_D(const QWidgetAction);
246 return d->createdWidgets;
247}
248
249QT_END_NAMESPACE
250
251#include "moc_qwidgetaction.cpp"