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

Last change on this file since 858 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 51.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
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 [email protected].
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 *);
192Q_GUI_EXPORT extern 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#ifndef QT_NO_TOOLTIP
901 case QEvent::GraphicsSceneHelp: {
902 // Propagate the help event (for tooltip) to the widget under mouse
903 if (d->lastWidgetUnderMouse) {
904 QGraphicsSceneHelpEvent *he = static_cast<QGraphicsSceneHelpEvent *>(event);
905 QPoint pos = d->mapToReceiver(mapFromScene(he->scenePos()), d->lastWidgetUnderMouse).toPoint();
906 QHelpEvent e(QEvent::ToolTip, pos, he->screenPos());
907 QApplication::sendEvent(d->lastWidgetUnderMouse, &e);
908 event->setAccepted(e.isAccepted());
909 return e.isAccepted();
910 }
911 break;
912 }
913 case QEvent::ToolTipChange: {
914 // Propagate tooltip change to the widget
915 if (!d->tooltipChangeMode) {
916 d->tooltipChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode;
917 d->widget->setToolTip(toolTip());
918 d->tooltipChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
919 }
920 break;
921 }
922#endif
923 default:
924 break;
925 }
926 return QGraphicsWidget::event(event);
927}
928
929/*!
930 \reimp
931*/
932bool QGraphicsProxyWidget::eventFilter(QObject *object, QEvent *event)
933{
934 Q_D(QGraphicsProxyWidget);
935
936 if (object == d->widget) {
937 switch (event->type()) {
938 case QEvent::LayoutRequest:
939 updateGeometry();
940 break;
941 case QEvent::Resize:
942 // If the widget resizes itself, we resize the proxy too.
943 // Prevent feed-back by checking the geometry change mode.
944 if (!d->sizeChangeMode)
945 d->updateProxyGeometryFromWidget();
946 break;
947 case QEvent::Move:
948 // If the widget moves itself, we move the proxy too. Prevent
949 // feed-back by checking the geometry change mode.
950 if (!d->posChangeMode)
951 d->updateProxyGeometryFromWidget();
952 break;
953 case QEvent::Hide:
954 case QEvent::Show:
955 // If the widget toggles its visible state, the proxy will follow.
956 if (!d->visibleChangeMode) {
957 d->visibleChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
958 setVisible(event->type() == QEvent::Show);
959 d->visibleChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
960 }
961 break;
962 case QEvent::EnabledChange:
963 // If the widget toggles its enabled state, the proxy will follow.
964 if (!d->enabledChangeMode) {
965 d->enabledChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
966 setEnabled(d->widget->isEnabled());
967 d->enabledChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
968 }
969 break;
970 case QEvent::StyleChange:
971 // Propagate style changes to the proxy.
972 if (!d->styleChangeMode) {
973 d->styleChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
974 setStyle(d->widget->style());
975 d->styleChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
976 }
977 break;
978#ifndef QT_NO_TOOLTIP
979 case QEvent::ToolTipChange:
980 // Propagate tooltip change to the proxy.
981 if (!d->tooltipChangeMode) {
982 d->tooltipChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
983 setToolTip(d->widget->toolTip());
984 d->tooltipChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
985 }
986 break;
987#endif
988 default:
989 break;
990 }
991 }
992 return QGraphicsWidget::eventFilter(object, event);
993}
994
995/*!
996 \reimp
997*/
998void QGraphicsProxyWidget::showEvent(QShowEvent *event)
999{
1000 Q_UNUSED(event);
1001}
1002
1003/*!
1004 \reimp
1005*/
1006void QGraphicsProxyWidget::hideEvent(QHideEvent *event)
1007{
1008 Q_UNUSED(event);
1009}
1010
1011#ifndef QT_NO_CONTEXTMENU
1012/*!
1013 \reimp
1014*/
1015void QGraphicsProxyWidget::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
1016{
1017 Q_D(QGraphicsProxyWidget);
1018 if (!event || !d->widget || !d->widget->isVisible() || !hasFocus())
1019 return;
1020
1021 // Find widget position and receiver.
1022 QPointF pos = event->pos();
1023 QPointer<QWidget> alienWidget = d->widget->childAt(pos.toPoint());
1024 QPointer<QWidget> receiver = alienWidget ? alienWidget : d->widget;
1025
1026 // Map event position from us to the receiver
1027 pos = d->mapToReceiver(pos, receiver);
1028
1029 QPoint globalPos = receiver->mapToGlobal(pos.toPoint());
1030 //If the receiver by-pass the proxy its popups
1031 //will be top level QWidgets therefore they need
1032 //the screen position. mapToGlobal expect the widget to
1033 //have proper coordinates in regards of the windowing system
1034 //but it's not true because the widget is embedded.
1035 if (bypassGraphicsProxyWidget(receiver))
1036 globalPos = event->screenPos();
1037
1038 // Send mouse event. ### Doesn't propagate the event.
1039 QContextMenuEvent contextMenuEvent(QContextMenuEvent::Reason(event->reason()),
1040 pos.toPoint(), globalPos, event->modifiers());
1041 QApplication::sendEvent(receiver, &contextMenuEvent);
1042
1043 event->setAccepted(contextMenuEvent.isAccepted());
1044}
1045#endif // QT_NO_CONTEXTMENU
1046
1047#ifndef QT_NO_DRAGANDDROP
1048/*!
1049 \reimp
1050*/
1051void QGraphicsProxyWidget::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
1052{
1053#ifdef QT_NO_DRAGANDDROP
1054 Q_UNUSED(event);
1055#else
1056 Q_D(QGraphicsProxyWidget);
1057 if (!d->widget)
1058 return;
1059
1060 QDragEnterEvent proxyDragEnter(event->pos().toPoint(), event->dropAction(), event->mimeData(), event->buttons(), event->modifiers());
1061 proxyDragEnter.setAccepted(event->isAccepted());
1062 QApplication::sendEvent(d->widget, &proxyDragEnter);
1063 event->setAccepted(proxyDragEnter.isAccepted());
1064 if (proxyDragEnter.isAccepted()) // we discard answerRect
1065 event->setDropAction(proxyDragEnter.dropAction());
1066#endif
1067}
1068/*!
1069 \reimp
1070*/
1071void QGraphicsProxyWidget::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
1072{
1073 Q_UNUSED(event);
1074#ifndef QT_NO_DRAGANDDROP
1075 Q_D(QGraphicsProxyWidget);
1076 if (!d->widget || !d->dragDropWidget)
1077 return;
1078 QDragLeaveEvent proxyDragLeave;
1079 QApplication::sendEvent(d->dragDropWidget, &proxyDragLeave);
1080 d->dragDropWidget = 0;
1081#endif
1082}
1083
1084/*!
1085 \reimp
1086*/
1087void QGraphicsProxyWidget::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
1088{
1089#ifdef QT_NO_DRAGANDDROP
1090 Q_UNUSED(event);
1091#else
1092 Q_D(QGraphicsProxyWidget);
1093 if (!d->widget)
1094 return;
1095 QPointF p = event->pos();
1096 event->ignore();
1097 QPointer<QWidget> subWidget = d->widget->childAt(p.toPoint());
1098 QPointer<QWidget> receiver = subWidget ? subWidget : d->widget;
1099 bool eventDelivered = false;
1100 for (; receiver; receiver = receiver->parentWidget()) {
1101 if (!receiver->isEnabled() || !receiver->acceptDrops())
1102 continue;
1103 // Map event position from us to the receiver
1104 QPoint receiverPos = d->mapToReceiver(p, receiver).toPoint();
1105 if (receiver != d->dragDropWidget) {
1106 // Try to enter before we leave
1107 QDragEnterEvent dragEnter(receiverPos, event->possibleActions(), event->mimeData(), event->buttons(), event->modifiers());
1108 dragEnter.setDropAction(event->proposedAction());
1109 QApplication::sendEvent(receiver, &dragEnter);
1110 event->setAccepted(dragEnter.isAccepted());
1111 event->setDropAction(dragEnter.dropAction());
1112 if (!event->isAccepted()) {
1113 // propagate to the parent widget
1114 continue;
1115 }
1116
1117 d->lastDropAction = event->dropAction();
1118
1119 if (d->dragDropWidget) {
1120 QDragLeaveEvent dragLeave;
1121 QApplication::sendEvent(d->dragDropWidget, &dragLeave);
1122 }
1123 d->dragDropWidget = receiver;
1124 }
1125
1126 QDragMoveEvent dragMove(receiverPos, event->possibleActions(), event->mimeData(), event->buttons(), event->modifiers());
1127 event->setDropAction(d->lastDropAction);
1128 QApplication::sendEvent(receiver, &dragMove);
1129 event->setAccepted(dragMove.isAccepted());
1130 event->setDropAction(dragMove.dropAction());
1131 if (event->isAccepted())
1132 d->lastDropAction = event->dropAction();
1133 eventDelivered = true;
1134 break;
1135 }
1136
1137 if (!eventDelivered) {
1138 if (d->dragDropWidget) {
1139 // Leave the last drag drop item
1140 QDragLeaveEvent dragLeave;
1141 QApplication::sendEvent(d->dragDropWidget, &dragLeave);
1142 d->dragDropWidget = 0;
1143 }
1144 // Propagate
1145 event->setDropAction(Qt::IgnoreAction);
1146 }
1147#endif
1148}
1149
1150/*!
1151 \reimp
1152*/
1153void QGraphicsProxyWidget::dropEvent(QGraphicsSceneDragDropEvent *event)
1154{
1155#ifdef QT_NO_DRAGANDDROP
1156 Q_UNUSED(event);
1157#else
1158 Q_D(QGraphicsProxyWidget);
1159 if (d->widget && d->dragDropWidget) {
1160 QPoint widgetPos = d->mapToReceiver(event->pos(), d->dragDropWidget).toPoint();
1161 QDropEvent dropEvent(widgetPos, event->possibleActions(), event->mimeData(), event->buttons(), event->modifiers());
1162 QApplication::sendEvent(d->dragDropWidget, &dropEvent);
1163 event->setAccepted(dropEvent.isAccepted());
1164 d->dragDropWidget = 0;
1165 }
1166#endif
1167}
1168#endif
1169
1170/*!
1171 \reimp
1172*/
1173void QGraphicsProxyWidget::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
1174{
1175 Q_UNUSED(event);
1176}
1177
1178/*!
1179 \reimp
1180*/
1181void QGraphicsProxyWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
1182{
1183 Q_UNUSED(event);
1184 Q_D(QGraphicsProxyWidget);
1185 // If hoverMove was compressed away, make sure we update properly here.
1186 if (d->lastWidgetUnderMouse) {
1187 QApplicationPrivate::dispatchEnterLeave(0, d->lastWidgetUnderMouse);
1188 d->lastWidgetUnderMouse = 0;
1189 }
1190}
1191
1192/*!
1193 \reimp
1194*/
1195void QGraphicsProxyWidget::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
1196{
1197 Q_D(QGraphicsProxyWidget);
1198#ifdef GRAPHICSPROXYWIDGET_DEBUG
1199 qDebug() << "QGraphicsProxyWidget::hoverMoveEvent";
1200#endif
1201 // Ignore events on the window frame.
1202 if (!d->widget || !rect().contains(event->pos())) {
1203 if (d->lastWidgetUnderMouse) {
1204 QApplicationPrivate::dispatchEnterLeave(0, d->lastWidgetUnderMouse);
1205 d->lastWidgetUnderMouse = 0;
1206 }
1207 return;
1208 }
1209
1210 d->embeddedMouseGrabber = 0;
1211 d->sendWidgetMouseEvent(event);
1212}
1213
1214/*!
1215 \reimp
1216*/
1217void QGraphicsProxyWidget::grabMouseEvent(QEvent *event)
1218{
1219 Q_UNUSED(event);
1220}
1221
1222/*!
1223 \reimp
1224*/
1225void QGraphicsProxyWidget::ungrabMouseEvent(QEvent *event)
1226{
1227 Q_D(QGraphicsProxyWidget);
1228 Q_UNUSED(event);
1229 d->embeddedMouseGrabber = 0;
1230}
1231
1232/*!
1233 \reimp
1234*/
1235void QGraphicsProxyWidget::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
1236{
1237 Q_D(QGraphicsProxyWidget);
1238#ifdef GRAPHICSPROXYWIDGET_DEBUG
1239 qDebug() << "QGraphicsProxyWidget::mouseMoveEvent";
1240#endif
1241 d->sendWidgetMouseEvent(event);
1242}
1243
1244/*!
1245 \reimp
1246*/
1247void QGraphicsProxyWidget::mousePressEvent(QGraphicsSceneMouseEvent *event)
1248{
1249 Q_D(QGraphicsProxyWidget);
1250#ifdef GRAPHICSPROXYWIDGET_DEBUG
1251 qDebug() << "QGraphicsProxyWidget::mousePressEvent";
1252#endif
1253 d->sendWidgetMouseEvent(event);
1254}
1255
1256/*!
1257 \reimp
1258*/
1259void QGraphicsProxyWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
1260{
1261 Q_D(QGraphicsProxyWidget);
1262#ifdef GRAPHICSPROXYWIDGET_DEBUG
1263 qDebug() << "QGraphicsProxyWidget::mouseDoubleClickEvent";
1264#endif
1265 d->sendWidgetMouseEvent(event);
1266}
1267
1268/*!
1269 \reimp
1270*/
1271#ifndef QT_NO_WHEELEVENT
1272void QGraphicsProxyWidget::wheelEvent(QGraphicsSceneWheelEvent *event)
1273{
1274 Q_D(QGraphicsProxyWidget);
1275#ifdef GRAPHICSPROXYWIDGET_DEBUG
1276 qDebug() << "QGraphicsProxyWidget::wheelEvent";
1277#endif
1278 if (!d->widget)
1279 return;
1280
1281 QPointF pos = event->pos();
1282 QPointer<QWidget> receiver = d->widget->childAt(pos.toPoint());
1283 if (!receiver)
1284 receiver = d->widget;
1285
1286 // Map event position from us to the receiver
1287 pos = d->mapToReceiver(pos, receiver);
1288
1289 // Send mouse event.
1290 QWheelEvent wheelEvent(pos.toPoint(), event->screenPos(), event->delta(),
1291 event->buttons(), event->modifiers(), event->orientation());
1292 QPointer<QWidget> focusWidget = d->widget->focusWidget();
1293 extern bool qt_sendSpontaneousEvent(QObject *, QEvent *);
1294 qt_sendSpontaneousEvent(receiver, &wheelEvent);
1295 event->setAccepted(wheelEvent.isAccepted());
1296
1297 // ### Remove, this should be done by proper focusIn/focusOut events.
1298 if (focusWidget && !focusWidget->hasFocus()) {
1299 focusWidget->update();
1300 focusWidget = d->widget->focusWidget();
1301 if (focusWidget && focusWidget->hasFocus())
1302 focusWidget->update();
1303 }
1304}
1305#endif
1306
1307/*!
1308 \reimp
1309*/
1310void QGraphicsProxyWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
1311{
1312 Q_D(QGraphicsProxyWidget);
1313#ifdef GRAPHICSPROXYWIDGET_DEBUG
1314 qDebug() << "QGraphicsProxyWidget::mouseReleaseEvent";
1315#endif
1316 d->sendWidgetMouseEvent(event);
1317}
1318
1319/*!
1320 \reimp
1321*/
1322void QGraphicsProxyWidget::keyPressEvent(QKeyEvent *event)
1323{
1324 Q_D(QGraphicsProxyWidget);
1325#ifdef GRAPHICSPROXYWIDGET_DEBUG
1326 qDebug() << "QGraphicsProxyWidget::keyPressEvent";
1327#endif
1328 d->sendWidgetKeyEvent(event);
1329}
1330
1331/*!
1332 \reimp
1333*/
1334void QGraphicsProxyWidget::keyReleaseEvent(QKeyEvent *event)
1335{
1336 Q_D(QGraphicsProxyWidget);
1337#ifdef GRAPHICSPROXYWIDGET_DEBUG
1338 qDebug() << "QGraphicsProxyWidget::keyReleaseEvent";
1339#endif
1340 d->sendWidgetKeyEvent(event);
1341}
1342
1343/*!
1344 \reimp
1345*/
1346void QGraphicsProxyWidget::focusInEvent(QFocusEvent *event)
1347{
1348#ifdef GRAPHICSPROXYWIDGET_DEBUG
1349 qDebug() << "QGraphicsProxyWidget::focusInEvent";
1350#endif
1351 Q_D(QGraphicsProxyWidget);
1352
1353 if (d->focusFromWidgetToProxy) {
1354 // Prevent recursion when the proxy autogains focus through the
1355 // embedded widget calling setFocus(). ### Could be done with event
1356 // filter on FocusIn instead?
1357 return;
1358 }
1359
1360 d->proxyIsGivingFocus = true;
1361
1362 switch (event->reason()) {
1363 case Qt::TabFocusReason: {
1364 if (QWidget *focusChild = d->findFocusChild(0, true))
1365 focusChild->setFocus(event->reason());
1366 break;
1367 }
1368 case Qt::BacktabFocusReason:
1369 if (QWidget *focusChild = d->findFocusChild(0, false))
1370 focusChild->setFocus(event->reason());
1371 break;
1372 default:
1373 if (d->widget && d->widget->focusWidget()) {
1374 d->widget->focusWidget()->setFocus(event->reason());
1375 }
1376 break;
1377 }
1378
1379 d->proxyIsGivingFocus = false;
1380}
1381
1382/*!
1383 \reimp
1384*/
1385void QGraphicsProxyWidget::focusOutEvent(QFocusEvent *event)
1386{
1387#ifdef GRAPHICSPROXYWIDGET_DEBUG
1388 qDebug() << "QGraphicsProxyWidget::focusOutEvent";
1389#endif
1390 Q_D(QGraphicsProxyWidget);
1391 if (d->widget) {
1392 // We need to explicitly remove subfocus from the embedded widget's
1393 // focus widget.
1394 if (QWidget *focusWidget = d->widget->focusWidget())
1395 d->removeSubFocusHelper(focusWidget, event->reason());
1396 }
1397}
1398
1399/*!
1400 \reimp
1401*/
1402bool QGraphicsProxyWidget::focusNextPrevChild(bool next)
1403{
1404 Q_D(QGraphicsProxyWidget);
1405 if (!d->widget || !d->scene)
1406 return QGraphicsWidget::focusNextPrevChild(next);
1407
1408 Qt::FocusReason reason = next ? Qt::TabFocusReason : Qt::BacktabFocusReason;
1409 QWidget *lastFocusChild = d->widget->focusWidget();
1410 if (QWidget *newFocusChild = d->findFocusChild(lastFocusChild, next)) {
1411 newFocusChild->setFocus(reason);
1412 return true;
1413 }
1414
1415 return QGraphicsWidget::focusNextPrevChild(next);
1416}
1417
1418/*!
1419 \reimp
1420*/
1421QSizeF QGraphicsProxyWidget::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
1422{
1423 Q_D(const QGraphicsProxyWidget);
1424 if (!d->widget)
1425 return QGraphicsWidget::sizeHint(which, constraint);
1426
1427 QSizeF sh;
1428 switch (which) {
1429 case Qt::PreferredSize:
1430 if (QLayout *l = d->widget->layout())
1431 sh = l->sizeHint();
1432 else
1433 sh = d->widget->sizeHint();
1434 break;
1435 case Qt::MinimumSize:
1436 if (QLayout *l = d->widget->layout())
1437 sh = l->minimumSize();
1438 else
1439 sh = d->widget->minimumSizeHint();
1440 break;
1441 case Qt::MaximumSize:
1442 if (QLayout *l = d->widget->layout())
1443 sh = l->maximumSize();
1444 else
1445 sh = QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
1446 break;
1447 case Qt::MinimumDescent:
1448 sh = constraint;
1449 break;
1450 default:
1451 break;
1452 }
1453 return sh;
1454}
1455
1456/*!
1457 \reimp
1458*/
1459void QGraphicsProxyWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
1460{
1461 Q_D(QGraphicsProxyWidget);
1462 if (d->widget) {
1463 if (d->sizeChangeMode != QGraphicsProxyWidgetPrivate::WidgetToProxyMode)
1464 d->widget->resize(event->newSize().toSize());
1465 }
1466 QGraphicsWidget::resizeEvent(event);
1467}
1468
1469/*!
1470 \reimp
1471*/
1472void QGraphicsProxyWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
1473{
1474 Q_D(QGraphicsProxyWidget);
1475 Q_UNUSED(widget);
1476 if (!d->widget || !d->widget->isVisible())
1477 return;
1478
1479 // Filter out repaints on the window frame.
1480 const QRect exposedWidgetRect = (option->exposedRect & rect()).toAlignedRect();
1481 if (exposedWidgetRect.isEmpty())
1482 return;
1483
1484 // Disable QPainter's default pen being cosmetic. This allows widgets and
1485 // styles to follow Qt's existing defaults without getting ugly cosmetic
1486 // lines when scaled.
1487 bool restore = !(painter->renderHints() & QPainter::NonCosmeticDefaultPen);
1488 painter->setRenderHints(QPainter::NonCosmeticDefaultPen, true);
1489
1490 d->widget->render(painter, exposedWidgetRect.topLeft(), exposedWidgetRect);
1491
1492 // Restore the render hints if necessary.
1493 if (restore)
1494 painter->setRenderHints(QPainter::NonCosmeticDefaultPen, false);
1495}
1496
1497/*!
1498 \reimp
1499*/
1500int QGraphicsProxyWidget::type() const
1501{
1502 return Type;
1503}
1504
1505/*!
1506 \since 4.5
1507
1508 Creates a proxy widget for the given \a child of the widget
1509 contained in this proxy.
1510
1511 This function makes it possible to acquire proxies for
1512 non top-level widgets. For instance, you can embed a dialog,
1513 and then transform only one of its widgets.
1514
1515 If the widget is already embedded, return the existing proxy widget.
1516
1517 \sa newProxyWidget(), QGraphicsScene::addWidget()
1518*/
1519QGraphicsProxyWidget *QGraphicsProxyWidget::createProxyForChildWidget(QWidget *child)
1520{
1521 QGraphicsProxyWidget *proxy = child->graphicsProxyWidget();
1522 if (proxy)
1523 return proxy;
1524 if (!child->parentWidget()) {
1525 qWarning("QGraphicsProxyWidget::createProxyForChildWidget: top-level widget not in a QGraphicsScene");
1526 return 0;
1527 }
1528
1529 QGraphicsProxyWidget *parentProxy = createProxyForChildWidget(child->parentWidget());
1530 if (!parentProxy)
1531 return 0;
1532
1533 if (!QMetaObject::invokeMethod(parentProxy, "newProxyWidget", Qt::DirectConnection,
1534 Q_RETURN_ARG(QGraphicsProxyWidget*, proxy), Q_ARG(const QWidget*, child)))
1535 return 0;
1536 proxy->setParent(parentProxy);
1537 proxy->setWidget(child);
1538 return proxy;
1539}
1540
1541/*!
1542 \fn QGraphicsProxyWidget *QGraphicsProxyWidget::newProxyWidget(const QWidget *child)
1543 \since 4.5
1544
1545 Creates a proxy widget for the given \a child of the widget contained in this
1546 proxy.
1547
1548 You should not call this function directly; use
1549 QGraphicsProxyWidget::createProxyForChildWidget() instead.
1550
1551 This function is a fake virtual slot that you can reimplement in
1552 your subclass in order to control how new proxy widgets are
1553 created. The default implementation returns a proxy created with
1554 the QGraphicsProxyWidget() constructor with this proxy widget as
1555 the parent.
1556
1557 \sa createProxyForChildWidget()
1558*/
1559QGraphicsProxyWidget *QGraphicsProxyWidget::newProxyWidget(const QWidget *)
1560{
1561 return new QGraphicsProxyWidget(this);
1562}
1563
1564
1565
1566QT_END_NAMESPACE
1567
1568#include "moc_qgraphicsproxywidget.cpp"
1569
1570#endif //QT_NO_GRAPHICSVIEW
Note: See TracBrowser for help on using the repository browser.