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