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