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

Last change on this file since 500 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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