src/gui/graphicsview/qgraphicsproxywidget.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 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 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    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 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    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 
       
    64 QT_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 
       
   191 extern bool qt_sendSpontaneousEvent(QObject *, QEvent *);
       
   192 extern bool qt_tab_all_widgets;
       
   193 
       
   194 /*!
       
   195     \internal
       
   196 */
       
   197 void QGraphicsProxyWidgetPrivate::init()
       
   198 {
       
   199     Q_Q(QGraphicsProxyWidget);
       
   200     q->setFocusPolicy(Qt::WheelFocus);
       
   201     q->setAcceptDrops(true);
       
   202 }
       
   203 
       
   204 /*!
       
   205     \internal
       
   206 */
       
   207 void 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 */
       
   222 void 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 
       
   309 void 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 */
       
   331 void 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 */
       
   346 QVariant 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 */
       
   380 QWidget *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 */
       
   412 void QGraphicsProxyWidgetPrivate::_q_removeWidgetSlot()
       
   413 {
       
   414     Q_Q(QGraphicsProxyWidget);
       
   415     widget = 0;
       
   416     delete q;
       
   417 }
       
   418 
       
   419 /*!
       
   420     \internal
       
   421 */
       
   422 void QGraphicsProxyWidgetPrivate::updateWidgetGeometryFromProxy()
       
   423 {
       
   424 }
       
   425 
       
   426 /*!
       
   427     \internal
       
   428 */
       
   429 void 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 */
       
   463 void 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 */
       
   483 void 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 */
       
   499 void 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 
       
   515 bool QGraphicsProxyWidgetPrivate::isProxyWidget() const
       
   516 {
       
   517     return true;
       
   518 }
       
   519 
       
   520 /*!
       
   521      \internal
       
   522 */
       
   523 QPointF 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 */
       
   539 QGraphicsProxyWidget::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 */
       
   549 QGraphicsProxyWidget::~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 */
       
   590 void QGraphicsProxyWidget::setWidget(QWidget *widget)
       
   591 {
       
   592     Q_D(QGraphicsProxyWidget);
       
   593     d->setWidget_helper(widget, true);
       
   594 }
       
   595 
       
   596 void 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 */
       
   735 QWidget *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 */
       
   750 QRectF 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 */
       
   763 void 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 */
       
   781 QVariant 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 */
       
   831 bool QGraphicsProxyWidget::event(QEvent *event)
       
   832 {
       
   833     Q_D(QGraphicsProxyWidget);
       
   834     if (!d->widget)
       
   835         return QGraphicsWidget::event(event);
       
   836 
       
   837     switch (event->type()) {
       
   838     case QEvent::StyleChange:
       
   839         // Propagate style changes to the embedded widget.
       
   840         if (!d->styleChangeMode) {
       
   841             d->styleChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode;
       
   842             d->widget->setStyle(style());
       
   843             d->styleChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
       
   844         }
       
   845         break;
       
   846     case QEvent::FontChange: {
       
   847         // Propagate to widget.
       
   848         QWidgetPrivate *wd = d->widget->d_func();
       
   849         int mask = d->font.resolve() | d->inheritedFontResolveMask;
       
   850         wd->inheritedFontResolveMask = mask;
       
   851         wd->resolveFont();
       
   852         break;
       
   853     }
       
   854     case QEvent::PaletteChange: {
       
   855         // Propagate to widget.
       
   856         QWidgetPrivate *wd = d->widget->d_func();
       
   857         int mask = d->palette.resolve() | d->inheritedPaletteResolveMask;
       
   858         wd->inheritedPaletteResolveMask = mask;
       
   859         wd->resolvePalette();
       
   860         break;
       
   861     }
       
   862     case QEvent::InputMethod: {
       
   863         // Forward input method events if the focus widget enables
       
   864         // input methods.
       
   865         // ### Qt 4.5: this code must also go into a reimplementation
       
   866         // of inputMethodEvent().
       
   867         QWidget *focusWidget = d->widget->focusWidget();
       
   868         if (focusWidget && focusWidget->testAttribute(Qt::WA_InputMethodEnabled))
       
   869             QApplication::sendEvent(focusWidget, event);
       
   870         break;
       
   871     }
       
   872     case QEvent::ShortcutOverride: {
       
   873         QWidget *focusWidget = d->widget->focusWidget();
       
   874         while (focusWidget) {
       
   875             QApplication::sendEvent(focusWidget, event);
       
   876             if (event->isAccepted())
       
   877                 return true;
       
   878             focusWidget = focusWidget->parentWidget();
       
   879         }
       
   880         return false;
       
   881     }
       
   882     case QEvent::KeyPress: {
       
   883         QKeyEvent *k = static_cast<QKeyEvent *>(event);
       
   884         if (k->key() == Qt::Key_Tab || k->key() == Qt::Key_Backtab) {
       
   885             if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) {  //### Add MetaModifier?
       
   886                 QWidget *focusWidget = d->widget->focusWidget();
       
   887                 while (focusWidget) {
       
   888                     bool res = QApplication::sendEvent(focusWidget, event);
       
   889                     if ((res && event->isAccepted()) || (isWindow() && focusWidget == d->widget)) {
       
   890                         event->accept();
       
   891                         break;
       
   892                     }
       
   893                     focusWidget = focusWidget->parentWidget();
       
   894                 }
       
   895                 return true;
       
   896             }
       
   897         }
       
   898         break;
       
   899     }
       
   900     default:
       
   901         break;
       
   902     }
       
   903     return QGraphicsWidget::event(event);
       
   904 }
       
   905 
       
   906 /*!
       
   907     \reimp
       
   908 */
       
   909 bool QGraphicsProxyWidget::eventFilter(QObject *object, QEvent *event)
       
   910 {
       
   911     Q_D(QGraphicsProxyWidget);
       
   912 
       
   913     if (object == d->widget) {
       
   914         switch (event->type()) {
       
   915         case QEvent::LayoutRequest:
       
   916             updateGeometry();
       
   917             break;
       
   918          case QEvent::Resize:
       
   919              // If the widget resizes itself, we resize the proxy too.
       
   920              // Prevent feed-back by checking the geometry change mode.
       
   921              if (!d->sizeChangeMode)
       
   922                  d->updateProxyGeometryFromWidget();
       
   923             break;
       
   924          case QEvent::Move:
       
   925              // If the widget moves itself, we move the proxy too.  Prevent
       
   926              // feed-back by checking the geometry change mode.
       
   927              if (!d->posChangeMode)
       
   928                  d->updateProxyGeometryFromWidget();
       
   929             break;
       
   930         case QEvent::Hide:
       
   931         case QEvent::Show:
       
   932             // If the widget toggles its visible state, the proxy will follow.
       
   933             if (!d->visibleChangeMode) {
       
   934                 d->visibleChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
       
   935                 setVisible(event->type() == QEvent::Show);
       
   936                 d->visibleChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
       
   937             }
       
   938             break;
       
   939         case QEvent::EnabledChange:
       
   940             // If the widget toggles its enabled state, the proxy will follow.
       
   941             if (!d->enabledChangeMode) {
       
   942                 d->enabledChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
       
   943                 setEnabled(d->widget->isEnabled());
       
   944                 d->enabledChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
       
   945             }
       
   946             break;
       
   947         case QEvent::StyleChange:
       
   948             // Propagate style changes to the proxy.
       
   949             if (!d->styleChangeMode) {
       
   950                 d->styleChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
       
   951                 setStyle(d->widget->style());
       
   952                 d->styleChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
       
   953             }
       
   954             break;
       
   955         default:
       
   956             break;
       
   957         }
       
   958     }
       
   959     return QGraphicsWidget::eventFilter(object, event);
       
   960 }
       
   961 
       
   962 /*!
       
   963     \reimp
       
   964 */
       
   965 void QGraphicsProxyWidget::showEvent(QShowEvent *event)
       
   966 {
       
   967     Q_UNUSED(event);
       
   968 }
       
   969 
       
   970 /*!
       
   971     \reimp
       
   972 */
       
   973 void QGraphicsProxyWidget::hideEvent(QHideEvent *event)
       
   974 {
       
   975     Q_UNUSED(event);
       
   976 }
       
   977 
       
   978 #ifndef QT_NO_CONTEXTMENU
       
   979 /*!
       
   980     \reimp
       
   981 */
       
   982 void QGraphicsProxyWidget::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
       
   983 {
       
   984     Q_D(QGraphicsProxyWidget);
       
   985     if (!event || !d->widget || !d->widget->isVisible() || !hasFocus())
       
   986         return;
       
   987 
       
   988     // Find widget position and receiver.
       
   989     QPointF pos = event->pos();
       
   990     QPointer<QWidget> alienWidget = d->widget->childAt(pos.toPoint());
       
   991     QPointer<QWidget> receiver =  alienWidget ? alienWidget : d->widget;
       
   992 
       
   993     // Map event position from us to the receiver
       
   994     pos = d->mapToReceiver(pos, receiver);
       
   995 
       
   996     // Send mouse event. ### Doesn't propagate the event.
       
   997     QContextMenuEvent contextMenuEvent(QContextMenuEvent::Reason(event->reason()),
       
   998                                        pos.toPoint(), receiver->mapToGlobal(pos.toPoint()), event->modifiers());
       
   999     QApplication::sendEvent(receiver, &contextMenuEvent);
       
  1000 
       
  1001     event->setAccepted(contextMenuEvent.isAccepted());
       
  1002 }
       
  1003 #endif // QT_NO_CONTEXTMENU
       
  1004 
       
  1005 #ifndef QT_NO_DRAGANDDROP
       
  1006 /*!
       
  1007     \reimp
       
  1008 */
       
  1009 void QGraphicsProxyWidget::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
       
  1010 {
       
  1011 #ifdef QT_NO_DRAGANDDROP
       
  1012     Q_UNUSED(event);
       
  1013 #else
       
  1014     Q_D(QGraphicsProxyWidget);
       
  1015     if (!d->widget)
       
  1016         return;
       
  1017 
       
  1018     QDragEnterEvent proxyDragEnter(event->pos().toPoint(), event->dropAction(), event->mimeData(), event->buttons(), event->modifiers());
       
  1019     proxyDragEnter.setAccepted(event->isAccepted());
       
  1020     QApplication::sendEvent(d->widget, &proxyDragEnter);
       
  1021     event->setAccepted(proxyDragEnter.isAccepted());
       
  1022     if (proxyDragEnter.isAccepted())    // we discard answerRect
       
  1023         event->setDropAction(proxyDragEnter.dropAction());
       
  1024 #endif
       
  1025 }
       
  1026 /*!
       
  1027     \reimp
       
  1028 */
       
  1029 void QGraphicsProxyWidget::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
       
  1030 {
       
  1031     Q_UNUSED(event);
       
  1032 #ifndef QT_NO_DRAGANDDROP
       
  1033     Q_D(QGraphicsProxyWidget);
       
  1034     if (!d->widget || !d->dragDropWidget)
       
  1035         return;
       
  1036     QDragLeaveEvent proxyDragLeave;
       
  1037     QApplication::sendEvent(d->dragDropWidget, &proxyDragLeave);
       
  1038     d->dragDropWidget = 0;
       
  1039 #endif
       
  1040 }
       
  1041 
       
  1042 /*!
       
  1043     \reimp
       
  1044 */
       
  1045 void QGraphicsProxyWidget::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
       
  1046 {
       
  1047 #ifdef QT_NO_DRAGANDDROP
       
  1048     Q_UNUSED(event);
       
  1049 #else
       
  1050     Q_D(QGraphicsProxyWidget);
       
  1051     if (!d->widget)
       
  1052         return;
       
  1053     QPointF p = event->pos();
       
  1054     event->ignore();
       
  1055     QPointer<QWidget> subWidget = d->widget->childAt(p.toPoint());
       
  1056     QPointer<QWidget> receiver =  subWidget ? subWidget : d->widget;
       
  1057     bool eventDelivered = false;
       
  1058     for (; receiver; receiver = receiver->parentWidget()) {
       
  1059         if (!receiver->isEnabled() || !receiver->acceptDrops())
       
  1060             continue;
       
  1061         // Map event position from us to the receiver
       
  1062         QPoint receiverPos = d->mapToReceiver(p, receiver).toPoint();
       
  1063         if (receiver != d->dragDropWidget) {
       
  1064             // Try to enter before we leave
       
  1065             QDragEnterEvent dragEnter(receiverPos, event->possibleActions(), event->mimeData(), event->buttons(), event->modifiers());
       
  1066             dragEnter.setDropAction(event->proposedAction());
       
  1067             QApplication::sendEvent(receiver, &dragEnter);
       
  1068             event->setAccepted(dragEnter.isAccepted());
       
  1069             event->setDropAction(dragEnter.dropAction());
       
  1070             if (!event->isAccepted()) {
       
  1071                 // propagate to the parent widget
       
  1072                 continue;
       
  1073             }
       
  1074 
       
  1075             d->lastDropAction = event->dropAction();
       
  1076 
       
  1077             if (d->dragDropWidget) {
       
  1078                 QDragLeaveEvent dragLeave;
       
  1079                 QApplication::sendEvent(d->dragDropWidget, &dragLeave);
       
  1080             }
       
  1081             d->dragDropWidget = receiver;
       
  1082         }
       
  1083 
       
  1084         QDragMoveEvent dragMove(receiverPos, event->possibleActions(), event->mimeData(), event->buttons(), event->modifiers());
       
  1085         event->setDropAction(d->lastDropAction);
       
  1086         QApplication::sendEvent(receiver, &dragMove);
       
  1087         event->setAccepted(dragMove.isAccepted());
       
  1088         event->setDropAction(dragMove.dropAction());
       
  1089         if (event->isAccepted())
       
  1090             d->lastDropAction = event->dropAction();
       
  1091         eventDelivered = true;
       
  1092         break;
       
  1093     }
       
  1094 
       
  1095     if (!eventDelivered) {
       
  1096         if (d->dragDropWidget) {
       
  1097             // Leave the last drag drop item
       
  1098             QDragLeaveEvent dragLeave;
       
  1099             QApplication::sendEvent(d->dragDropWidget, &dragLeave);
       
  1100             d->dragDropWidget = 0;
       
  1101         }
       
  1102         // Propagate
       
  1103         event->setDropAction(Qt::IgnoreAction);
       
  1104     }
       
  1105 #endif
       
  1106 }
       
  1107 
       
  1108 /*!
       
  1109     \reimp
       
  1110 */
       
  1111 void QGraphicsProxyWidget::dropEvent(QGraphicsSceneDragDropEvent *event)
       
  1112 {
       
  1113 #ifdef QT_NO_DRAGANDDROP
       
  1114     Q_UNUSED(event);
       
  1115 #else
       
  1116     Q_D(QGraphicsProxyWidget);
       
  1117     if (d->widget && d->dragDropWidget) {
       
  1118         QPoint widgetPos = d->mapToReceiver(event->pos(), d->dragDropWidget).toPoint();
       
  1119         QDropEvent dropEvent(widgetPos, event->possibleActions(), event->mimeData(), event->buttons(), event->modifiers());
       
  1120         QApplication::sendEvent(d->dragDropWidget, &dropEvent);
       
  1121         event->setAccepted(dropEvent.isAccepted());
       
  1122         d->dragDropWidget = 0;
       
  1123     }
       
  1124 #endif
       
  1125 }
       
  1126 #endif
       
  1127 
       
  1128 /*!
       
  1129     \reimp
       
  1130 */
       
  1131 void QGraphicsProxyWidget::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
       
  1132 {
       
  1133     Q_UNUSED(event);
       
  1134 }
       
  1135 
       
  1136 /*!
       
  1137     \reimp
       
  1138 */
       
  1139 void QGraphicsProxyWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
       
  1140 {
       
  1141     Q_UNUSED(event);
       
  1142     Q_D(QGraphicsProxyWidget);
       
  1143     // If hoverMove was compressed away, make sure we update properly here.
       
  1144     if (d->lastWidgetUnderMouse) {
       
  1145         QApplicationPrivate::dispatchEnterLeave(0, d->lastWidgetUnderMouse);
       
  1146         d->lastWidgetUnderMouse = 0;
       
  1147     }
       
  1148 }
       
  1149 
       
  1150 /*!
       
  1151     \reimp
       
  1152 */
       
  1153 void QGraphicsProxyWidget::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
       
  1154 {
       
  1155     Q_D(QGraphicsProxyWidget);
       
  1156 #ifdef GRAPHICSPROXYWIDGET_DEBUG
       
  1157     qDebug() << "QGraphicsProxyWidget::hoverMoveEvent";
       
  1158 #endif
       
  1159     // Ignore events on the window frame.
       
  1160     if (!d->widget || !rect().contains(event->pos())) {
       
  1161         if (d->lastWidgetUnderMouse) {
       
  1162             QApplicationPrivate::dispatchEnterLeave(0, d->lastWidgetUnderMouse);
       
  1163             d->lastWidgetUnderMouse = 0;
       
  1164         }
       
  1165         return;
       
  1166     }
       
  1167 
       
  1168     d->embeddedMouseGrabber = 0;
       
  1169     d->sendWidgetMouseEvent(event);
       
  1170 }
       
  1171 
       
  1172 /*!
       
  1173     \reimp
       
  1174 */
       
  1175 void QGraphicsProxyWidget::grabMouseEvent(QEvent *event)
       
  1176 {
       
  1177     Q_UNUSED(event);
       
  1178 }
       
  1179 
       
  1180 /*!
       
  1181     \reimp
       
  1182 */
       
  1183 void QGraphicsProxyWidget::ungrabMouseEvent(QEvent *event)
       
  1184 {
       
  1185     Q_D(QGraphicsProxyWidget);
       
  1186     Q_UNUSED(event);
       
  1187     d->embeddedMouseGrabber = 0;
       
  1188 }
       
  1189 
       
  1190 /*!
       
  1191     \reimp
       
  1192 */
       
  1193 void QGraphicsProxyWidget::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
       
  1194 {
       
  1195     Q_D(QGraphicsProxyWidget);
       
  1196 #ifdef GRAPHICSPROXYWIDGET_DEBUG
       
  1197     qDebug() << "QGraphicsProxyWidget::mouseMoveEvent";
       
  1198 #endif
       
  1199     d->sendWidgetMouseEvent(event);
       
  1200 }
       
  1201 
       
  1202 /*!
       
  1203     \reimp
       
  1204 */
       
  1205 void QGraphicsProxyWidget::mousePressEvent(QGraphicsSceneMouseEvent *event)
       
  1206 {
       
  1207     Q_D(QGraphicsProxyWidget);
       
  1208 #ifdef GRAPHICSPROXYWIDGET_DEBUG
       
  1209     qDebug() << "QGraphicsProxyWidget::mousePressEvent";
       
  1210 #endif
       
  1211     d->sendWidgetMouseEvent(event);
       
  1212 }
       
  1213 
       
  1214 /*!
       
  1215     \reimp
       
  1216 */
       
  1217 void QGraphicsProxyWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
       
  1218 {
       
  1219     Q_D(QGraphicsProxyWidget);
       
  1220 #ifdef GRAPHICSPROXYWIDGET_DEBUG
       
  1221     qDebug() << "QGraphicsProxyWidget::mouseDoubleClickEvent";
       
  1222 #endif
       
  1223     d->sendWidgetMouseEvent(event);
       
  1224 }
       
  1225 
       
  1226 /*!
       
  1227     \reimp
       
  1228 */
       
  1229 #ifndef QT_NO_WHEELEVENT
       
  1230 void QGraphicsProxyWidget::wheelEvent(QGraphicsSceneWheelEvent *event)
       
  1231 {
       
  1232     Q_D(QGraphicsProxyWidget);
       
  1233 #ifdef GRAPHICSPROXYWIDGET_DEBUG
       
  1234     qDebug() << "QGraphicsProxyWidget::wheelEvent";
       
  1235 #endif
       
  1236     if (!d->widget)
       
  1237         return;
       
  1238 
       
  1239     QPointF pos = event->pos();
       
  1240     QPointer<QWidget> receiver = d->widget->childAt(pos.toPoint());
       
  1241     if (!receiver)
       
  1242         receiver = d->widget;
       
  1243 
       
  1244     // Map event position from us to the receiver
       
  1245     pos = d->mapToReceiver(pos, receiver);
       
  1246 
       
  1247     // Send mouse event.
       
  1248     QWheelEvent wheelEvent(pos.toPoint(), event->screenPos(), event->delta(),
       
  1249                            event->buttons(), event->modifiers(), event->orientation());
       
  1250     QPointer<QWidget> focusWidget = d->widget->focusWidget();
       
  1251     extern bool qt_sendSpontaneousEvent(QObject *, QEvent *);
       
  1252     qt_sendSpontaneousEvent(receiver, &wheelEvent);
       
  1253     event->setAccepted(wheelEvent.isAccepted());
       
  1254 
       
  1255     // ### Remove, this should be done by proper focusIn/focusOut events.
       
  1256     if (focusWidget && !focusWidget->hasFocus()) {
       
  1257         focusWidget->update();
       
  1258         focusWidget = d->widget->focusWidget();
       
  1259         if (focusWidget && focusWidget->hasFocus())
       
  1260             focusWidget->update();
       
  1261     }
       
  1262 }
       
  1263 #endif
       
  1264 
       
  1265 /*!
       
  1266     \reimp
       
  1267 */
       
  1268 void QGraphicsProxyWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
       
  1269 {
       
  1270     Q_D(QGraphicsProxyWidget);
       
  1271 #ifdef GRAPHICSPROXYWIDGET_DEBUG
       
  1272     qDebug() << "QGraphicsProxyWidget::mouseReleaseEvent";
       
  1273 #endif
       
  1274     d->sendWidgetMouseEvent(event);
       
  1275 }
       
  1276 
       
  1277 /*!
       
  1278     \reimp
       
  1279 */
       
  1280 void QGraphicsProxyWidget::keyPressEvent(QKeyEvent *event)
       
  1281 {
       
  1282     Q_D(QGraphicsProxyWidget);
       
  1283 #ifdef GRAPHICSPROXYWIDGET_DEBUG
       
  1284     qDebug() << "QGraphicsProxyWidget::keyPressEvent";
       
  1285 #endif
       
  1286     d->sendWidgetKeyEvent(event);
       
  1287 }
       
  1288 
       
  1289 /*!
       
  1290     \reimp
       
  1291 */
       
  1292 void QGraphicsProxyWidget::keyReleaseEvent(QKeyEvent *event)
       
  1293 {
       
  1294     Q_D(QGraphicsProxyWidget);
       
  1295 #ifdef GRAPHICSPROXYWIDGET_DEBUG
       
  1296     qDebug() << "QGraphicsProxyWidget::keyReleaseEvent";
       
  1297 #endif
       
  1298     d->sendWidgetKeyEvent(event);
       
  1299 }
       
  1300 
       
  1301 /*!
       
  1302     \reimp
       
  1303 */
       
  1304 void QGraphicsProxyWidget::focusInEvent(QFocusEvent *event)
       
  1305 {
       
  1306 #ifdef GRAPHICSPROXYWIDGET_DEBUG
       
  1307     qDebug() << "QGraphicsProxyWidget::focusInEvent";
       
  1308 #endif
       
  1309     Q_D(QGraphicsProxyWidget);
       
  1310 
       
  1311     if (d->focusFromWidgetToProxy) {
       
  1312         // Prevent recursion when the proxy autogains focus through the
       
  1313         // embedded widget calling setFocus(). ### Could be done with event
       
  1314         // filter on FocusIn instead?
       
  1315         return;
       
  1316     }
       
  1317 
       
  1318     switch (event->reason()) {
       
  1319     case Qt::TabFocusReason: {
       
  1320 	if (QWidget *focusChild = d->findFocusChild(0, true))
       
  1321             focusChild->setFocus(event->reason());
       
  1322         break;
       
  1323     }
       
  1324     case Qt::BacktabFocusReason:
       
  1325 	if (QWidget *focusChild = d->findFocusChild(0, false))
       
  1326             focusChild->setFocus(event->reason());
       
  1327         break;
       
  1328     default:
       
  1329 	if (d->widget && d->widget->focusWidget()) {
       
  1330 	    d->widget->focusWidget()->setFocus(event->reason());
       
  1331 	    return;
       
  1332         }
       
  1333         break;
       
  1334     }
       
  1335 }
       
  1336 
       
  1337 /*!
       
  1338     \reimp
       
  1339 */
       
  1340 void QGraphicsProxyWidget::focusOutEvent(QFocusEvent *event)
       
  1341 {
       
  1342 #ifdef GRAPHICSPROXYWIDGET_DEBUG
       
  1343     qDebug() << "QGraphicsProxyWidget::focusOutEvent";
       
  1344 #endif
       
  1345     Q_D(QGraphicsProxyWidget);
       
  1346     if (d->widget) {
       
  1347         // We need to explicitly remove subfocus from the embedded widget's
       
  1348         // focus widget.
       
  1349         if (QWidget *focusWidget = d->widget->focusWidget())
       
  1350             d->removeSubFocusHelper(focusWidget, event->reason());
       
  1351     }
       
  1352 }
       
  1353 
       
  1354 /*!
       
  1355     \reimp
       
  1356 */
       
  1357 bool QGraphicsProxyWidget::focusNextPrevChild(bool next)
       
  1358 {
       
  1359     Q_D(QGraphicsProxyWidget);
       
  1360     if (!d->widget || !d->scene)
       
  1361         return QGraphicsWidget::focusNextPrevChild(next);
       
  1362 
       
  1363     Qt::FocusReason reason = next ? Qt::TabFocusReason : Qt::BacktabFocusReason;
       
  1364     QWidget *lastFocusChild = d->widget->focusWidget();
       
  1365     if (QWidget *newFocusChild = d->findFocusChild(lastFocusChild, next)) {
       
  1366 	newFocusChild->setFocus(reason);
       
  1367 	return true;
       
  1368     }
       
  1369 
       
  1370     return QGraphicsWidget::focusNextPrevChild(next);
       
  1371 }
       
  1372 
       
  1373 /*!
       
  1374     \reimp
       
  1375 */
       
  1376 QSizeF QGraphicsProxyWidget::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
       
  1377 {
       
  1378     Q_D(const QGraphicsProxyWidget);
       
  1379     if (!d->widget)
       
  1380         return QGraphicsWidget::sizeHint(which, constraint);
       
  1381 
       
  1382     QSizeF sh;
       
  1383     switch (which) {
       
  1384     case Qt::PreferredSize:
       
  1385         if (QLayout *l = d->widget->layout())
       
  1386             sh = l->sizeHint();
       
  1387         else
       
  1388             sh = d->widget->sizeHint();
       
  1389         break;
       
  1390     case Qt::MinimumSize:
       
  1391         if (QLayout *l = d->widget->layout())
       
  1392             sh = l->minimumSize();
       
  1393         else
       
  1394             sh = d->widget->minimumSizeHint();
       
  1395         break;
       
  1396     case Qt::MaximumSize:
       
  1397         if (QLayout *l = d->widget->layout())
       
  1398             sh = l->maximumSize();
       
  1399         else
       
  1400             sh = QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
       
  1401         break;
       
  1402     case Qt::MinimumDescent:
       
  1403         sh = constraint;
       
  1404         break;
       
  1405     default:
       
  1406         break;
       
  1407     }
       
  1408     return sh;
       
  1409 }
       
  1410 
       
  1411 /*!
       
  1412     \reimp
       
  1413 */
       
  1414 void QGraphicsProxyWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
       
  1415 {
       
  1416     Q_D(QGraphicsProxyWidget);
       
  1417     if (d->widget) {
       
  1418         if (d->sizeChangeMode != QGraphicsProxyWidgetPrivate::WidgetToProxyMode)
       
  1419             d->widget->resize(event->newSize().toSize());
       
  1420     }
       
  1421     QGraphicsWidget::resizeEvent(event);
       
  1422 }
       
  1423 
       
  1424 /*!
       
  1425     \reimp
       
  1426 */
       
  1427 void QGraphicsProxyWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
       
  1428 {
       
  1429     Q_D(QGraphicsProxyWidget);
       
  1430     Q_UNUSED(widget);
       
  1431     if (!d->widget || !d->widget->isVisible())
       
  1432         return;
       
  1433 
       
  1434     // Filter out repaints on the window frame.
       
  1435     const QRect exposedWidgetRect = (option->exposedRect & rect()).toRect();
       
  1436     if (exposedWidgetRect.isEmpty())
       
  1437         return;
       
  1438 
       
  1439     // Disable QPainter's default pen being cosmetic. This allows widgets and
       
  1440     // styles to follow Qt's existing defaults without getting ugly cosmetic
       
  1441     // lines when scaled.
       
  1442     bool restore = !(painter->renderHints() & QPainter::NonCosmeticDefaultPen);
       
  1443     painter->setRenderHints(QPainter::NonCosmeticDefaultPen, true);
       
  1444 
       
  1445     d->widget->render(painter, exposedWidgetRect.topLeft(), exposedWidgetRect);
       
  1446 
       
  1447     // Restore the render hints if necessary.
       
  1448     if (restore)
       
  1449         painter->setRenderHints(QPainter::NonCosmeticDefaultPen, false);
       
  1450 }
       
  1451 
       
  1452 /*!
       
  1453     \reimp
       
  1454 */
       
  1455 int QGraphicsProxyWidget::type() const
       
  1456 {
       
  1457     return Type;
       
  1458 }
       
  1459 
       
  1460 /*!
       
  1461   \since 4.5
       
  1462 
       
  1463   Creates a proxy widget for the given \a child of the widget
       
  1464   contained in this proxy.
       
  1465 
       
  1466   This function makes it possible to aquire proxies for
       
  1467   non top-level widgets. For instance, you can embed a dialog,
       
  1468   and then transform only one of its widgets.
       
  1469 
       
  1470   If the widget is already embedded, return the existing proxy widget.
       
  1471 
       
  1472   \sa newProxyWidget(), QGraphicsScene::addWidget()
       
  1473 */
       
  1474 QGraphicsProxyWidget *QGraphicsProxyWidget::createProxyForChildWidget(QWidget *child)
       
  1475 {
       
  1476     QGraphicsProxyWidget *proxy = child->graphicsProxyWidget();
       
  1477     if (proxy)
       
  1478         return proxy;
       
  1479     if (!child->parentWidget()) {
       
  1480         qWarning("QGraphicsProxyWidget::createProxyForChildWidget: top-level widget not in a QGraphicsScene");
       
  1481         return 0;
       
  1482     }
       
  1483 
       
  1484     QGraphicsProxyWidget *parentProxy = createProxyForChildWidget(child->parentWidget());
       
  1485     if (!parentProxy)
       
  1486         return 0;
       
  1487 
       
  1488     if (!QMetaObject::invokeMethod(parentProxy, "newProxyWidget",  Qt::DirectConnection,
       
  1489          Q_RETURN_ARG(QGraphicsProxyWidget*, proxy), Q_ARG(const QWidget*, child)))
       
  1490         return 0;
       
  1491     proxy->setParent(parentProxy);
       
  1492     proxy->setWidget(child);
       
  1493     return proxy;
       
  1494 }
       
  1495 
       
  1496 /*!
       
  1497   \fn QGraphicsProxyWidget *QGraphicsProxyWidget::newProxyWidget(const QWidget *child)
       
  1498   \since 4.5
       
  1499 
       
  1500   Creates a proxy widget for the given \a child of the widget contained in this
       
  1501   proxy.
       
  1502 
       
  1503   You should not call this function directly; use
       
  1504   QGraphicsProxyWidget::createProxyForChildWidget() instead.
       
  1505 
       
  1506   This function is a fake virtual slot that you can reimplement in
       
  1507   your subclass in order to control how new proxy widgets are
       
  1508   created. The default implementation returns a proxy created with
       
  1509   the QGraphicsProxyWidget() constructor with this proxy widget as
       
  1510   the parent.
       
  1511 
       
  1512   \sa createProxyForChildWidget()
       
  1513 */
       
  1514 QGraphicsProxyWidget *QGraphicsProxyWidget::newProxyWidget(const QWidget *)
       
  1515 {
       
  1516     return new QGraphicsProxyWidget(this);
       
  1517 }
       
  1518 
       
  1519 
       
  1520 
       
  1521 QT_END_NAMESPACE
       
  1522 
       
  1523 #include "moc_qgraphicsproxywidget.cpp"
       
  1524 
       
  1525 #endif //QT_NO_GRAPHICSVIEW