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
63QT_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
193extern bool qt_sendSpontaneousEvent(QObject *, QEvent *);
194Q_WIDGETS_EXPORT extern bool qt_tab_all_widgets();
195
196/*!
197 \internal
198*/
199QGraphicsProxyWidgetPrivate::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*/
217QGraphicsProxyWidgetPrivate::~QGraphicsProxyWidgetPrivate()
218{
219}
220
221/*!
222 \internal
223*/
224void QGraphicsProxyWidgetPrivate::init()
225{
226 Q_Q(QGraphicsProxyWidget);
227 q->setFocusPolicy(Qt::WheelFocus);
228 q->setAcceptDrops(true);
229}
230
231/*!
232 \internal
233*/
234void 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*/
249void 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
335void 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*/
357void 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*/
370QWidget *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*/
405void 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*/
419void QGraphicsProxyWidgetPrivate::updateWidgetGeometryFromProxy()
420{
421}
422
423/*!
424 \internal
425*/
426void 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*/
460void 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*/
480void 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*/
496void QGraphicsProxyWidgetPrivate::unembedSubWindow(QWidget *subWin)
497{
498 for (QGraphicsItem *child : qAsConst(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
512bool QGraphicsProxyWidgetPrivate::isProxyWidget() const
513{
514 return true;
515}
516
517/*!
518 \internal
519*/
520QPointF 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*/
536QGraphicsProxyWidget::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*/
546QGraphicsProxyWidget::~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*/
588void QGraphicsProxyWidget::setWidget(QWidget *widget)
589{
590 Q_D(QGraphicsProxyWidget);
591 d->setWidget_helper(widget, true);
592}
593
594void 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*/
732QWidget *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*/
747QRectF 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*/
760void 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*/
778QVariant 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*/
828bool 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.resolveMask() | 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.resolveMask() | 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#if QT_CONFIG(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*/
938bool 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#if QT_CONFIG(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*/
1004void QGraphicsProxyWidget::showEvent(QShowEvent *event)
1005{
1006 Q_UNUSED(event);
1007}
1008
1009/*!
1010 \reimp
1011*/
1012void QGraphicsProxyWidget::hideEvent(QHideEvent *event)
1013{
1014 Q_UNUSED(event);
1015}
1016
1017#ifndef QT_NO_CONTEXTMENU
1018/*!
1019 \reimp
1020*/
1021void 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*/
1057void 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*/
1077void 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*/
1093void 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*/
1159void 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*/
1179void QGraphicsProxyWidget::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
1180{
1181 Q_UNUSED(event);
1182}
1183
1184/*!
1185 \reimp
1186*/
1187void 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*/
1201void 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*/
1223void QGraphicsProxyWidget::grabMouseEvent(QEvent *event)
1224{
1225 Q_UNUSED(event);
1226}
1227
1228/*!
1229 \reimp
1230*/
1231void QGraphicsProxyWidget::ungrabMouseEvent(QEvent *event)
1232{
1233 Q_D(QGraphicsProxyWidget);
1234 Q_UNUSED(event);
1235 d->embeddedMouseGrabber = nullptr;
1236}
1237
1238/*!
1239 \reimp
1240*/
1241void 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*/
1253void 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*/
1265void 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)
1278void 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,
1305 false, Qt::MouseEventNotSynthesized,
1306 QPointingDevice::primaryPointingDevice());
1307 QPointer<QWidget> focusWidget = d->widget->focusWidget();
1308 extern bool qt_sendSpontaneousEvent(QObject *, QEvent *);
1309 qt_sendSpontaneousEvent(receiver, &wheelEvent);
1310 event->setAccepted(wheelEvent.isAccepted());
1311
1312 // ### Remove, this should be done by proper focusIn/focusOut events.
1313 if (focusWidget && !focusWidget->hasFocus()) {
1314 focusWidget->update();
1315 focusWidget = d->widget->focusWidget();
1316 if (focusWidget && focusWidget->hasFocus())
1317 focusWidget->update();
1318 }
1319}
1320#endif
1321
1322/*!
1323 \reimp
1324*/
1325void QGraphicsProxyWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
1326{
1327 Q_D(QGraphicsProxyWidget);
1328#ifdef GRAPHICSPROXYWIDGET_DEBUG
1329 qDebug("QGraphicsProxyWidget::mouseReleaseEvent");
1330#endif
1331 d->sendWidgetMouseEvent(event);
1332}
1333
1334/*!
1335 \reimp
1336*/
1337void QGraphicsProxyWidget::keyPressEvent(QKeyEvent *event)
1338{
1339 Q_D(QGraphicsProxyWidget);
1340#ifdef GRAPHICSPROXYWIDGET_DEBUG
1341 qDebug("QGraphicsProxyWidget::keyPressEvent");
1342#endif
1343 d->sendWidgetKeyEvent(event);
1344}
1345
1346/*!
1347 \reimp
1348*/
1349void QGraphicsProxyWidget::keyReleaseEvent(QKeyEvent *event)
1350{
1351 Q_D(QGraphicsProxyWidget);
1352#ifdef GRAPHICSPROXYWIDGET_DEBUG
1353 qDebug("QGraphicsProxyWidget::keyReleaseEvent");
1354#endif
1355 d->sendWidgetKeyEvent(event);
1356}
1357
1358/*!
1359 \reimp
1360*/
1361void QGraphicsProxyWidget::focusInEvent(QFocusEvent *event)
1362{
1363#ifdef GRAPHICSPROXYWIDGET_DEBUG
1364 qDebug("QGraphicsProxyWidget::focusInEvent");
1365#endif
1366 Q_D(QGraphicsProxyWidget);
1367
1368 if (d->focusFromWidgetToProxy) {
1369 // Prevent recursion when the proxy autogains focus through the
1370 // embedded widget calling setFocus(). ### Could be done with event
1371 // filter on FocusIn instead?
1372 return;
1373 }
1374
1375 d->proxyIsGivingFocus = true;
1376
1377 switch (event->reason()) {
1378 case Qt::TabFocusReason: {
1379 if (QWidget *focusChild = d->findFocusChild(nullptr, true))
1380 focusChild->setFocus(event->reason());
1381 break;
1382 }
1383 case Qt::BacktabFocusReason:
1384 if (QWidget *focusChild = d->findFocusChild(nullptr, false))
1385 focusChild->setFocus(event->reason());
1386 break;
1387 default:
1388 if (d->widget && d->widget->focusWidget()) {
1389 d->widget->focusWidget()->setFocus(event->reason());
1390 }
1391 break;
1392 }
1393
1394 d->proxyIsGivingFocus = false;
1395}
1396
1397/*!
1398 \reimp
1399*/
1400void QGraphicsProxyWidget::focusOutEvent(QFocusEvent *event)
1401{
1402#ifdef GRAPHICSPROXYWIDGET_DEBUG
1403 qDebug("QGraphicsProxyWidget::focusOutEvent");
1404#endif
1405 Q_D(QGraphicsProxyWidget);
1406 if (d->widget) {
1407 // We need to explicitly remove subfocus from the embedded widget's
1408 // focus widget.
1409 if (QWidget *focusWidget = d->widget->focusWidget())
1410 d->removeSubFocusHelper(focusWidget, event->reason());
1411 }
1412}
1413
1414/*!
1415 \reimp
1416*/
1417bool QGraphicsProxyWidget::focusNextPrevChild(bool next)
1418{
1419 Q_D(QGraphicsProxyWidget);
1420 if (!d->widget || !d->scene)
1421 return QGraphicsWidget::focusNextPrevChild(next);
1422
1423 Qt::FocusReason reason = next ? Qt::TabFocusReason : Qt::BacktabFocusReason;
1424 QWidget *lastFocusChild = d->widget->focusWidget();
1425 if (QWidget *newFocusChild = d->findFocusChild(lastFocusChild, next)) {
1426 newFocusChild->setFocus(reason);
1427 return true;
1428 }
1429
1430 return QGraphicsWidget::focusNextPrevChild(next);
1431}
1432
1433/*!
1434 \reimp
1435*/
1436QVariant QGraphicsProxyWidget::inputMethodQuery(Qt::InputMethodQuery query) const
1437{
1438 Q_D(const QGraphicsProxyWidget);
1439
1440 if (!d->widget || !hasFocus())
1441 return QVariant();
1442
1443 QWidget *focusWidget = widget()->focusWidget();
1444 if (!focusWidget)
1445 focusWidget = d->widget;
1446 QVariant v = focusWidget->inputMethodQuery(query);
1447 QPointF focusWidgetPos = subWidgetRect(focusWidget).topLeft();
1448 switch (v.userType()) {
1449 case QMetaType::QRectF:
1450 v = v.toRectF().translated(focusWidgetPos);
1451 break;
1452 case QMetaType::QPointF:
1453 v = v.toPointF() + focusWidgetPos;
1454 break;
1455 case QMetaType::QRect:
1456 v = v.toRect().translated(focusWidgetPos.toPoint());
1457 break;
1458 case QMetaType::QPoint:
1459 v = v.toPoint() + focusWidgetPos.toPoint();
1460 break;
1461 default:
1462 break;
1463 }
1464 return v;
1465}
1466
1467/*!
1468 \reimp
1469*/
1470void QGraphicsProxyWidget::inputMethodEvent(QInputMethodEvent *event)
1471{
1472 // Forward input method events if the focus widget enables input methods.
1473 Q_D(const QGraphicsProxyWidget);
1474 QWidget *focusWidget = d->widget->focusWidget();
1475 if (focusWidget && focusWidget->testAttribute(Qt::WA_InputMethodEnabled))
1476 QCoreApplication::sendEvent(focusWidget, event);
1477}
1478
1479/*!
1480 \reimp
1481*/
1482QSizeF QGraphicsProxyWidget::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
1483{
1484 Q_D(const QGraphicsProxyWidget);
1485 if (!d->widget)
1486 return QGraphicsWidget::sizeHint(which, constraint);
1487
1488 QSizeF sh;
1489 switch (which) {
1490 case Qt::PreferredSize:
1491 if (QLayout *l = d->widget->layout())
1492 sh = l->sizeHint();
1493 else
1494 sh = d->widget->sizeHint();
1495 break;
1496 case Qt::MinimumSize:
1497 if (QLayout *l = d->widget->layout())
1498 sh = l->minimumSize();
1499 else
1500 sh = d->widget->minimumSizeHint();
1501 break;
1502 case Qt::MaximumSize:
1503 if (QLayout *l = d->widget->layout())
1504 sh = l->maximumSize();
1505 else
1506 sh = QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
1507 break;
1508 case Qt::MinimumDescent:
1509 sh = constraint;
1510 break;
1511 default:
1512 break;
1513 }
1514 return sh;
1515}
1516
1517/*!
1518 \reimp
1519*/
1520void QGraphicsProxyWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
1521{
1522 Q_D(QGraphicsProxyWidget);
1523 if (d->widget) {
1524 if (d->sizeChangeMode != QGraphicsProxyWidgetPrivate::WidgetToProxyMode)
1525 d->widget->resize(event->newSize().toSize());
1526 }
1527 QGraphicsWidget::resizeEvent(event);
1528}
1529
1530/*!
1531 \reimp
1532*/
1533void QGraphicsProxyWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
1534{
1535 Q_D(QGraphicsProxyWidget);
1536 Q_UNUSED(widget);
1537 if (!d->widget || !d->widget->isVisible())
1538 return;
1539
1540 // Filter out repaints on the window frame.
1541 const QRect exposedWidgetRect = (option->exposedRect & rect()).toAlignedRect();
1542 if (exposedWidgetRect.isEmpty())
1543 return;
1544
1545 d->widget->render(painter, exposedWidgetRect.topLeft(), exposedWidgetRect);
1546}
1547
1548/*!
1549 \enum QGraphicsProxyWidget::anonymous
1550
1551 The value returned by the virtual type() function.
1552
1553 \value Type A graphics proxy widget
1554*/
1555
1556/*!
1557 \reimp
1558*/
1559int QGraphicsProxyWidget::type() const
1560{
1561 return Type;
1562}
1563
1564/*!
1565 \since 4.5
1566
1567 Creates a proxy widget for the given \a child of the widget
1568 contained in this proxy.
1569
1570 This function makes it possible to acquire proxies for
1571 non top-level widgets. For instance, you can embed a dialog,
1572 and then transform only one of its widgets.
1573
1574 If the widget is already embedded, return the existing proxy widget.
1575
1576 \sa newProxyWidget(), QGraphicsScene::addWidget()
1577*/
1578QGraphicsProxyWidget *QGraphicsProxyWidget::createProxyForChildWidget(QWidget *child)
1579{
1580 QGraphicsProxyWidget *proxy = child->graphicsProxyWidget();
1581 if (proxy)
1582 return proxy;
1583 if (!child->parentWidget()) {
1584 qWarning("QGraphicsProxyWidget::createProxyForChildWidget: top-level widget not in a QGraphicsScene");
1585 return nullptr;
1586 }
1587
1588 QGraphicsProxyWidget *parentProxy = createProxyForChildWidget(child->parentWidget());
1589 if (!parentProxy)
1590 return nullptr;
1591
1592 if (!QMetaObject::invokeMethod(parentProxy, "newProxyWidget", Qt::DirectConnection,
1593 Q_RETURN_ARG(QGraphicsProxyWidget*, proxy), Q_ARG(const QWidget*, child)))
1594 return nullptr;
1595 proxy->setParent(parentProxy);
1596 proxy->setWidget(child);
1597 return proxy;
1598}
1599
1600/*!
1601 \fn QGraphicsProxyWidget *QGraphicsProxyWidget::newProxyWidget(const QWidget *child)
1602 \since 4.5
1603
1604 Creates a proxy widget for the given \a child of the widget contained in this
1605 proxy.
1606
1607 You should not call this function directly; use
1608 QGraphicsProxyWidget::createProxyForChildWidget() instead.
1609
1610 This function is a fake virtual slot that you can reimplement in
1611 your subclass in order to control how new proxy widgets are
1612 created. The default implementation returns a proxy created with
1613 the QGraphicsProxyWidget() constructor with this proxy widget as
1614 the parent.
1615
1616 \sa createProxyForChildWidget()
1617*/
1618QGraphicsProxyWidget *QGraphicsProxyWidget::newProxyWidget(const QWidget *)
1619{
1620 return new QGraphicsProxyWidget(this);
1621}
1622
1623
1624
1625QT_END_NAMESPACE
1626
1627#include "moc_qgraphicsproxywidget.cpp"
1628