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

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

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

File size: 50.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qglobal.h"
43
44#ifndef QT_NO_GRAPHICSVIEW
45
46#include "qgraphicslayout.h"
47#include "qgraphicsproxywidget.h"
48#include "private/qgraphicsproxywidget_p.h"
49#include "private/qwidget_p.h"
50#include "private/qapplication_p.h"
51
52#include <QtCore/qdebug.h>
53#include <QtGui/qevent.h>
54#include <QtGui/qgraphicsscene.h>
55#include <QtGui/qgraphicssceneevent.h>
56#include <QtGui/qlayout.h>
57#include <QtGui/qpainter.h>
58#include <QtGui/qstyleoption.h>
59#include <QtGui/qgraphicsview.h>
60#include <QtGui/qlistview.h>
61#include <QtGui/qlineedit.h>
62#include <QtGui/qtextedit.h>
63
64QT_BEGIN_NAMESPACE
65
66//#define GRAPHICSPROXYWIDGET_DEBUG
67
68/*!
69 \class QGraphicsProxyWidget
70 \brief The QGraphicsProxyWidget class provides a proxy layer for embedding
71 a QWidget in a QGraphicsScene.
72 \since 4.4
73 \ingroup graphicsview-api
74
75 QGraphicsProxyWidget embeds QWidget-based widgets, for example, a
76 QPushButton, QFontComboBox, or even QFileDialog, into
77 QGraphicsScene. It forwards events between the two objects and
78 translates between QWidget's integer-based geometry and
79 QGraphicsWidget's qreal-based geometry. QGraphicsProxyWidget
80 supports all core features of QWidget, including tab focus,
81 keyboard input, Drag & Drop, and popups. You can also embed
82 complex widgets, e.g., widgets with subwidgets.
83
84 Example:
85
86 \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsproxywidget.cpp 0
87
88 QGraphicsProxyWidget takes care of automatically embedding popup children
89 of embedded widgets through creating a child proxy for each popup. This
90 means that when an embedded QComboBox shows its popup list, a new
91 QGraphicsProxyWidget is created automatically, embedding the popup, and
92 positioning it correctly. This only works if the popup is child of the
93 embedded widget (for example QToolButton::setMenu() requires the QMenu instance
94 to be child of the QToolButton).
95
96 \section1 Embedding a Widget with QGraphicsProxyWidget
97
98 There are two ways to embed a widget using QGraphicsProxyWidget. The most
99 common way is to pass a widget pointer to QGraphicsScene::addWidget()
100 together with any relevant \l Qt::WindowFlags. This function returns a
101 pointer to a QGraphicsProxyWidget. You can then choose to reparent or
102 position either the proxy, or the embedded widget itself.
103
104 For example, in the code snippet below, we embed a group box into the proxy:
105
106 \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsproxywidget.cpp 1
107
108 The image below is the output obtained with its contents margin and
109 contents rect labeled.
110
111 \image qgraphicsproxywidget-embed.png
112
113 Alternatively, you can start by creating a new QGraphicsProxyWidget item,
114 and then call setWidget() to embed a QWidget later. The widget() function
115 returns a pointer to the embedded widget. QGraphicsProxyWidget shares
116 ownership with QWidget, so if either of the two widgets are destroyed, the
117 other widget will be automatically destroyed as well.
118
119 \section1 Synchronizing Widget States
120
121 QGraphicsProxyWidget keeps its state in sync with the embedded widget. For
122 example, if the proxy is hidden or disabled, the embedded widget will be
123 hidden or disabled as well, and vice versa. When the widget is embedded by
124 calling addWidget(), QGraphicsProxyWidget copies the state from the widget
125 into the proxy, and after that, the two will stay synchronized where
126 possible. By default, when you embed a widget into a proxy, both the widget
127 and the proxy will be visible because a QGraphicsWidget is visible when
128 created (you do not have to call show()). If you explicitly hide the
129 embedded widget, the proxy will also become invisible.
130
131 Example:
132
133 \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsproxywidget.cpp 2
134
135 QGraphicsProxyWidget maintains symmetry for the following states:
136
137 \table
138 \header \o QWidget state \o QGraphicsProxyWidget state \o Notes
139 \row \o QWidget::enabled
140 \o QGraphicsProxyWidget::enabled
141 \o
142 \row \o QWidget::visible
143 \o QGraphicsProxyWidget::visible
144 \o The explicit state is also symmetric.
145 \row \o QWidget::geometry
146 \o QGraphicsProxyWidget::geometry
147 \o Geometry is only guaranteed to be symmetric while
148 the embedded widget is visible.
149 \row \o QWidget::layoutDirection
150 \o QGraphicsProxyWidget::layoutDirection
151 \o
152 \row \o QWidget::style
153 \o QGraphicsProxyWidget::style
154 \o
155 \row \o QWidget::palette
156 \o QGraphicsProxyWidget::palette
157 \o
158 \row \o QWidget::font
159 \o QGraphicsProxyWidget::font
160 \o
161 \row \o QWidget::cursor
162 \o QGraphicsProxyWidget::cursor
163 \o The embedded widget overrides the proxy widget
164 cursor. The proxy cursor changes depending on
165 which embedded subwidget is currently under the
166 mouse.
167 \row \o QWidget::sizeHint()
168 \o QGraphicsProxyWidget::sizeHint()
169 \o All size hint functionality from the embedded
170 widget is forwarded by the proxy.
171 \row \o QWidget::getContentsMargins()
172 \o QGraphicsProxyWidget::getContentsMargins()
173 \o Updated once by setWidget().
174 \row \o QWidget::windowTitle
175 \o QGraphicsProxyWidget::windowTitle
176 \o Updated once by setWidget().
177 \endtable
178
179 \note QGraphicsScene keeps the embedded widget in a special state that
180 prevents it from disturbing other widgets (both embedded and not embedded)
181 while the widget is embedded. In this state, the widget may differ slightly
182 in behavior from when it is not embedded.
183
184 \warning This class is provided for convenience when bridging
185 QWidgets and QGraphicsItems, it should not be used for
186 high-performance scenarios.
187
188 \sa QGraphicsScene::addWidget(), QGraphicsWidget
189*/
190
191extern bool qt_sendSpontaneousEvent(QObject *, QEvent *);
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 case QEvent::ToolTipChange:
979 // Propagate tooltip change to the proxy.
980 if (!d->tooltipChangeMode) {
981 d->tooltipChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
982 setToolTip(d->widget->toolTip());
983 d->tooltipChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
984 }
985 break;
986 default:
987 break;
988 }
989 }
990 return QGraphicsWidget::eventFilter(object, event);
991}
992
993/*!
994 \reimp
995*/
996void QGraphicsProxyWidget::showEvent(QShowEvent *event)
997{
998 Q_UNUSED(event);
999}
1000
1001/*!
1002 \reimp
1003*/
1004void QGraphicsProxyWidget::hideEvent(QHideEvent *event)
1005{
1006 Q_UNUSED(event);
1007}
1008
1009#ifndef QT_NO_CONTEXTMENU
1010/*!
1011 \reimp
1012*/
1013void QGraphicsProxyWidget::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
1014{
1015 Q_D(QGraphicsProxyWidget);
1016 if (!event || !d->widget || !d->widget->isVisible() || !hasFocus())
1017 return;
1018
1019 // Find widget position and receiver.
1020 QPointF pos = event->pos();
1021 QPointer<QWidget> alienWidget = d->widget->childAt(pos.toPoint());
1022 QPointer<QWidget> receiver = alienWidget ? alienWidget : d->widget;
1023
1024 // Map event position from us to the receiver
1025 pos = d->mapToReceiver(pos, receiver);
1026
1027 // Send mouse event. ### Doesn't propagate the event.
1028 QContextMenuEvent contextMenuEvent(QContextMenuEvent::Reason(event->reason()),
1029 pos.toPoint(), receiver->mapToGlobal(pos.toPoint()), event->modifiers());
1030 QApplication::sendEvent(receiver, &contextMenuEvent);
1031
1032 event->setAccepted(contextMenuEvent.isAccepted());
1033}
1034#endif // QT_NO_CONTEXTMENU
1035
1036#ifndef QT_NO_DRAGANDDROP
1037/*!
1038 \reimp
1039*/
1040void QGraphicsProxyWidget::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
1041{
1042#ifdef QT_NO_DRAGANDDROP
1043 Q_UNUSED(event);
1044#else
1045 Q_D(QGraphicsProxyWidget);
1046 if (!d->widget)
1047 return;
1048
1049 QDragEnterEvent proxyDragEnter(event->pos().toPoint(), event->dropAction(), event->mimeData(), event->buttons(), event->modifiers());
1050 proxyDragEnter.setAccepted(event->isAccepted());
1051 QApplication::sendEvent(d->widget, &proxyDragEnter);
1052 event->setAccepted(proxyDragEnter.isAccepted());
1053 if (proxyDragEnter.isAccepted()) // we discard answerRect
1054 event->setDropAction(proxyDragEnter.dropAction());
1055#endif
1056}
1057/*!
1058 \reimp
1059*/
1060void QGraphicsProxyWidget::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
1061{
1062 Q_UNUSED(event);
1063#ifndef QT_NO_DRAGANDDROP
1064 Q_D(QGraphicsProxyWidget);
1065 if (!d->widget || !d->dragDropWidget)
1066 return;
1067 QDragLeaveEvent proxyDragLeave;
1068 QApplication::sendEvent(d->dragDropWidget, &proxyDragLeave);
1069 d->dragDropWidget = 0;
1070#endif
1071}
1072
1073/*!
1074 \reimp
1075*/
1076void QGraphicsProxyWidget::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
1077{
1078#ifdef QT_NO_DRAGANDDROP
1079 Q_UNUSED(event);
1080#else
1081 Q_D(QGraphicsProxyWidget);
1082 if (!d->widget)
1083 return;
1084 QPointF p = event->pos();
1085 event->ignore();
1086 QPointer<QWidget> subWidget = d->widget->childAt(p.toPoint());
1087 QPointer<QWidget> receiver = subWidget ? subWidget : d->widget;
1088 bool eventDelivered = false;
1089 for (; receiver; receiver = receiver->parentWidget()) {
1090 if (!receiver->isEnabled() || !receiver->acceptDrops())
1091 continue;
1092 // Map event position from us to the receiver
1093 QPoint receiverPos = d->mapToReceiver(p, receiver).toPoint();
1094 if (receiver != d->dragDropWidget) {
1095 // Try to enter before we leave
1096 QDragEnterEvent dragEnter(receiverPos, event->possibleActions(), event->mimeData(), event->buttons(), event->modifiers());
1097 dragEnter.setDropAction(event->proposedAction());
1098 QApplication::sendEvent(receiver, &dragEnter);
1099 event->setAccepted(dragEnter.isAccepted());
1100 event->setDropAction(dragEnter.dropAction());
1101 if (!event->isAccepted()) {
1102 // propagate to the parent widget
1103 continue;
1104 }
1105
1106 d->lastDropAction = event->dropAction();
1107
1108 if (d->dragDropWidget) {
1109 QDragLeaveEvent dragLeave;
1110 QApplication::sendEvent(d->dragDropWidget, &dragLeave);
1111 }
1112 d->dragDropWidget = receiver;
1113 }
1114
1115 QDragMoveEvent dragMove(receiverPos, event->possibleActions(), event->mimeData(), event->buttons(), event->modifiers());
1116 event->setDropAction(d->lastDropAction);
1117 QApplication::sendEvent(receiver, &dragMove);
1118 event->setAccepted(dragMove.isAccepted());
1119 event->setDropAction(dragMove.dropAction());
1120 if (event->isAccepted())
1121 d->lastDropAction = event->dropAction();
1122 eventDelivered = true;
1123 break;
1124 }
1125
1126 if (!eventDelivered) {
1127 if (d->dragDropWidget) {
1128 // Leave the last drag drop item
1129 QDragLeaveEvent dragLeave;
1130 QApplication::sendEvent(d->dragDropWidget, &dragLeave);
1131 d->dragDropWidget = 0;
1132 }
1133 // Propagate
1134 event->setDropAction(Qt::IgnoreAction);
1135 }
1136#endif
1137}
1138
1139/*!
1140 \reimp
1141*/
1142void QGraphicsProxyWidget::dropEvent(QGraphicsSceneDragDropEvent *event)
1143{
1144#ifdef QT_NO_DRAGANDDROP
1145 Q_UNUSED(event);
1146#else
1147 Q_D(QGraphicsProxyWidget);
1148 if (d->widget && d->dragDropWidget) {
1149 QPoint widgetPos = d->mapToReceiver(event->pos(), d->dragDropWidget).toPoint();
1150 QDropEvent dropEvent(widgetPos, event->possibleActions(), event->mimeData(), event->buttons(), event->modifiers());
1151 QApplication::sendEvent(d->dragDropWidget, &dropEvent);
1152 event->setAccepted(dropEvent.isAccepted());
1153 d->dragDropWidget = 0;
1154 }
1155#endif
1156}
1157#endif
1158
1159/*!
1160 \reimp
1161*/
1162void QGraphicsProxyWidget::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
1163{
1164 Q_UNUSED(event);
1165}
1166
1167/*!
1168 \reimp
1169*/
1170void QGraphicsProxyWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
1171{
1172 Q_UNUSED(event);
1173 Q_D(QGraphicsProxyWidget);
1174 // If hoverMove was compressed away, make sure we update properly here.
1175 if (d->lastWidgetUnderMouse) {
1176 QApplicationPrivate::dispatchEnterLeave(0, d->lastWidgetUnderMouse);
1177 d->lastWidgetUnderMouse = 0;
1178 }
1179}
1180
1181/*!
1182 \reimp
1183*/
1184void QGraphicsProxyWidget::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
1185{
1186 Q_D(QGraphicsProxyWidget);
1187#ifdef GRAPHICSPROXYWIDGET_DEBUG
1188 qDebug() << "QGraphicsProxyWidget::hoverMoveEvent";
1189#endif
1190 // Ignore events on the window frame.
1191 if (!d->widget || !rect().contains(event->pos())) {
1192 if (d->lastWidgetUnderMouse) {
1193 QApplicationPrivate::dispatchEnterLeave(0, d->lastWidgetUnderMouse);
1194 d->lastWidgetUnderMouse = 0;
1195 }
1196 return;
1197 }
1198
1199 d->embeddedMouseGrabber = 0;
1200 d->sendWidgetMouseEvent(event);
1201}
1202
1203/*!
1204 \reimp
1205*/
1206void QGraphicsProxyWidget::grabMouseEvent(QEvent *event)
1207{
1208 Q_UNUSED(event);
1209}
1210
1211/*!
1212 \reimp
1213*/
1214void QGraphicsProxyWidget::ungrabMouseEvent(QEvent *event)
1215{
1216 Q_D(QGraphicsProxyWidget);
1217 Q_UNUSED(event);
1218 d->embeddedMouseGrabber = 0;
1219}
1220
1221/*!
1222 \reimp
1223*/
1224void QGraphicsProxyWidget::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
1225{
1226 Q_D(QGraphicsProxyWidget);
1227#ifdef GRAPHICSPROXYWIDGET_DEBUG
1228 qDebug() << "QGraphicsProxyWidget::mouseMoveEvent";
1229#endif
1230 d->sendWidgetMouseEvent(event);
1231}
1232
1233/*!
1234 \reimp
1235*/
1236void QGraphicsProxyWidget::mousePressEvent(QGraphicsSceneMouseEvent *event)
1237{
1238 Q_D(QGraphicsProxyWidget);
1239#ifdef GRAPHICSPROXYWIDGET_DEBUG
1240 qDebug() << "QGraphicsProxyWidget::mousePressEvent";
1241#endif
1242 d->sendWidgetMouseEvent(event);
1243}
1244
1245/*!
1246 \reimp
1247*/
1248void QGraphicsProxyWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
1249{
1250 Q_D(QGraphicsProxyWidget);
1251#ifdef GRAPHICSPROXYWIDGET_DEBUG
1252 qDebug() << "QGraphicsProxyWidget::mouseDoubleClickEvent";
1253#endif
1254 d->sendWidgetMouseEvent(event);
1255}
1256
1257/*!
1258 \reimp
1259*/
1260#ifndef QT_NO_WHEELEVENT
1261void QGraphicsProxyWidget::wheelEvent(QGraphicsSceneWheelEvent *event)
1262{
1263 Q_D(QGraphicsProxyWidget);
1264#ifdef GRAPHICSPROXYWIDGET_DEBUG
1265 qDebug() << "QGraphicsProxyWidget::wheelEvent";
1266#endif
1267 if (!d->widget)
1268 return;
1269
1270 QPointF pos = event->pos();
1271 QPointer<QWidget> receiver = d->widget->childAt(pos.toPoint());
1272 if (!receiver)
1273 receiver = d->widget;
1274
1275 // Map event position from us to the receiver
1276 pos = d->mapToReceiver(pos, receiver);
1277
1278 // Send mouse event.
1279 QWheelEvent wheelEvent(pos.toPoint(), event->screenPos(), event->delta(),
1280 event->buttons(), event->modifiers(), event->orientation());
1281 QPointer<QWidget> focusWidget = d->widget->focusWidget();
1282 extern bool qt_sendSpontaneousEvent(QObject *, QEvent *);
1283 qt_sendSpontaneousEvent(receiver, &wheelEvent);
1284 event->setAccepted(wheelEvent.isAccepted());
1285
1286 // ### Remove, this should be done by proper focusIn/focusOut events.
1287 if (focusWidget && !focusWidget->hasFocus()) {
1288 focusWidget->update();
1289 focusWidget = d->widget->focusWidget();
1290 if (focusWidget && focusWidget->hasFocus())
1291 focusWidget->update();
1292 }
1293}
1294#endif
1295
1296/*!
1297 \reimp
1298*/
1299void QGraphicsProxyWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
1300{
1301 Q_D(QGraphicsProxyWidget);
1302#ifdef GRAPHICSPROXYWIDGET_DEBUG
1303 qDebug() << "QGraphicsProxyWidget::mouseReleaseEvent";
1304#endif
1305 d->sendWidgetMouseEvent(event);
1306}
1307
1308/*!
1309 \reimp
1310*/
1311void QGraphicsProxyWidget::keyPressEvent(QKeyEvent *event)
1312{
1313 Q_D(QGraphicsProxyWidget);
1314#ifdef GRAPHICSPROXYWIDGET_DEBUG
1315 qDebug() << "QGraphicsProxyWidget::keyPressEvent";
1316#endif
1317 d->sendWidgetKeyEvent(event);
1318}
1319
1320/*!
1321 \reimp
1322*/
1323void QGraphicsProxyWidget::keyReleaseEvent(QKeyEvent *event)
1324{
1325 Q_D(QGraphicsProxyWidget);
1326#ifdef GRAPHICSPROXYWIDGET_DEBUG
1327 qDebug() << "QGraphicsProxyWidget::keyReleaseEvent";
1328#endif
1329 d->sendWidgetKeyEvent(event);
1330}
1331
1332/*!
1333 \reimp
1334*/
1335void QGraphicsProxyWidget::focusInEvent(QFocusEvent *event)
1336{
1337#ifdef GRAPHICSPROXYWIDGET_DEBUG
1338 qDebug() << "QGraphicsProxyWidget::focusInEvent";
1339#endif
1340 Q_D(QGraphicsProxyWidget);
1341
1342 if (d->focusFromWidgetToProxy) {
1343 // Prevent recursion when the proxy autogains focus through the
1344 // embedded widget calling setFocus(). ### Could be done with event
1345 // filter on FocusIn instead?
1346 return;
1347 }
1348
1349 d->proxyIsGivingFocus = true;
1350
1351 switch (event->reason()) {
1352 case Qt::TabFocusReason: {
1353 if (QWidget *focusChild = d->findFocusChild(0, true))
1354 focusChild->setFocus(event->reason());
1355 break;
1356 }
1357 case Qt::BacktabFocusReason:
1358 if (QWidget *focusChild = d->findFocusChild(0, false))
1359 focusChild->setFocus(event->reason());
1360 break;
1361 default:
1362 if (d->widget && d->widget->focusWidget()) {
1363 d->widget->focusWidget()->setFocus(event->reason());
1364 }
1365 break;
1366 }
1367
1368 d->proxyIsGivingFocus = false;
1369}
1370
1371/*!
1372 \reimp
1373*/
1374void QGraphicsProxyWidget::focusOutEvent(QFocusEvent *event)
1375{
1376#ifdef GRAPHICSPROXYWIDGET_DEBUG
1377 qDebug() << "QGraphicsProxyWidget::focusOutEvent";
1378#endif
1379 Q_D(QGraphicsProxyWidget);
1380 if (d->widget) {
1381 // We need to explicitly remove subfocus from the embedded widget's
1382 // focus widget.
1383 if (QWidget *focusWidget = d->widget->focusWidget())
1384 d->removeSubFocusHelper(focusWidget, event->reason());
1385 }
1386}
1387
1388/*!
1389 \reimp
1390*/
1391bool QGraphicsProxyWidget::focusNextPrevChild(bool next)
1392{
1393 Q_D(QGraphicsProxyWidget);
1394 if (!d->widget || !d->scene)
1395 return QGraphicsWidget::focusNextPrevChild(next);
1396
1397 Qt::FocusReason reason = next ? Qt::TabFocusReason : Qt::BacktabFocusReason;
1398 QWidget *lastFocusChild = d->widget->focusWidget();
1399 if (QWidget *newFocusChild = d->findFocusChild(lastFocusChild, next)) {
1400 newFocusChild->setFocus(reason);
1401 return true;
1402 }
1403
1404 return QGraphicsWidget::focusNextPrevChild(next);
1405}
1406
1407/*!
1408 \reimp
1409*/
1410QSizeF QGraphicsProxyWidget::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
1411{
1412 Q_D(const QGraphicsProxyWidget);
1413 if (!d->widget)
1414 return QGraphicsWidget::sizeHint(which, constraint);
1415
1416 QSizeF sh;
1417 switch (which) {
1418 case Qt::PreferredSize:
1419 if (QLayout *l = d->widget->layout())
1420 sh = l->sizeHint();
1421 else
1422 sh = d->widget->sizeHint();
1423 break;
1424 case Qt::MinimumSize:
1425 if (QLayout *l = d->widget->layout())
1426 sh = l->minimumSize();
1427 else
1428 sh = d->widget->minimumSizeHint();
1429 break;
1430 case Qt::MaximumSize:
1431 if (QLayout *l = d->widget->layout())
1432 sh = l->maximumSize();
1433 else
1434 sh = QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
1435 break;
1436 case Qt::MinimumDescent:
1437 sh = constraint;
1438 break;
1439 default:
1440 break;
1441 }
1442 return sh;
1443}
1444
1445/*!
1446 \reimp
1447*/
1448void QGraphicsProxyWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
1449{
1450 Q_D(QGraphicsProxyWidget);
1451 if (d->widget) {
1452 if (d->sizeChangeMode != QGraphicsProxyWidgetPrivate::WidgetToProxyMode)
1453 d->widget->resize(event->newSize().toSize());
1454 }
1455 QGraphicsWidget::resizeEvent(event);
1456}
1457
1458/*!
1459 \reimp
1460*/
1461void QGraphicsProxyWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
1462{
1463 Q_D(QGraphicsProxyWidget);
1464 Q_UNUSED(widget);
1465 if (!d->widget || !d->widget->isVisible())
1466 return;
1467
1468 // Filter out repaints on the window frame.
1469 const QRect exposedWidgetRect = (option->exposedRect & rect()).toAlignedRect();
1470 if (exposedWidgetRect.isEmpty())
1471 return;
1472
1473 // Disable QPainter's default pen being cosmetic. This allows widgets and
1474 // styles to follow Qt's existing defaults without getting ugly cosmetic
1475 // lines when scaled.
1476 bool restore = !(painter->renderHints() & QPainter::NonCosmeticDefaultPen);
1477 painter->setRenderHints(QPainter::NonCosmeticDefaultPen, true);
1478
1479 d->widget->render(painter, exposedWidgetRect.topLeft(), exposedWidgetRect);
1480
1481 // Restore the render hints if necessary.
1482 if (restore)
1483 painter->setRenderHints(QPainter::NonCosmeticDefaultPen, false);
1484}
1485
1486/*!
1487 \reimp
1488*/
1489int QGraphicsProxyWidget::type() const
1490{
1491 return Type;
1492}
1493
1494/*!
1495 \since 4.5
1496
1497 Creates a proxy widget for the given \a child of the widget
1498 contained in this proxy.
1499
1500 This function makes it possible to aquire proxies for
1501 non top-level widgets. For instance, you can embed a dialog,
1502 and then transform only one of its widgets.
1503
1504 If the widget is already embedded, return the existing proxy widget.
1505
1506 \sa newProxyWidget(), QGraphicsScene::addWidget()
1507*/
1508QGraphicsProxyWidget *QGraphicsProxyWidget::createProxyForChildWidget(QWidget *child)
1509{
1510 QGraphicsProxyWidget *proxy = child->graphicsProxyWidget();
1511 if (proxy)
1512 return proxy;
1513 if (!child->parentWidget()) {
1514 qWarning("QGraphicsProxyWidget::createProxyForChildWidget: top-level widget not in a QGraphicsScene");
1515 return 0;
1516 }
1517
1518 QGraphicsProxyWidget *parentProxy = createProxyForChildWidget(child->parentWidget());
1519 if (!parentProxy)
1520 return 0;
1521
1522 if (!QMetaObject::invokeMethod(parentProxy, "newProxyWidget", Qt::DirectConnection,
1523 Q_RETURN_ARG(QGraphicsProxyWidget*, proxy), Q_ARG(const QWidget*, child)))
1524 return 0;
1525 proxy->setParent(parentProxy);
1526 proxy->setWidget(child);
1527 return proxy;
1528}
1529
1530/*!
1531 \fn QGraphicsProxyWidget *QGraphicsProxyWidget::newProxyWidget(const QWidget *child)
1532 \since 4.5
1533
1534 Creates a proxy widget for the given \a child of the widget contained in this
1535 proxy.
1536
1537 You should not call this function directly; use
1538 QGraphicsProxyWidget::createProxyForChildWidget() instead.
1539
1540 This function is a fake virtual slot that you can reimplement in
1541 your subclass in order to control how new proxy widgets are
1542 created. The default implementation returns a proxy created with
1543 the QGraphicsProxyWidget() constructor with this proxy widget as
1544 the parent.
1545
1546 \sa createProxyForChildWidget()
1547*/
1548QGraphicsProxyWidget *QGraphicsProxyWidget::newProxyWidget(const QWidget *)
1549{
1550 return new QGraphicsProxyWidget(this);
1551}
1552
1553
1554
1555QT_END_NAMESPACE
1556
1557#include "moc_qgraphicsproxywidget.cpp"
1558
1559#endif //QT_NO_GRAPHICSVIEW
Note: See TracBrowser for help on using the repository browser.