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

Provided by KDAB

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

source code of qtbase/src/widgets/kernel/qwidgetaction.cpp