source: trunk/src/gui/graphicsview/qgraphicsproxywidget.cpp@ 651

Last change on this file since 651 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

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