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
qgraphicsproxywidget.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
5#include "qglobal.h"
6
9#include "private/qgraphicsproxywidget_p.h"
10#include "private/qwidget_p.h"
11#include "private/qapplication_p.h"
12
13#include <QtCore/qdebug.h>
14#include <QtGui/qevent.h>
15#include <QtWidgets/qgraphicsscene.h>
16#include <QtWidgets/qgraphicssceneevent.h>
17#include <QtWidgets/qlayout.h>
18#include <QtGui/qpainter.h>
19#include <QtWidgets/qstyleoption.h>
20#include <QtWidgets/qgraphicsview.h>
21#if QT_CONFIG(lineedit)
22#include <QtWidgets/qlineedit.h>
23#endif
24#if QT_CONFIG(textedit)
25#include <QtWidgets/qtextedit.h>
26#endif
27
29
30//#define GRAPHICSPROXYWIDGET_DEBUG
31
32/*!
33 \class QGraphicsProxyWidget
34 \brief The QGraphicsProxyWidget class provides a proxy layer for embedding
35 a QWidget in a QGraphicsScene.
36 \since 4.4
37 \ingroup graphicsview-api
38 \inmodule QtWidgets
39
40 QGraphicsProxyWidget embeds QWidget-based widgets, for example, a
41 QPushButton, QFontComboBox, or even QFileDialog, into
42 QGraphicsScene. It forwards events between the two objects and
43 translates between QWidget's integer-based geometry and
44 QGraphicsWidget's qreal-based geometry. QGraphicsProxyWidget
45 supports all core features of QWidget, including tab focus,
46 keyboard input, Drag & Drop, and popups. You can also embed
47 complex widgets, e.g., widgets with subwidgets.
48
49 Example:
50
51 \snippet code/src_gui_graphicsview_qgraphicsproxywidget.cpp 0
52
53 QGraphicsProxyWidget takes care of automatically embedding popup children
54 of embedded widgets through creating a child proxy for each popup. This
55 means that when an embedded QComboBox shows its popup list, a new
56 QGraphicsProxyWidget is created automatically, embedding the popup, and
57 positioning it correctly. This only works if the popup is child of the
58 embedded widget (for example QToolButton::setMenu() requires the QMenu instance
59 to be child of the QToolButton).
60
61 \section1 Embedding a Widget with QGraphicsProxyWidget
62
63 There are two ways to embed a widget using QGraphicsProxyWidget. The most
64 common way is to pass a widget pointer to QGraphicsScene::addWidget()
65 together with any relevant \l Qt::WindowFlags. This function returns a
66 pointer to a QGraphicsProxyWidget. You can then choose to reparent or
67 position either the proxy, or the embedded widget itself.
68
69 For example, in the code snippet below, we embed a group box into the proxy:
70
71 \snippet code/src_gui_graphicsview_qgraphicsproxywidget.cpp 1
72
73 The image below is the output obtained with its contents margin and
74 contents rect labeled.
75
76 \image qgraphicsproxywidget-embed.png
77 {Proxy widget and its embedded widget with their positions}
78
79 Alternatively, you can start by creating a new QGraphicsProxyWidget item,
80 and then call setWidget() to embed a QWidget later. The widget() function
81 returns a pointer to the embedded widget. QGraphicsProxyWidget shares
82 ownership with QWidget, so if either of the two widgets are destroyed, the
83 other widget will be automatically destroyed as well.
84
85 \section1 Synchronizing Widget States
86
87 QGraphicsProxyWidget keeps its state in sync with the embedded widget. For
88 example, if the proxy is hidden or disabled, the embedded widget will be
89 hidden or disabled as well, and vice versa. When the widget is embedded by
90 calling addWidget(), QGraphicsProxyWidget copies the state from the widget
91 into the proxy, and after that, the two will stay synchronized where
92 possible. By default, when you embed a widget into a proxy, both the widget
93 and the proxy will be visible because a QGraphicsWidget is visible when
94 created (you do not have to call show()). If you explicitly hide the
95 embedded widget, the proxy will also become invisible.
96
97 Example:
98
99 \snippet code/src_gui_graphicsview_qgraphicsproxywidget.cpp 2
100
101 QGraphicsProxyWidget maintains symmetry for the following states:
102
103 \table
104 \header \li QWidget state \li QGraphicsProxyWidget state \li Notes
105 \row \li QWidget::enabled
106 \li QGraphicsProxyWidget::enabled
107 \li
108 \row \li QWidget::visible
109 \li QGraphicsProxyWidget::visible
110 \li The explicit state is also symmetric.
111 \row \li QWidget::geometry
112 \li QGraphicsProxyWidget::geometry
113 \li Geometry is only guaranteed to be symmetric while
114 the embedded widget is visible.
115 \row \li QWidget::layoutDirection
116 \li QGraphicsProxyWidget::layoutDirection
117 \li
118 \row \li QWidget::style
119 \li QGraphicsProxyWidget::style
120 \li
121 \row \li QWidget::palette
122 \li QGraphicsProxyWidget::palette
123 \li
124 \row \li QWidget::font
125 \li QGraphicsProxyWidget::font
126 \li
127 \row \li QWidget::cursor
128 \li QGraphicsProxyWidget::cursor
129 \li The embedded widget overrides the proxy widget
130 cursor. The proxy cursor changes depending on
131 which embedded subwidget is currently under the
132 mouse.
133 \row \li QWidget::sizeHint()
134 \li QGraphicsProxyWidget::sizeHint()
135 \li All size hint functionality from the embedded
136 widget is forwarded by the proxy.
137 \row \li QWidget::getContentsMargins()
138 \li QGraphicsProxyWidget::getContentsMargins()
139 \li Updated once by setWidget().
140 \row \li QWidget::windowTitle
141 \li QGraphicsProxyWidget::windowTitle
142 \li Updated once by setWidget().
143 \endtable
144
145 \note QGraphicsScene keeps the embedded widget in a special state that
146 prevents it from disturbing other widgets (both embedded and not embedded)
147 while the widget is embedded. In this state, the widget may differ slightly
148 in behavior from when it is not embedded.
149
150 \warning This class is provided for convenience when bridging
151 QWidgets and QGraphicsItems, it should not be used for
152 high-performance scenarios. In particular, embedding widgets into a scene
153 that is then displayed through a QGraphicsView that uses an OpenGL viewport
154 will not work for all combinations.
155
156 \sa QGraphicsScene::addWidget(), QGraphicsWidget
157*/
158
159extern bool qt_sendSpontaneousEvent(QObject *, QEvent *);
160Q_WIDGETS_EXPORT extern bool qt_tab_all_widgets();
161
162/*!
163 \internal
164*/
165QGraphicsProxyWidgetPrivate::QGraphicsProxyWidgetPrivate()
166 : QGraphicsWidgetPrivate(),
167 dragDropWidget(nullptr),
168 posChangeMode(NoMode),
169 sizeChangeMode(NoMode),
170 visibleChangeMode(NoMode),
171 enabledChangeMode(NoMode),
172 styleChangeMode(NoMode),
173 paletteChangeMode(NoMode),
174 tooltipChangeMode(NoMode),
175 focusFromWidgetToProxy(false),
176 proxyIsGivingFocus(false)
177{
178}
179
180/*!
181 \internal
182*/
183QGraphicsProxyWidgetPrivate::~QGraphicsProxyWidgetPrivate()
184{
185}
186
187/*!
188 \internal
189*/
190void QGraphicsProxyWidgetPrivate::init()
191{
192 Q_Q(QGraphicsProxyWidget);
193 q->setFocusPolicy(Qt::WheelFocus);
194 q->setAcceptDrops(true);
195}
196
197/*!
198 \internal
199*/
200void QGraphicsProxyWidgetPrivate::sendWidgetMouseEvent(QGraphicsSceneHoverEvent *event)
201{
202 QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseMove);
203 mouseEvent.setPos(event->pos());
204 mouseEvent.setScreenPos(event->screenPos());
205 mouseEvent.setButton(Qt::NoButton);
206 mouseEvent.setButtons({ });
207 mouseEvent.setModifiers(event->modifiers());
208 mouseEvent.setTimestamp(event->timestamp());
209 sendWidgetMouseEvent(&mouseEvent);
210 event->setAccepted(mouseEvent.isAccepted());
211}
212
213/*!
214 \internal
215*/
216void QGraphicsProxyWidgetPrivate::sendWidgetMouseEvent(QGraphicsSceneMouseEvent *event)
217{
218 if (!event || !widget || !widget->isVisible())
219 return;
220 Q_Q(QGraphicsProxyWidget);
221
222 // Find widget position and receiver.
223 QPointF pos = event->pos();
224 QPointer<QWidget> alienWidget = widget->childAt(pos.toPoint());
225 QPointer<QWidget> receiver = alienWidget ? alienWidget : widget;
226
227 if (QWidgetPrivate::nearestGraphicsProxyWidget(receiver) != q)
228 return; //another proxywidget will handle the events
229
230 // Translate QGraphicsSceneMouse events to QMouseEvents.
231 QEvent::Type type = QEvent::None;
232 switch (event->type()) {
233 case QEvent::GraphicsSceneMousePress:
234 type = QEvent::MouseButtonPress;
235 if (!embeddedMouseGrabber)
236 embeddedMouseGrabber = receiver;
237 else
238 receiver = embeddedMouseGrabber;
239 break;
240 case QEvent::GraphicsSceneMouseRelease:
241 type = QEvent::MouseButtonRelease;
242 if (embeddedMouseGrabber)
243 receiver = embeddedMouseGrabber;
244 break;
245 case QEvent::GraphicsSceneMouseDoubleClick:
246 type = QEvent::MouseButtonDblClick;
247 if (!embeddedMouseGrabber)
248 embeddedMouseGrabber = receiver;
249 else
250 receiver = embeddedMouseGrabber;
251 break;
252 case QEvent::GraphicsSceneMouseMove:
253 type = QEvent::MouseMove;
254 if (embeddedMouseGrabber)
255 receiver = embeddedMouseGrabber;
256 break;
257 default:
258 Q_ASSERT_X(false, "QGraphicsProxyWidget", "internal error");
259 break;
260 }
261
262 if (!lastWidgetUnderMouse) {
263 QApplicationPrivate::dispatchEnterLeave(embeddedMouseGrabber ? embeddedMouseGrabber : receiver, nullptr, event->screenPos());
264 lastWidgetUnderMouse = receiver;
265 }
266
267 // Map event position from us to the receiver
268 pos = mapToReceiver(pos, receiver);
269
270 // Send mouse event.
271 QMouseEvent mouseEvent(type, pos, receiver->mapTo(receiver->topLevelWidget(), pos.toPoint()),
272 receiver->mapToGlobal(pos.toPoint()),
273 event->button(), event->buttons(), event->modifiers(), event->source());
274 mouseEvent.setTimestamp(event->timestamp());
275
276 QWidget *embeddedMouseGrabberPtr = (QWidget *)embeddedMouseGrabber;
277 QApplicationPrivate::sendMouseEvent(receiver, &mouseEvent, alienWidget, widget,
278 &embeddedMouseGrabberPtr, lastWidgetUnderMouse, event->spontaneous());
279 embeddedMouseGrabber = embeddedMouseGrabberPtr;
280
281 // Handle enter/leave events when last button is released from mouse
282 // grabber child widget.
283 if (embeddedMouseGrabber && type == QEvent::MouseButtonRelease && !event->buttons()) {
284 Q_Q(QGraphicsProxyWidget);
285 if (q->rect().contains(event->pos()) && q->acceptHoverEvents())
286 lastWidgetUnderMouse = alienWidget ? alienWidget : widget;
287 else // released on the frame our outside the item, or doesn't accept hover events.
288 lastWidgetUnderMouse = nullptr;
289
290 QApplicationPrivate::dispatchEnterLeave(lastWidgetUnderMouse, embeddedMouseGrabber, event->screenPos());
291 embeddedMouseGrabber = nullptr;
292
293#ifndef QT_NO_CURSOR
294 // ### Restore the cursor, don't override it.
295 if (!lastWidgetUnderMouse)
296 q->unsetCursor();
297#endif
298 }
299
300#ifndef QT_NO_CURSOR
301 // Keep cursor in sync
302 if (lastWidgetUnderMouse) {
303 QCursor widgetsCursor = lastWidgetUnderMouse->cursor();
304 if (q->cursor() != widgetsCursor)
305 q->setCursor(widgetsCursor);
306 }
307#endif
308
309 event->setAccepted(mouseEvent.isAccepted());
310}
311
312void QGraphicsProxyWidgetPrivate::sendWidgetKeyEvent(QKeyEvent *event)
313{
314 Q_Q(QGraphicsProxyWidget);
315 if (!event || !widget || !widget->isVisible())
316 return;
317
318 QPointer<QWidget> receiver = widget->focusWidget();
319 if (!receiver)
320 receiver = widget;
321 Q_ASSERT(receiver);
322
323 do {
324 bool res = QCoreApplication::sendEvent(receiver, event);
325 if ((res && event->isAccepted()) || (q->isWindow() && receiver == widget))
326 break;
327 receiver = receiver->parentWidget();
328 } while (receiver);
329}
330
331/*!
332 \internal
333*/
334void QGraphicsProxyWidgetPrivate::removeSubFocusHelper(QWidget *widget, Qt::FocusReason reason)
335{
336 QFocusEvent event(QEvent::FocusOut, reason);
337 QPointer<QWidget> widgetGuard = widget;
338 QCoreApplication::sendEvent(widget, &event);
339 if (widgetGuard && event.isAccepted())
340 QCoreApplication::sendEvent(widget->style(), &event);
341}
342
343/*!
344 \internal
345 Some of the logic is shared with QApplicationPrivate::focusNextPrevChild_helper
346*/
347QWidget *QGraphicsProxyWidgetPrivate::findFocusChild(QWidget *child, bool next) const
348{
349 if (!widget)
350 return nullptr;
351
352 // Run around the focus chain until we find a widget that can take tab focus.
353 if (!child) {
354 child = next ? widget.data() : widget->previousInFocusChain();
355 } else {
356 child = next ? child->nextInFocusChain() : child->previousInFocusChain();
357 if ((next && child == widget) || (!next && child == widget->previousInFocusChain())) {
358 return nullptr;
359 }
360 }
361
362 if (!child)
363 return nullptr;
364
365 QWidget *oldChild = child;
366 uint focus_flag = qt_tab_all_widgets() ? Qt::TabFocus : Qt::StrongFocus;
367 do {
368 if (child->isEnabled()
369 && child->isVisibleTo(widget)
370 && ((child->focusPolicy() & focus_flag) == focus_flag)
371 && !(child->d_func()->extra && child->d_func()->extra->focus_proxy)) {
372 return child;
373 }
374 child = next ? child->nextInFocusChain() : child->previousInFocusChain();
375 } while (child != oldChild && !(next && child == widget) && !(!next && child == widget->previousInFocusChain()));
376 return nullptr;
377}
378
379/*!
380 \internal
381*/
382void QGraphicsProxyWidgetPrivate::_q_removeWidgetSlot()
383{
384 Q_Q(QGraphicsProxyWidget);
385 if (!widget.isNull()) {
386 if (const auto &extra = widget->d_func()->extra)
387 extra->proxyWidget = nullptr;
388 }
389 widget = nullptr;
390 delete q;
391}
392
393/*!
394 \internal
395*/
396void QGraphicsProxyWidgetPrivate::updateWidgetGeometryFromProxy()
397{
398}
399
400/*!
401 \internal
402*/
403void QGraphicsProxyWidgetPrivate::updateProxyGeometryFromWidget()
404{
405 Q_Q(QGraphicsProxyWidget);
406 if (!widget)
407 return;
408
409 QRectF widgetGeometry = widget->geometry();
410 QWidget *parentWidget = widget->parentWidget();
411 if (widget->isWindow()) {
412 QGraphicsProxyWidget *proxyParent = nullptr;
413 if (parentWidget && (proxyParent = qobject_cast<QGraphicsProxyWidget *>(q->parentWidget()))) {
414 // Nested window proxy (e.g., combobox popup), map widget to the
415 // parent widget's global coordinates, and map that to the parent
416 // proxy's child coordinates.
417 widgetGeometry.moveTo(proxyParent->subWidgetRect(parentWidget).topLeft()
418 + parentWidget->mapFromGlobal(widget->pos()));
419 }
420 }
421
422 // Adjust to size hint if the widget has never been resized.
423 if (!widget->size().isValid())
424 widgetGeometry.setSize(widget->sizeHint());
425
426 // Assign new geometry.
427 posChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
428 sizeChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
429 q->setGeometry(widgetGeometry);
430 posChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
431 sizeChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
432}
433
434/*!
435 \internal
436*/
437void QGraphicsProxyWidgetPrivate::updateProxyInputMethodAcceptanceFromWidget()
438{
439 Q_Q(QGraphicsProxyWidget);
440 if (!widget)
441 return;
442
443 QWidget *focusWidget = widget->focusWidget();
444 if (!focusWidget)
445 focusWidget = widget;
446 q->setFlag(QGraphicsItem::ItemAcceptsInputMethod,
447 focusWidget->testAttribute(Qt::WA_InputMethodEnabled));
448}
449
450/*!
451 \internal
452
453 Embeds \a subWin as a subwindow of this proxy widget. \a subWin must be a top-level
454 widget and a descendant of the widget managed by this proxy. A separate subproxy
455 will be created as a child of this proxy widget to manage \a subWin.
456*/
457void QGraphicsProxyWidgetPrivate::embedSubWindow(QWidget *subWin)
458{
459 const auto &extra = subWin->d_func()->extra;
460 if (!extra || !extra->proxyWidget) {
461 QGraphicsProxyWidget *subProxy = new QGraphicsProxyWidget(q_func(), subWin->windowFlags());
462 subProxy->d_func()->setWidget_helper(subWin, false);
463 }
464}
465
466/*!
467 \internal
468
469 Removes ("unembeds") \a subWin and deletes the proxy holder item. This can
470 happen when QWidget::setParent() reparents the embedded window out of
471 "embedded space".
472*/
473void QGraphicsProxyWidgetPrivate::unembedSubWindow(QWidget *subWin)
474{
475 for (QGraphicsItem *child : std::as_const(children)) {
476 if (child->isWidget()) {
477 if (QGraphicsProxyWidget *proxy = qobject_cast<QGraphicsProxyWidget *>(static_cast<QGraphicsWidget *>(child))) {
478 if (proxy->widget() == subWin) {
479 proxy->setWidget(nullptr);
480 scene->removeItem(proxy);
481 delete proxy;
482 return;
483 }
484 }
485 }
486 }
487}
488
489bool QGraphicsProxyWidgetPrivate::isProxyWidget() const
490{
491 return true;
492}
493
494/*!
495 \internal
496*/
497QPointF QGraphicsProxyWidgetPrivate::mapToReceiver(const QPointF &pos, const QWidget *receiver) const
498{
499 QPointF p = pos;
500 // Map event position from us to the receiver, preserving its
501 // precision (don't use QWidget::mapFrom here).
502 while (receiver && receiver != widget) {
503 p -= QPointF(receiver->pos());
504 receiver = receiver->parentWidget();
505 }
506 return p;
507}
508
509/*!
510 Constructs a new QGraphicsProxy widget. \a parent and \a wFlags are passed
511 to QGraphicsItem's constructor.
512*/
513QGraphicsProxyWidget::QGraphicsProxyWidget(QGraphicsItem *parent, Qt::WindowFlags wFlags)
514 : QGraphicsWidget(*new QGraphicsProxyWidgetPrivate, parent, wFlags)
515{
516 Q_D(QGraphicsProxyWidget);
517 d->init();
518}
519
520/*!
521 Destroys the proxy widget and any embedded widget.
522*/
523QGraphicsProxyWidget::~QGraphicsProxyWidget()
524{
525 Q_D(QGraphicsProxyWidget);
526 if (d->widget) {
527 d->widget->removeEventFilter(this);
528 QObject::disconnect(d->widget, SIGNAL(destroyed()), this, SLOT(_q_removeWidgetSlot()));
529 delete d->widget;
530 }
531}
532
533/*!
534 Embeds \a widget into this proxy widget. The embedded widget must reside
535 exclusively either inside or outside of Graphics View. You cannot embed a
536 widget as long as it is visible elsewhere in the UI, at the same time.
537
538 \a widget must be a top-level widget whose parent is \nullptr.
539
540 When the widget is embedded, its state (e.g., visible, enabled, geometry,
541 size hints) is copied into the proxy widget. If the embedded widget is
542 explicitly hidden or disabled, the proxy widget will become explicitly
543 hidden or disabled after embedding is complete. The class documentation
544 has a full overview over the shared state.
545
546 QGraphicsProxyWidget's window flags determine whether the widget, after
547 embedding, will be given window decorations or not.
548
549 After this function returns, QGraphicsProxyWidget will keep its state
550 synchronized with that of \a widget whenever possible.
551
552 If a widget is already embedded by this proxy when this function is called,
553 that widget will first be automatically unembedded. Passing \nullptr for
554 the \a widget argument will only unembed the widget, and the ownership of
555 the currently embedded widget will be passed on to the caller.
556 Every child widget that are embedded will also be embedded and their proxy
557 widget destroyed.
558
559 Note that widgets with the Qt::WA_PaintOnScreen widget attribute
560 set and widgets that wrap an external application or controller
561 cannot be embedded. Examples are QOpenGLWidget and QAxWidget.
562
563 \sa widget()
564*/
565void QGraphicsProxyWidget::setWidget(QWidget *widget)
566{
567 Q_D(QGraphicsProxyWidget);
568 d->setWidget_helper(widget, true);
569}
570
571void QGraphicsProxyWidgetPrivate::setWidget_helper(QWidget *newWidget, bool autoShow)
572{
573 Q_Q(QGraphicsProxyWidget);
574 if (newWidget == widget)
575 return;
576 if (widget) {
577 QObject::disconnect(widget, SIGNAL(destroyed()), q, SLOT(_q_removeWidgetSlot()));
578 widget->removeEventFilter(q);
579 widget->setAttribute(Qt::WA_DontShowOnScreen, false);
580 widget->d_func()->extra->proxyWidget = nullptr;
581 resolveFont(inheritedFontResolveMask);
582 resolvePalette(inheritedPaletteResolveMask);
583 widget->update();
584
585 const auto childItems = q->childItems();
586 for (QGraphicsItem *child : childItems) {
587 if (child->d_ptr->isProxyWidget()) {
588 QGraphicsProxyWidget *childProxy = static_cast<QGraphicsProxyWidget *>(child);
589 QWidget *parent = childProxy->widget();
590 while (parent && parent->parentWidget()) {
591 if (parent == widget)
592 break;
593 parent = parent->parentWidget();
594 }
595 if (!childProxy->widget() || parent != widget)
596 continue;
597 childProxy->setWidget(nullptr);
598 delete childProxy;
599 }
600 }
601
602 widget = nullptr;
603#ifndef QT_NO_CURSOR
604 q->unsetCursor();
605#endif
606 q->setAcceptHoverEvents(false);
607 if (!newWidget)
608 q->update();
609 }
610 if (!newWidget)
611 return;
612 if (!newWidget->isWindow()) {
613 const auto &extra = newWidget->parentWidget()->d_func()->extra;
614 if (!extra || !extra->proxyWidget) {
615 qWarning("QGraphicsProxyWidget::setWidget: cannot embed widget %p "
616 "which is not a toplevel widget, and is not a child of an embedded widget", newWidget);
617 return;
618 }
619 }
620
621 // Register this proxy within the widget's private.
622 // ### This is a bit backdoorish
623 QWExtra *extra = newWidget->d_func()->extra.get();
624 if (!extra) {
625 newWidget->d_func()->createExtra();
626 extra = newWidget->d_func()->extra.get();
627 }
628 QGraphicsProxyWidget **proxyWidget = &extra->proxyWidget;
629 if (*proxyWidget) {
630 if (*proxyWidget != q) {
631 qWarning("QGraphicsProxyWidget::setWidget: cannot embed widget %p"
632 "; already embedded", newWidget);
633 }
634 return;
635 }
636 *proxyWidget = q;
637
638 newWidget->setAttribute(Qt::WA_DontShowOnScreen);
639 newWidget->ensurePolished();
640 // Do not wait for this widget to close before the app closes ###
641 // shouldn't this widget inherit the attribute?
642 newWidget->setAttribute(Qt::WA_QuitOnClose, false);
643 q->setAcceptHoverEvents(true);
644
645 if (newWidget->testAttribute(Qt::WA_NoSystemBackground))
646 q->setAttribute(Qt::WA_NoSystemBackground);
647 if (newWidget->testAttribute(Qt::WA_OpaquePaintEvent))
648 q->setAttribute(Qt::WA_OpaquePaintEvent);
649
650 widget = newWidget;
651
652 // Changes only go from the widget to the proxy.
653 enabledChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
654 visibleChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
655 posChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
656 sizeChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
657
658 if ((autoShow && !newWidget->testAttribute(Qt::WA_WState_ExplicitShowHide)) || !newWidget->testAttribute(Qt::WA_WState_Hidden)) {
659 newWidget->show();
660 }
661
662 // Copy the state from the widget onto the proxy.
663#ifndef QT_NO_CURSOR
664 if (newWidget->testAttribute(Qt::WA_SetCursor))
665 q->setCursor(widget->cursor());
666#endif
667 q->setEnabled(newWidget->isEnabled());
668 q->setVisible(newWidget->isVisible());
669 q->setLayoutDirection(newWidget->layoutDirection());
670 if (newWidget->testAttribute(Qt::WA_SetStyle))
671 q->setStyle(widget->style());
672
673 resolveFont(inheritedFontResolveMask);
674 resolvePalette(inheritedPaletteResolveMask);
675
676 if (!newWidget->testAttribute(Qt::WA_Resized))
677 newWidget->adjustSize();
678
679 q->setContentsMargins(newWidget->contentsMargins());
680 q->setWindowTitle(newWidget->windowTitle());
681
682 // size policies and constraints..
683 q->setSizePolicy(newWidget->sizePolicy());
684 QSize sz = newWidget->minimumSize();
685 q->setMinimumSize(sz.isNull() ? QSizeF() : QSizeF(sz));
686 sz = newWidget->maximumSize();
687 q->setMaximumSize(sz.isNull() ? QSizeF() : QSizeF(sz));
688
689 updateProxyGeometryFromWidget();
690
691 updateProxyInputMethodAcceptanceFromWidget();
692
693 // Hook up the event filter to keep the state up to date.
694 newWidget->installEventFilter(q);
695 QObject::connect(newWidget, SIGNAL(destroyed()), q, SLOT(_q_removeWidgetSlot()));
696
697 // Changes no longer go only from the widget to the proxy.
698 enabledChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
699 visibleChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
700 posChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
701 sizeChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
702}
703
704/*!
705 Returns a pointer to the embedded widget.
706
707 \sa setWidget()
708*/
709QWidget *QGraphicsProxyWidget::widget() const
710{
711 Q_D(const QGraphicsProxyWidget);
712 return d->widget;
713}
714
715/*!
716 Returns the rectangle for \a widget, which must be a descendant of
717 widget(), or widget() itself, in this proxy item's local coordinates.
718
719 If no widget is embedded, \a widget is \nullptr, or \a widget is not a
720 descendant of the embedded widget, this function returns an empty QRectF.
721
722 \sa widget()
723*/
724QRectF QGraphicsProxyWidget::subWidgetRect(const QWidget *widget) const
725{
726 Q_D(const QGraphicsProxyWidget);
727 if (!widget || !d->widget)
728 return QRectF();
729 if (d->widget == widget || d->widget->isAncestorOf(widget))
730 return QRectF(widget->mapTo(d->widget, QPoint(0, 0)), widget->size());
731 return QRectF();
732}
733
734/*!
735 \reimp
736*/
737void QGraphicsProxyWidget::setGeometry(const QRectF &rect)
738{
739 Q_D(QGraphicsProxyWidget);
740 bool proxyResizesWidget = !d->posChangeMode && !d->sizeChangeMode;
741 if (proxyResizesWidget) {
742 d->posChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode;
743 d->sizeChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode;
744 }
745 QGraphicsWidget::setGeometry(rect);
746 if (proxyResizesWidget) {
747 d->posChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
748 d->sizeChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
749 }
750}
751
752/*!
753 \reimp
754*/
755QVariant QGraphicsProxyWidget::itemChange(GraphicsItemChange change,
756 const QVariant &value)
757{
758 Q_D(QGraphicsProxyWidget);
759
760 switch (change) {
761 case ItemPositionChange:
762 // The item's position is either changed directly on the proxy, in
763 // which case the position change should propagate to the widget,
764 // otherwise it happens as a side effect when filtering QEvent::Move.
765 if (!d->posChangeMode)
766 d->posChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode;
767 break;
768 case ItemPositionHasChanged:
769 // Move the internal widget if we're in widget-to-proxy
770 // mode. Otherwise the widget has already moved.
771 if (d->widget && d->posChangeMode != QGraphicsProxyWidgetPrivate::WidgetToProxyMode)
772 d->widget->move(value.toPoint());
773 if (d->posChangeMode == QGraphicsProxyWidgetPrivate::ProxyToWidgetMode)
774 d->posChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
775 break;
776 case ItemVisibleChange:
777 if (!d->visibleChangeMode)
778 d->visibleChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode;
779 break;
780 case ItemVisibleHasChanged:
781 if (d->widget && d->visibleChangeMode != QGraphicsProxyWidgetPrivate::WidgetToProxyMode)
782 d->widget->setVisible(isVisible());
783 if (d->visibleChangeMode == QGraphicsProxyWidgetPrivate::ProxyToWidgetMode)
784 d->visibleChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
785 break;
786 case ItemEnabledChange:
787 if (!d->enabledChangeMode)
788 d->enabledChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode;
789 break;
790 case ItemEnabledHasChanged:
791 if (d->widget && d->enabledChangeMode != QGraphicsProxyWidgetPrivate::WidgetToProxyMode)
792 d->widget->setEnabled(isEnabled());
793 if (d->enabledChangeMode == QGraphicsProxyWidgetPrivate::ProxyToWidgetMode)
794 d->enabledChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
795 break;
796 default:
797 break;
798 }
799 return QGraphicsWidget::itemChange(change, value);
800}
801
802/*!
803 \reimp
804*/
805bool QGraphicsProxyWidget::event(QEvent *event)
806{
807 Q_D(QGraphicsProxyWidget);
808 if (!d->widget)
809 return QGraphicsWidget::event(event);
810
811 switch (event->type()) {
812 case QEvent::WindowActivate:
813 case QEvent::WindowDeactivate:
814 QCoreApplication::sendEvent(d->widget, event);
815 break;
816 case QEvent::StyleChange:
817 // Propagate style changes to the embedded widget.
818 if (!d->styleChangeMode) {
819 d->styleChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode;
820 d->widget->setStyle(style());
821 d->styleChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
822 }
823 break;
824 case QEvent::FontChange: {
825 // Propagate to widget.
826 QWidgetPrivate *wd = d->widget->d_func();
827 int mask = d->font.resolveMask() | d->inheritedFontResolveMask;
828 wd->inheritedFontResolveMask = mask;
829 wd->resolveFont();
830 break;
831 }
832 case QEvent::PaletteChange: {
833 // Propagate to widget.
834 QWidgetPrivate *wd = d->widget->d_func();
835 int mask = d->palette.resolveMask() | d->inheritedPaletteResolveMask;
836 wd->inheritedPaletteResolveMask = mask;
837 wd->resolvePalette();
838 break;
839 }
840 case QEvent::InputMethod: {
841 inputMethodEvent(static_cast<QInputMethodEvent *>(event));
842 if (event->isAccepted())
843 return true;
844 return false;
845 }
846 case QEvent::ShortcutOverride: {
847 QWidget *focusWidget = d->widget->focusWidget();
848 while (focusWidget) {
849 QCoreApplication::sendEvent(focusWidget, event);
850 if (event->isAccepted())
851 return true;
852 focusWidget = focusWidget->parentWidget();
853 }
854 return false;
855 }
856 case QEvent::KeyPress: {
857 QKeyEvent *k = static_cast<QKeyEvent *>(event);
858 if (k->key() == Qt::Key_Tab || k->key() == Qt::Key_Backtab) {
859 if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) { //### Add MetaModifier?
860 QWidget *focusWidget = d->widget->focusWidget();
861 while (focusWidget) {
862 const bool res = QCoreApplication::sendEvent(focusWidget, event);
863 if ((res && event->isAccepted()) || (isWindow() && focusWidget == d->widget)) {
864 event->accept();
865 break;
866 }
867 focusWidget = focusWidget->parentWidget();
868 }
869 return true;
870 }
871 }
872 break;
873 }
874#if QT_CONFIG(tooltip)
875 case QEvent::GraphicsSceneHelp: {
876 // Propagate the help event (for tooltip) to the widget under mouse
877 if (d->lastWidgetUnderMouse) {
878 QGraphicsSceneHelpEvent *he = static_cast<QGraphicsSceneHelpEvent *>(event);
879 QPoint pos = d->mapToReceiver(mapFromScene(he->scenePos()), d->lastWidgetUnderMouse).toPoint();
880 QHelpEvent e(QEvent::ToolTip, pos, he->screenPos());
881 QCoreApplication::sendEvent(d->lastWidgetUnderMouse, &e);
882 event->setAccepted(e.isAccepted());
883 return e.isAccepted();
884 }
885 break;
886 }
887 case QEvent::ToolTipChange: {
888 // Propagate tooltip change to the widget
889 if (!d->tooltipChangeMode) {
890 d->tooltipChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode;
891 d->widget->setToolTip(toolTip());
892 d->tooltipChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
893 }
894 break;
895 }
896#endif
897 case QEvent::TouchBegin:
898 case QEvent::TouchUpdate:
899 case QEvent::TouchEnd: {
900 QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event);
901 bool res = QApplicationPrivate::translateRawTouchEvent(d->widget, touchEvent);
902 if (res & touchEvent->isAccepted())
903 return true;
904
905 break;
906 }
907 default:
908 break;
909 }
910 return QGraphicsWidget::event(event);
911}
912
913/*!
914 \reimp
915*/
916bool QGraphicsProxyWidget::eventFilter(QObject *object, QEvent *event)
917{
918 Q_D(QGraphicsProxyWidget);
919
920 if (object == d->widget) {
921 switch (event->type()) {
922 case QEvent::LayoutRequest:
923 updateGeometry();
924 break;
925 case QEvent::Resize:
926 // If the widget resizes itself, we resize the proxy too.
927 // Prevent feed-back by checking the geometry change mode.
928 if (!d->sizeChangeMode)
929 d->updateProxyGeometryFromWidget();
930 break;
931 case QEvent::Move:
932 // If the widget moves itself, we move the proxy too. Prevent
933 // feed-back by checking the geometry change mode.
934 if (!d->posChangeMode)
935 d->updateProxyGeometryFromWidget();
936 break;
937 case QEvent::Hide:
938 case QEvent::Show:
939 // If the widget toggles its visible state, the proxy will follow.
940 if (!d->visibleChangeMode) {
941 d->visibleChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
942 setVisible(event->type() == QEvent::Show);
943 d->visibleChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
944 }
945 break;
946 case QEvent::EnabledChange:
947 // If the widget toggles its enabled state, the proxy will follow.
948 if (!d->enabledChangeMode) {
949 d->enabledChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
950 setEnabled(d->widget->isEnabled());
951 d->enabledChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
952 }
953 break;
954 case QEvent::StyleChange:
955 // Propagate style changes to the proxy.
956 if (!d->styleChangeMode) {
957 d->styleChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
958 setStyle(d->widget->style());
959 d->styleChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
960 }
961 break;
962#if QT_CONFIG(tooltip)
963 case QEvent::ToolTipChange:
964 // Propagate tooltip change to the proxy.
965 if (!d->tooltipChangeMode) {
966 d->tooltipChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
967 setToolTip(d->widget->toolTip());
968 d->tooltipChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
969 }
970 break;
971#endif
972 default:
973 break;
974 }
975 }
976 return QGraphicsWidget::eventFilter(object, event);
977}
978
979/*!
980 \reimp
981*/
982void QGraphicsProxyWidget::showEvent(QShowEvent *event)
983{
984 Q_UNUSED(event);
985}
986
987/*!
988 \reimp
989*/
990void QGraphicsProxyWidget::hideEvent(QHideEvent *event)
991{
992 Q_UNUSED(event);
993}
994
995#ifndef QT_NO_CONTEXTMENU
996/*!
997 \reimp
998*/
999void QGraphicsProxyWidget::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
1000{
1001 Q_D(QGraphicsProxyWidget);
1002 if (!event || !d->widget || !d->widget->isVisible() || !hasFocus())
1003 return;
1004
1005 // Find widget position and receiver.
1006 QPointF pos = event->pos();
1007 QPointer<QWidget> alienWidget = d->widget->childAt(pos.toPoint());
1008 QPointer<QWidget> receiver = alienWidget ? alienWidget : d->widget;
1009
1010 // Map event position from us to the receiver
1011 pos = d->mapToReceiver(pos, receiver);
1012
1013 QPoint globalPos = receiver->mapToGlobal(pos.toPoint());
1014 //If the receiver by-pass the proxy its popups
1015 //will be top level QWidgets therefore they need
1016 //the screen position. mapToGlobal expect the widget to
1017 //have proper coordinates in regards of the windowing system
1018 //but it's not true because the widget is embedded.
1019 if (bypassGraphicsProxyWidget(receiver))
1020 globalPos = event->screenPos();
1021
1022 // Send mouse event. ### Doesn't propagate the event.
1023 QContextMenuEvent contextMenuEvent(QContextMenuEvent::Reason(event->reason()),
1024 pos.toPoint(), globalPos, event->modifiers());
1025 contextMenuEvent.setTimestamp(event->timestamp());
1026 QCoreApplication::sendEvent(receiver, &contextMenuEvent);
1027
1028 event->setAccepted(contextMenuEvent.isAccepted());
1029}
1030#endif // QT_NO_CONTEXTMENU
1031
1032#if QT_CONFIG(draganddrop)
1033/*!
1034 \reimp
1035*/
1036void QGraphicsProxyWidget::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
1037{
1038#if !QT_CONFIG(draganddrop)
1039 Q_UNUSED(event);
1040#else
1041 Q_D(QGraphicsProxyWidget);
1042 if (!d->widget)
1043 return;
1044
1045 QDragEnterEvent proxyDragEnter(event->pos().toPoint(), event->dropAction(), event->mimeData(), event->buttons(), event->modifiers());
1046 proxyDragEnter.setAccepted(event->isAccepted());
1047 QCoreApplication::sendEvent(d->widget, &proxyDragEnter);
1048 event->setAccepted(proxyDragEnter.isAccepted());
1049 if (proxyDragEnter.isAccepted()) // we discard answerRect
1050 event->setDropAction(proxyDragEnter.dropAction());
1051#endif
1052}
1053/*!
1054 \reimp
1055*/
1056void QGraphicsProxyWidget::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
1057{
1058 Q_UNUSED(event);
1059#if QT_CONFIG(draganddrop)
1060 Q_D(QGraphicsProxyWidget);
1061 if (!d->widget || !d->dragDropWidget)
1062 return;
1063 QDragLeaveEvent proxyDragLeave;
1064 QCoreApplication::sendEvent(d->dragDropWidget, &proxyDragLeave);
1065 d->dragDropWidget = nullptr;
1066#endif
1067}
1068
1069/*!
1070 \reimp
1071*/
1072void QGraphicsProxyWidget::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
1073{
1074#if !QT_CONFIG(draganddrop)
1075 Q_UNUSED(event);
1076#else
1077 Q_D(QGraphicsProxyWidget);
1078 if (!d->widget)
1079 return;
1080 QPointF p = event->pos();
1081 event->ignore();
1082 QPointer<QWidget> subWidget = d->widget->childAt(p.toPoint());
1083 QPointer<QWidget> receiver = subWidget ? subWidget : d->widget;
1084 bool eventDelivered = false;
1085 for (; receiver; receiver = receiver->parentWidget()) {
1086 if (!receiver->isEnabled() || !receiver->acceptDrops())
1087 continue;
1088 // Map event position from us to the receiver
1089 QPoint receiverPos = d->mapToReceiver(p, receiver).toPoint();
1090 if (receiver != d->dragDropWidget) {
1091 // Try to enter before we leave
1092 QDragEnterEvent dragEnter(receiverPos, event->possibleActions(), event->mimeData(), event->buttons(), event->modifiers());
1093 dragEnter.setDropAction(event->proposedAction());
1094 QCoreApplication::sendEvent(receiver, &dragEnter);
1095 event->setAccepted(dragEnter.isAccepted());
1096 event->setDropAction(dragEnter.dropAction());
1097 if (!event->isAccepted()) {
1098 // propagate to the parent widget
1099 continue;
1100 }
1101
1102 d->lastDropAction = event->dropAction();
1103
1104 if (d->dragDropWidget) {
1105 QDragLeaveEvent dragLeave;
1106 QCoreApplication::sendEvent(d->dragDropWidget, &dragLeave);
1107 }
1108 d->dragDropWidget = receiver;
1109 }
1110
1111 QDragMoveEvent dragMove(receiverPos, event->possibleActions(), event->mimeData(), event->buttons(), event->modifiers());
1112 event->setDropAction(d->lastDropAction);
1113 QCoreApplication::sendEvent(receiver, &dragMove);
1114 event->setAccepted(dragMove.isAccepted());
1115 event->setDropAction(dragMove.dropAction());
1116 if (event->isAccepted())
1117 d->lastDropAction = event->dropAction();
1118 eventDelivered = true;
1119 break;
1120 }
1121
1122 if (!eventDelivered) {
1123 if (d->dragDropWidget) {
1124 // Leave the last drag drop item
1125 QDragLeaveEvent dragLeave;
1126 QCoreApplication::sendEvent(d->dragDropWidget, &dragLeave);
1127 d->dragDropWidget = nullptr;
1128 }
1129 // Propagate
1130 event->setDropAction(Qt::IgnoreAction);
1131 }
1132#endif
1133}
1134
1135/*!
1136 \reimp
1137*/
1138void QGraphicsProxyWidget::dropEvent(QGraphicsSceneDragDropEvent *event)
1139{
1140#if !QT_CONFIG(draganddrop)
1141 Q_UNUSED(event);
1142#else
1143 Q_D(QGraphicsProxyWidget);
1144 if (d->widget && d->dragDropWidget) {
1145 QPoint widgetPos = d->mapToReceiver(event->pos(), d->dragDropWidget).toPoint();
1146 QDropEvent dropEvent(widgetPos, event->possibleActions(), event->mimeData(), event->buttons(), event->modifiers());
1147 QCoreApplication::sendEvent(d->dragDropWidget, &dropEvent);
1148 event->setAccepted(dropEvent.isAccepted());
1149 d->dragDropWidget = nullptr;
1150 }
1151#endif
1152}
1153#endif
1154
1155/*!
1156 \reimp
1157*/
1158void QGraphicsProxyWidget::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
1159{
1160 Q_UNUSED(event);
1161}
1162
1163/*!
1164 \reimp
1165*/
1166void QGraphicsProxyWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
1167{
1168 Q_UNUSED(event);
1169 Q_D(QGraphicsProxyWidget);
1170 // If hoverMove was compressed away, make sure we update properly here.
1171 if (d->lastWidgetUnderMouse) {
1172 QApplicationPrivate::dispatchEnterLeave(nullptr, d->lastWidgetUnderMouse, event->screenPos());
1173 d->lastWidgetUnderMouse = nullptr;
1174 }
1175}
1176
1177/*!
1178 \reimp
1179*/
1180void QGraphicsProxyWidget::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
1181{
1182 Q_D(QGraphicsProxyWidget);
1183#ifdef GRAPHICSPROXYWIDGET_DEBUG
1184 qDebug("QGraphicsProxyWidget::hoverMoveEvent");
1185#endif
1186 // Ignore events on the window frame.
1187 if (!d->widget || !rect().contains(event->pos())) {
1188 if (d->lastWidgetUnderMouse) {
1189 QApplicationPrivate::dispatchEnterLeave(nullptr, d->lastWidgetUnderMouse, event->screenPos());
1190 d->lastWidgetUnderMouse = nullptr;
1191 }
1192 return;
1193 }
1194
1195 d->embeddedMouseGrabber = nullptr;
1196 d->sendWidgetMouseEvent(event);
1197}
1198
1199/*!
1200 \reimp
1201*/
1202void QGraphicsProxyWidget::grabMouseEvent(QEvent *event)
1203{
1204 Q_UNUSED(event);
1205}
1206
1207/*!
1208 \reimp
1209*/
1210void QGraphicsProxyWidget::ungrabMouseEvent(QEvent *event)
1211{
1212 Q_D(QGraphicsProxyWidget);
1213 Q_UNUSED(event);
1214 d->embeddedMouseGrabber = nullptr;
1215}
1216
1217/*!
1218 \reimp
1219*/
1220void QGraphicsProxyWidget::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
1221{
1222 Q_D(QGraphicsProxyWidget);
1223#ifdef GRAPHICSPROXYWIDGET_DEBUG
1224 qDebug("QGraphicsProxyWidget::mouseMoveEvent");
1225#endif
1226 d->sendWidgetMouseEvent(event);
1227}
1228
1229/*!
1230 \reimp
1231*/
1232void QGraphicsProxyWidget::mousePressEvent(QGraphicsSceneMouseEvent *event)
1233{
1234 Q_D(QGraphicsProxyWidget);
1235#ifdef GRAPHICSPROXYWIDGET_DEBUG
1236 qDebug("QGraphicsProxyWidget::mousePressEvent");
1237#endif
1238 d->sendWidgetMouseEvent(event);
1239}
1240
1241/*!
1242 \reimp
1243*/
1244void QGraphicsProxyWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
1245{
1246 Q_D(QGraphicsProxyWidget);
1247#ifdef GRAPHICSPROXYWIDGET_DEBUG
1248 qDebug("QGraphicsProxyWidget::mouseDoubleClickEvent");
1249#endif
1250 d->sendWidgetMouseEvent(event);
1251}
1252
1253/*!
1254 \reimp
1255*/
1256#if QT_CONFIG(wheelevent)
1257void QGraphicsProxyWidget::wheelEvent(QGraphicsSceneWheelEvent *event)
1258{
1259 Q_D(QGraphicsProxyWidget);
1260#ifdef GRAPHICSPROXYWIDGET_DEBUG
1261 qDebug("QGraphicsProxyWidget::wheelEvent");
1262#endif
1263 if (!d->widget)
1264 return;
1265
1266 QPointF pos = event->pos();
1267 QPointer<QWidget> receiver = d->widget->childAt(pos.toPoint());
1268 if (!receiver)
1269 receiver = d->widget;
1270
1271 // high precision event streams go to the grabber, which will be the
1272 // QGraphicsView's viewport. We need to change that temporarily, otherwise
1273 // the event we send to the receiver get grabbed by the viewport, resulting
1274 // in infinite recursion
1275 QPointer<QWidget> prev_grabber = QApplicationPrivate::wheel_widget;
1276 if (event->phase() == Qt::ScrollBegin) {
1277 QApplicationPrivate::wheel_widget = receiver;
1278 } else if (event->phase() != Qt::NoScrollPhase && QApplicationPrivate::wheel_widget != receiver) {
1279 // this event is part of a stream that didn't start here, so ignore
1280 event->ignore();
1281 return;
1282 }
1283
1284 // Map event position from us to the receiver
1285 pos = d->mapToReceiver(pos, receiver);
1286
1287 // Send mouse event.
1288 QPoint angleDelta;
1289 if (event->orientation() == Qt::Horizontal)
1290 angleDelta.setX(event->delta());
1291 else
1292 angleDelta.setY(event->delta());
1293 // pixelDelta, inverted, scrollPhase and source from the original QWheelEvent
1294 // were not preserved in the QGraphicsSceneWheelEvent unfortunately
1295 QWheelEvent wheelEvent(pos, event->screenPos(), event->pixelDelta(), angleDelta,
1296 event->buttons(), event->modifiers(), event->phase(),
1297 event->isInverted(), Qt::MouseEventSynthesizedByQt,
1298 QPointingDevice::primaryPointingDevice());
1299 QPointer<QWidget> focusWidget = d->widget->focusWidget();
1300 extern bool qt_sendSpontaneousEvent(QObject *, QEvent *);
1301 qt_sendSpontaneousEvent(receiver, &wheelEvent);
1302 event->setAccepted(wheelEvent.isAccepted());
1303
1304 if (event->phase() == Qt::ScrollBegin) {
1305 // reset the wheel grabber if the event wasn't accepted
1306 if (!wheelEvent.isAccepted())
1307 QApplicationPrivate::wheel_widget = prev_grabber;
1308 }
1309
1310 // ### Remove, this should be done by proper focusIn/focusOut events.
1311 if (focusWidget && !focusWidget->hasFocus()) {
1312 focusWidget->update();
1313 focusWidget = d->widget->focusWidget();
1314 if (focusWidget && focusWidget->hasFocus())
1315 focusWidget->update();
1316 }
1317}
1318#endif
1319
1320/*!
1321 \reimp
1322*/
1323void QGraphicsProxyWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
1324{
1325 Q_D(QGraphicsProxyWidget);
1326#ifdef GRAPHICSPROXYWIDGET_DEBUG
1327 qDebug("QGraphicsProxyWidget::mouseReleaseEvent");
1328#endif
1329 d->sendWidgetMouseEvent(event);
1330}
1331
1332/*!
1333 \reimp
1334*/
1335void QGraphicsProxyWidget::keyPressEvent(QKeyEvent *event)
1336{
1337 Q_D(QGraphicsProxyWidget);
1338#ifdef GRAPHICSPROXYWIDGET_DEBUG
1339 qDebug("QGraphicsProxyWidget::keyPressEvent");
1340#endif
1341 d->sendWidgetKeyEvent(event);
1342}
1343
1344/*!
1345 \reimp
1346*/
1347void QGraphicsProxyWidget::keyReleaseEvent(QKeyEvent *event)
1348{
1349 Q_D(QGraphicsProxyWidget);
1350#ifdef GRAPHICSPROXYWIDGET_DEBUG
1351 qDebug("QGraphicsProxyWidget::keyReleaseEvent");
1352#endif
1353 d->sendWidgetKeyEvent(event);
1354}
1355
1356/*!
1357 \reimp
1358*/
1359void QGraphicsProxyWidget::focusInEvent(QFocusEvent *event)
1360{
1361#ifdef GRAPHICSPROXYWIDGET_DEBUG
1362 qDebug("QGraphicsProxyWidget::focusInEvent");
1363#endif
1364 Q_D(QGraphicsProxyWidget);
1365
1366 if (d->focusFromWidgetToProxy) {
1367 // Prevent recursion when the proxy autogains focus through the
1368 // embedded widget calling setFocus(). ### Could be done with event
1369 // filter on FocusIn instead?
1370 return;
1371 }
1372
1373 d->proxyIsGivingFocus = true;
1374
1375 switch (event->reason()) {
1376 case Qt::TabFocusReason: {
1377 if (QWidget *focusChild = d->findFocusChild(nullptr, true))
1378 focusChild->setFocus(event->reason());
1379 break;
1380 }
1381 case Qt::BacktabFocusReason:
1382 if (QWidget *focusChild = d->findFocusChild(nullptr, false))
1383 focusChild->setFocus(event->reason());
1384 break;
1385 default:
1386 if (d->widget && d->widget->focusWidget()) {
1387 d->widget->focusWidget()->setFocus(event->reason());
1388 }
1389 break;
1390 }
1391
1392 // QTBUG-88016
1393 if (d->widget && d->widget->focusWidget()
1394 && d->widget->focusWidget()->testAttribute(Qt::WA_InputMethodEnabled))
1395 QApplication::inputMethod()->reset();
1396
1397 d->proxyIsGivingFocus = false;
1398}
1399
1400/*!
1401 \reimp
1402*/
1403void QGraphicsProxyWidget::focusOutEvent(QFocusEvent *event)
1404{
1405#ifdef GRAPHICSPROXYWIDGET_DEBUG
1406 qDebug("QGraphicsProxyWidget::focusOutEvent");
1407#endif
1408 Q_D(QGraphicsProxyWidget);
1409 if (d->widget) {
1410 // We need to explicitly remove subfocus from the embedded widget's
1411 // focus widget.
1412 if (QWidget *focusWidget = d->widget->focusWidget()) {
1413 // QTBUG-88016 proxyWidget set QTextEdit(QLineEdit etc.) when input preview text,
1414 // inputMethod should be reset when proxyWidget lost focus
1415 if (focusWidget->testAttribute(Qt::WA_InputMethodEnabled))
1416 QApplication::inputMethod()->reset();
1417
1418 d->removeSubFocusHelper(focusWidget, event->reason());
1419 }
1420 }
1421}
1422
1423/*!
1424 \reimp
1425*/
1426bool QGraphicsProxyWidget::focusNextPrevChild(bool next)
1427{
1428 Q_D(QGraphicsProxyWidget);
1429 if (!d->widget || !d->scene)
1430 return QGraphicsWidget::focusNextPrevChild(next);
1431
1432 Qt::FocusReason reason = next ? Qt::TabFocusReason : Qt::BacktabFocusReason;
1433 QWidget *lastFocusChild = d->widget->focusWidget();
1434 if (QWidget *newFocusChild = d->findFocusChild(lastFocusChild, next)) {
1435 newFocusChild->setFocus(reason);
1436 return true;
1437 }
1438
1439 return QGraphicsWidget::focusNextPrevChild(next);
1440}
1441
1442/*!
1443 \reimp
1444*/
1445QVariant QGraphicsProxyWidget::inputMethodQuery(Qt::InputMethodQuery query) const
1446{
1447 Q_D(const QGraphicsProxyWidget);
1448
1449 if (!d->widget || !hasFocus())
1450 return QVariant();
1451
1452 QWidget *focusWidget = widget()->focusWidget();
1453 if (!focusWidget)
1454 focusWidget = d->widget;
1455 QVariant v = focusWidget->inputMethodQuery(query);
1456 QPointF focusWidgetPos = subWidgetRect(focusWidget).topLeft();
1457 switch (v.userType()) {
1458 case QMetaType::QRectF:
1459 v = v.toRectF().translated(focusWidgetPos);
1460 break;
1461 case QMetaType::QPointF:
1462 v = v.toPointF() + focusWidgetPos;
1463 break;
1464 case QMetaType::QRect:
1465 v = v.toRect().translated(focusWidgetPos.toPoint());
1466 break;
1467 case QMetaType::QPoint:
1468 v = v.toPoint() + focusWidgetPos.toPoint();
1469 break;
1470 default:
1471 break;
1472 }
1473 return v;
1474}
1475
1476/*!
1477 \reimp
1478*/
1479void QGraphicsProxyWidget::inputMethodEvent(QInputMethodEvent *event)
1480{
1481 // Forward input method events if the focus widget enables input methods.
1482 Q_D(const QGraphicsProxyWidget);
1483 QWidget *focusWidget = d->widget->focusWidget();
1484 if (focusWidget && focusWidget->testAttribute(Qt::WA_InputMethodEnabled))
1485 QCoreApplication::sendEvent(focusWidget, event);
1486}
1487
1488/*!
1489 \reimp
1490*/
1491QSizeF QGraphicsProxyWidget::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
1492{
1493 Q_D(const QGraphicsProxyWidget);
1494 if (!d->widget)
1495 return QGraphicsWidget::sizeHint(which, constraint);
1496
1497 QSizeF sh;
1498 switch (which) {
1499 case Qt::PreferredSize:
1500 if (QLayout *l = d->widget->layout())
1501 sh = l->sizeHint();
1502 else
1503 sh = d->widget->sizeHint();
1504 break;
1505 case Qt::MinimumSize:
1506 if (QLayout *l = d->widget->layout())
1507 sh = l->minimumSize();
1508 else
1509 sh = d->widget->minimumSizeHint();
1510 break;
1511 case Qt::MaximumSize:
1512 if (QLayout *l = d->widget->layout())
1513 sh = l->maximumSize();
1514 else
1515 sh = QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
1516 break;
1517 case Qt::MinimumDescent:
1518 sh = constraint;
1519 break;
1520 default:
1521 break;
1522 }
1523 return sh;
1524}
1525
1526/*!
1527 \reimp
1528*/
1529void QGraphicsProxyWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
1530{
1531 Q_D(QGraphicsProxyWidget);
1532 if (d->widget) {
1533 if (d->sizeChangeMode != QGraphicsProxyWidgetPrivate::WidgetToProxyMode)
1534 d->widget->resize(event->newSize().toSize());
1535 }
1536 QGraphicsWidget::resizeEvent(event);
1537}
1538
1539/*!
1540 \reimp
1541*/
1542void QGraphicsProxyWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
1543{
1544 Q_D(QGraphicsProxyWidget);
1545 Q_UNUSED(widget);
1546 if (!d->widget || !d->widget->isVisible())
1547 return;
1548
1549 // Filter out repaints on the window frame.
1550 const QRect exposedWidgetRect = (option->exposedRect & rect()).toAlignedRect();
1551 if (exposedWidgetRect.isEmpty())
1552 return;
1553
1554 // When rendering to pdf etc. painting may go outside widget boundaries unless clipped
1555 if (painter->device()->devType() != QInternal::Widget && (flags() & ItemClipsChildrenToShape))
1556 painter->setClipRect(d->widget->geometry(), Qt::IntersectClip);
1557
1558 d->widget->render(painter, exposedWidgetRect.topLeft(), exposedWidgetRect);
1559}
1560
1561/*!
1562 \enum QGraphicsProxyWidget::anonymous
1563
1564 The value returned by the virtual type() function.
1565
1566 \value Type A graphics proxy widget
1567*/
1568
1569/*!
1570 \reimp
1571*/
1572int QGraphicsProxyWidget::type() const
1573{
1574 return Type;
1575}
1576
1577/*!
1578 \since 4.5
1579
1580 Creates a proxy widget for the given \a child of the widget
1581 contained in this proxy.
1582
1583 This function makes it possible to acquire proxies for
1584 non top-level widgets. For instance, you can embed a dialog,
1585 and then transform only one of its widgets.
1586
1587 If the widget is already embedded, return the existing proxy widget.
1588
1589 \sa newProxyWidget(), QGraphicsScene::addWidget()
1590*/
1591QGraphicsProxyWidget *QGraphicsProxyWidget::createProxyForChildWidget(QWidget *child)
1592{
1593 QGraphicsProxyWidget *proxy = child->graphicsProxyWidget();
1594 if (proxy)
1595 return proxy;
1596 if (!child->parentWidget()) {
1597 qWarning("QGraphicsProxyWidget::createProxyForChildWidget: top-level widget not in a QGraphicsScene");
1598 return nullptr;
1599 }
1600
1601 QGraphicsProxyWidget *parentProxy = createProxyForChildWidget(child->parentWidget());
1602 if (!parentProxy)
1603 return nullptr;
1604
1605 if (!QMetaObject::invokeMethod(parentProxy, "newProxyWidget", Qt::DirectConnection,
1606 Q_RETURN_ARG(QGraphicsProxyWidget*, proxy), Q_ARG(const QWidget*, child)))
1607 return nullptr;
1608 proxy->setParent(parentProxy);
1609 proxy->setWidget(child);
1610 return proxy;
1611}
1612
1613/*!
1614 \fn QGraphicsProxyWidget *QGraphicsProxyWidget::newProxyWidget(const QWidget *child)
1615 \since 4.5
1616
1617 Creates a proxy widget for the given \a child of the widget contained in this
1618 proxy.
1619
1620 You should not call this function directly; use
1621 QGraphicsProxyWidget::createProxyForChildWidget() instead.
1622
1623 This function is a fake virtual slot that you can reimplement in
1624 your subclass in order to control how new proxy widgets are
1625 created. The default implementation returns a proxy created with
1626 the QGraphicsProxyWidget() constructor with this proxy widget as
1627 the parent.
1628
1629 \sa createProxyForChildWidget()
1630*/
1631QGraphicsProxyWidget *QGraphicsProxyWidget::newProxyWidget(const QWidget *)
1632{
1633 return new QGraphicsProxyWidget(this);
1634}
1635
1636
1637
1638QT_END_NAMESPACE
1639
1640#include "moc_qgraphicsproxywidget.cpp"
Q_WIDGETS_EXPORT bool qt_tab_all_widgets()
bool qt_sendSpontaneousEvent(QObject *, QEvent *)